本文 AI 產出,尚未審核

Three.js 幾何體與 Mesh

BoxGeometry / SphereGeometry / PlaneGeometry


簡介

在 3D 網頁開發中,**幾何體(Geometry)**是建立任何可見物件的基礎。Three.js 提供了許多內建的幾何體類別,其中最常用的三個就是 BoxGeometrySphereGeometryPlaneGeometry。它們分別對應立方體、球體與平面,幾乎可以滿足日常的模型需求。

掌握這三種幾何體的使用方式,不僅能讓你快速搭建場景,還能深入了解 Mesh(幾何體 + 材質)的工作原理,為後續更複雜的模型(如自訂緩衝幾何體)奠定扎實基礎。本文將從概念說明、實作範例、常見陷阱與最佳實踐,完整帶你走過從「建立」到「優化」的全流程。


核心概念

1. Mesh 與 Geometry 的關係

在 Three.js 中,Mesh 是由 Geometry(描述頂點、面與法向量)與 Material(決定外觀)組成的可渲染物件。

const mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );

只要把不同的 Geometry 換成 BoxGeometrySphereGeometryPlaneGeometry,就能得到截然不同的形狀。

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();

最佳實踐

  1. 合理分段:只在需要變形或高光的地方使用較高的 segment 數,避免全局過度細分。
  2. 重用 Geometry:多個同類型物件(如多個立方體)可共用同一個 BoxGeometry 實例,減少記憶體開銷。
  3. 使用 BufferGeometryBoxBufferGeometrySphereBufferGeometry 效能更佳,特別是大量物件時。
  4. 啟用硬體加速:確保渲染器使用 antialias: true 並在 WebGLRenderer 中設定 powerPreference: "high-performance"

實際應用場景

  1. 產品展示網站:利用 BoxGeometry 建立商品盒子,搭配 MeshStandardMaterial 與環境貼圖,呈現高質感的 3D 產品視圖。
  2. 教育與科學模擬:用 SphereGeometry 表示行星、原子模型或細胞,結合動畫與光照,提供直觀的互動教學。
  3. 遊戲開發PlaneGeometry 常作為地面或平台,結合位移貼圖與法線貼圖,可快速製作不規則地形。
  4. 虛擬實境(VR):在 WebXR 中,這三種幾何體是建構簡易場景的基礎,配合 XRController 可實作抓取與放置功能。
  5. 資料視覺化:把資料點映射到 BoxGeometry 的高度(柱狀圖)或 SphereGeometry 的半徑(氣泡圖),直觀呈現統計資訊。

總結

  • BoxGeometry、SphereGeometry、PlaneGeometry 是 Three.js 中最常使用的三種基礎幾何體,掌握它們的參數與細分概念即可快速產出多樣的 3D 形狀。
  • Mesh 把 Geometry 與 Material 結合,是場景中唯一能被渲染的實體;透過正確的光照、陰影與貼圖設定,可讓簡單的幾何體呈現出逼真的效果。
  • 在開發過程中要留意 segment 數量、陰影設定、貼圖大小 等常見陷阱,並遵循 重用 Geometry、使用 BufferGeometry 的最佳實踐,以提升效能與維護性。
  • 這些基礎技術不僅適用於小型展示、教育模擬,也能作為大型遊戲與 VR 應用的構件,為未來更高階的自訂幾何體與動畫奠定堅實基礎。

現在就動手試試,把 BoxGeometrySphereGeometryPlaneGeometry 結合起來,打造屬於自己的 3D 互動作品吧!