Three.js 幾何體與 Mesh
BoxGeometry / SphereGeometry / PlaneGeometry
簡介
在 3D 網頁開發中,**幾何體(Geometry)**是建立任何可見物件的基礎。Three.js 提供了許多內建的幾何體類別,其中最常用的三個就是 BoxGeometry、SphereGeometry 與 PlaneGeometry。它們分別對應立方體、球體與平面,幾乎可以滿足日常的模型需求。
掌握這三種幾何體的使用方式,不僅能讓你快速搭建場景,還能深入了解 Mesh(幾何體 + 材質)的工作原理,為後續更複雜的模型(如自訂緩衝幾何體)奠定扎實基礎。本文將從概念說明、實作範例、常見陷阱與最佳實踐,完整帶你走過從「建立」到「優化」的全流程。
核心概念
1. Mesh 與 Geometry 的關係
在 Three.js 中,Mesh 是由 Geometry(描述頂點、面與法向量)與 Material(決定外觀)組成的可渲染物件。
const mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );
只要把不同的 Geometry 換成 BoxGeometry、SphereGeometry、PlaneGeometry,就能得到截然不同的形狀。
2. BoxGeometry
BoxGeometry(或 BoxBufferGeometry)用於產生長方體或立方體。常見的建構子參數如下:
new THREE.BoxGeometry( width, height, depth, widthSegments, heightSegments, depthSegments );
- width / height / depth:尺寸
- widthSegments / heightSegments / depthSegments:細分格數,數值越大模型越平滑,但會增加渲染負擔。
範例 1:建立基本立方體
// 建立場景、相機與渲染器(省略設定細節)
const geometry = new THREE.BoxGeometry( 2, 2, 2 ); // 2 單位的立方體
const material = new THREE.MeshStandardMaterial({ color: 0x1565c0 });
const cube = new THREE.Mesh( geometry, material );
scene.add( cube );
// 加入光源讓立方體顯示明暗
const light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set(5, 5, 5);
scene.add( light );
重點:若需要更細緻的表面(例如做凹凸貼圖),請使用至少
2個 segment。
3. SphereGeometry
SphereGeometry 產生球體,建構子參數如下:
new THREE.SphereGeometry( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength );
- radius:球半徑
- widthSegments / heightSegments:水平與垂直細分,通常建議
>= 32才能避免可見的多邊形接縫。 - 其餘參數可用於產生半球、切片等特殊形狀。
範例 2:球體貼圖與動態旋轉
const radius = 1.5;
const widthSeg = 48;
const heightSeg = 32;
const sphereGeo = new THREE.SphereGeometry( radius, widthSeg, heightSeg );
const texture = new THREE.TextureLoader().load('textures/earth.jpg');
const sphereMat = new THREE.MeshStandardMaterial({ map: texture });
const earth = new THREE.Mesh( sphereGeo, sphereMat );
scene.add( earth );
// 讓地球自轉
function animate() {
requestAnimationFrame( animate );
earth.rotation.y += 0.002; // 每幀微量旋轉
renderer.render( scene, camera );
}
animate();
提示:使用
MeshStandardMaterial搭配環境光(AmbientLight)與方向光(DirectionalLight),可得到更自然的光照效果。
4. PlaneGeometry
PlaneGeometry 用於產生平面,常見於地面、牆面或 UI 介面。建構子參數:
new THREE.PlaneGeometry( width, height, widthSegments, heightSegments );
- width / height:平面尺寸
- widthSegments / heightSegments:細分格數,對於需要 位移貼圖(Displacement Map) 或 細部碰撞 的情況非常重要。
範例 3:作為接收陰影的地板
const floorGeo = new THREE.PlaneGeometry( 10, 10, 64, 64 );
const floorMat = new THREE.MeshStandardMaterial({
color: 0x888888,
roughness: 0.8,
metalness: 0.2
});
const floor = new THREE.Mesh( floorGeo, floorMat );
floor.rotation.x = - Math.PI / 2; // 讓平面水平放置
floor.receiveShadow = true; // 接收陰影
scene.add( floor );
// 設定渲染器與光源投射陰影
renderer.shadowMap.enabled = true;
light.castShadow = true;
cube.castShadow = true; // 之前建立的立方體
5. 結合多個幾何體:建立簡易場景
範例 4:盒子、球體與平面組合成小型展示台
// 1. 立方體(作為展示台的柱子)
const pillarGeo = new THREE.BoxGeometry( 0.5, 3, 0.5 );
const pillarMat = new THREE.MeshStandardMaterial({ color: 0x555555 });
const pillar = new THREE.Mesh( pillarGeo, pillarMat );
pillar.position.y = 1.5;
scene.add( pillar );
// 2. 球體(擺放在柱子上方)
const ballGeo = new THREE.SphereGeometry( 0.8, 32, 16 );
const ballMat = new THREE.MeshStandardMaterial({ color: 0xff5722 });
const ball = new THREE.Mesh( ballGeo, ballMat );
ball.position.set( 0, 3.5, 0 );
scene.add( ball );
// 3. 平面(地板)
const groundGeo = new THREE.PlaneGeometry( 12, 12 );
const groundMat = new THREE.MeshStandardMaterial({ color: 0x222222 });
const ground = new THREE.Mesh( groundGeo, groundMat );
ground.rotation.x = - Math.PI / 2;
ground.position.y = 0;
ground.receiveShadow = true;
scene.add( ground );
以上範例示範了 如何把不同 Geometry 以不同材質、位置與陰影屬性組合,快速構築具有層次感的 3D 場景。
常見陷阱與最佳實踐
| 陷阱 | 可能的結果 | 解決方式 |
|---|---|---|
忘記啟用 renderer.shadowMap.enabled |
物件無法投射或接收陰影,畫面顯得平坦 | 在初始化渲染器後立即設定 renderer.shadowMap.enabled = true |
使用過少的 segment(如 BoxGeometry(1,1,1,1,1,1)) |
表面出現明顯的平面分割,貼圖失真 | 針對需要細部變形的幾何體,至少使用 2 個 segment,球體建議 >= 32 |
| 貼圖尺寸過大(4K+) | 下載時間長、記憶體占用過高,導致卡頓 | 使用適當的 MIPMAP 並在 TextureLoader 時設定 texture.minFilter = THREE.LinearMipmapLinearFilter |
| 未調整相機遠近裁剪面(near/far) | 大型平面或遠距離物件被裁剪掉 | 根據場景尺寸調整 camera.near(如 0.1)與 camera.far(如 1000) |
忘記設定 geometry.dispose() |
記憶體泄漏,長時間運行後瀏覽器崩潰 | 在不再使用的 Mesh 時,先 mesh.geometry.dispose(); mesh.material.dispose(); |
最佳實踐
- 合理分段:只在需要變形或高光的地方使用較高的 segment 數,避免全局過度細分。
- 重用 Geometry:多個同類型物件(如多個立方體)可共用同一個
BoxGeometry實例,減少記憶體開銷。 - 使用 BufferGeometry:
BoxBufferGeometry、SphereBufferGeometry效能更佳,特別是大量物件時。 - 啟用硬體加速:確保渲染器使用
antialias: true並在WebGLRenderer中設定powerPreference: "high-performance"。
實際應用場景
- 產品展示網站:利用
BoxGeometry建立商品盒子,搭配MeshStandardMaterial與環境貼圖,呈現高質感的 3D 產品視圖。 - 教育與科學模擬:用
SphereGeometry表示行星、原子模型或細胞,結合動畫與光照,提供直觀的互動教學。 - 遊戲開發:
PlaneGeometry常作為地面或平台,結合位移貼圖與法線貼圖,可快速製作不規則地形。 - 虛擬實境(VR):在 WebXR 中,這三種幾何體是建構簡易場景的基礎,配合
XRController可實作抓取與放置功能。 - 資料視覺化:把資料點映射到
BoxGeometry的高度(柱狀圖)或SphereGeometry的半徑(氣泡圖),直觀呈現統計資訊。
總結
- BoxGeometry、SphereGeometry、PlaneGeometry 是 Three.js 中最常使用的三種基礎幾何體,掌握它們的參數與細分概念即可快速產出多樣的 3D 形狀。
- Mesh 把 Geometry 與 Material 結合,是場景中唯一能被渲染的實體;透過正確的光照、陰影與貼圖設定,可讓簡單的幾何體呈現出逼真的效果。
- 在開發過程中要留意 segment 數量、陰影設定、貼圖大小 等常見陷阱,並遵循 重用 Geometry、使用 BufferGeometry 的最佳實踐,以提升效能與維護性。
- 這些基礎技術不僅適用於小型展示、教育模擬,也能作為大型遊戲與 VR 應用的構件,為未來更高階的自訂幾何體與動畫奠定堅實基礎。
現在就動手試試,把
BoxGeometry、SphereGeometry、PlaneGeometry結合起來,打造屬於自己的 3D 互動作品吧!