Three.js 基礎概念:什麼是 Three.js 與 WebGL
簡介
在 2020 年以後,Web 前端的互動體驗不再只停留在文字與圖片的切換,3D 场景、即時渲染與虛擬實境(VR)已成為主流需求。
要在瀏覽器內實作 3D 圖形,需要依賴底層的 WebGL(Web Graphics Library),但直接操作 WebGL 的 API 相當繁雜,對於大多數前端開發者而言門檻過高。
Three.js 正是為了降低這道門檻而誕生的高階 3D 程式庫。它把 WebGL 的低階指令包裝成直觀的物件模型,讓開發者只需要關注「場景、相機、物件」等概念,就能快速建立、渲染與互動的 3D 內容。
本篇文章將從 WebGL 的定位、Three.js 的核心架構、實作範例,到 常見陷阱與最佳實踐,一步步說明「什麼是 Three.js 與 WebGL」以及它在實務開發中的價值。
核心概念
1. WebGL:瀏覽器的原生 3D 渲染引擎
- WebGL 是基於 OpenGL ES 2.0 的 JavaScript API,直接在
<canvas>元素上執行 GPU 加速的圖形運算。 - 它使用 Shader(頂點著色器 & 片段著色器)來控制每個頂點與像素的渲染流程,具備極高的彈性與效能。
- 但 WebGL 的程式碼往往需要手寫大量的緩衝區、屬性、Uniform、渲染循環等,對新手相當不友善。
簡言之:WebGL 是底層的「硬體抽象層」,提供渲染能力;Three.js 則是「上層框架」,把這些底層操作封裝成易用的 API。
2. Three.js 的三大核心物件
| 物件 | 功能說明 | 常見屬性 |
|---|---|---|
| Scene | 所有 3D 物件的容器,類似「舞台」 | background、add()、remove() |
| Camera | 定義觀察者的位置、視角與投影方式 | position、lookAt()、aspect |
| Renderer | 把 Scene 與 Camera 交給 GPU 渲染,最常用 WebGLRenderer |
setSize()、render()、setPixelRatio() |
實作流程:先建立
Scene→ 建立Camera→ 準備Renderer→ 把物件加入Scene→ 在動畫迴圈中呼叫renderer.render(scene, camera)。
3. 常見的 Three.js 物件類型
- Mesh:由幾何體(Geometry)與材質(Material)組成的可見物件。
- Light:光源類別(AmbientLight、DirectionalLight、PointLight 等),決定物件的光照效果。
- Texture:貼圖,用於為材質提供圖像資訊。
4. 事件與動畫
Three.js 本身不處理 DOM 事件或時間軸,通常會結合 requestAnimationFrame、OrbitControls(相機控制)或 GSAP 等套件,實作互動與動畫效果。
程式碼範例
以下提供 5 個實用範例,從最基礎的渲染到加入光源、貼圖與互動控制,逐步展示 Three.js 的使用方式。每段程式碼都附上說明註解,方便初學者快速上手。
1️⃣ 基本「Hello Three.js」:渲染一個彩色立方體
// 1. 建立渲染器 (Renderer) 並掛載到 HTML
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// 2. 建立場景 (Scene)
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x202020); // 深灰背景
// 3. 建立相機 (Camera)
const camera = new THREE.PerspectiveCamera(
75, // 視野角度 (FOV)
window.innerWidth / window.innerHeight, // 長寬比
0.1, 1000 // near & far 近平面、遠平面
);
camera.position.z = 5; // 把相機往 Z 軸拉遠
// 4. 建立立方體 (Mesh) → 幾何體 + 材質
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshStandardMaterial({ color: 0x00ff7f });
const cube = new THREE.Mesh(geometry, material);
scene.add(cube); // 把立方體加入場景
// 5. 加入一個環境光 (AmbientLight) 讓物件可見
const ambient = new THREE.AmbientLight(0xffffff, 0.6);
scene.add(ambient);
// 6. 動畫迴圈
function animate() {
requestAnimationFrame(animate);
cube.rotation.x += 0.01; // 旋轉
cube.rotation.y += 0.01;
renderer.render(scene, camera);
}
animate();
重點:只需 20 行左右的程式,就能在瀏覽器顯示一個會旋轉的 3D 立方體,這正是 Three.js 降低門檻的核心所在。
2️⃣ 加入光源與陰影
// 1. 新增平行光 (DirectionalLight) 並啟用陰影
const dirLight = new THREE.DirectionalLight(0xffffff, 1);
dirLight.position.set(5, 10, 7);
dirLight.castShadow = true; // 允許投射陰影
scene.add(dirLight);
// 2. 設定渲染器支援陰影
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
// 3. 讓立方體與平面 (ground) 接收/投射陰影
cube.castShadow = true;
cube.receiveShadow = true;
// 4. 建立一個平面作為地面
const planeGeom = new THREE.PlaneGeometry(10, 10);
const planeMat = new THREE.MeshStandardMaterial({ color: 0x808080 });
const ground = new THREE.Mesh(planeGeom, planeMat);
ground.rotation.x = -Math.PI / 2; // 旋轉成水平面
ground.position.y = -1;
ground.receiveShadow = true;
scene.add(ground);
小技巧:陰影的品質與效能會受到
shadow.mapSize、camera.near/far等參數影響,開發時可根據需求調整。
3️⃣ 使用貼圖 (Texture) 為物件上色
// 1. 載入貼圖 (TextureLoader)
const loader = new THREE.TextureLoader();
const woodTex = loader.load('https://threejs.org/examples/textures/wood.jpg');
// 2. 建立材質時使用貼圖
const woodMat = new THREE.MeshStandardMaterial({ map: woodTex });
const box = new THREE.Mesh(new THREE.BoxGeometry(2, 2, 2), woodMat);
box.position.x = -3;
scene.add(box);
注意:若貼圖檔案較大,建議在
loader.load時加上 onLoad、onProgress、onError 回呼,以利除錯與載入提示。
4️⃣ 加入相機控制 (OrbitControls)
// 需要先在 HTML 中載入 three.js 的附加模組
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
// 建立控制器,讓使用者可以拖曳、縮放、旋轉相機
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true; // 平滑慣性
controls.dampingFactor = 0.05;
// 在動畫迴圈中更新控制器
function animate() {
requestAnimationFrame(animate);
controls.update(); // 必須在每幀呼叫
renderer.render(scene, camera);
}
animate();
實務建議:在手機或平板上使用時,記得加入
touch-action: none;的 CSS,以避免瀏覽器的預設手勢干擾。
5️⃣ 載入外部 3D 模型 (GLTF)
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
const gltfLoader = new GLTFLoader();
gltfLoader.load(
'https://threejs.org/examples/models/gltf/Duck/glTF/Duck.gltf',
(gltf) => {
const duck = gltf.scene;
duck.scale.set(0.01, 0.01, 0.01); // 調整大小
scene.add(duck);
},
(xhr) => {
console.log(`模型載入進度: ${(xhr.loaded / xhr.total) * 100}%`);
},
(error) => {
console.error('GLTF 載入失敗', error);
}
);
關鍵:GLTF 是目前最流行的 Web 3D 模型格式,支援 PBR 材質、動畫與壓縮,搭配 Three.js 的
GLTFLoader幾乎是「即插即用」的最佳選擇。
常見陷阱與最佳實踐
| 陷阱 | 為何會發生 | 解決方案 / 最佳實踐 |
|---|---|---|
| 忘記設定渲染尺寸 | renderer.setSize 未隨視窗變化更新,導致畫面模糊或被裁切。 |
監聽 window.resize 事件,重新呼叫 setSize 與相機的 aspect。 |
| 過度使用全局變數 | 把 scene、camera、renderer 放在全局,造成程式難以維護。 |
使用 ES6 模組或 Class 包裝,保持單一職責。 |
| 陰影效能過低 | shadow.mapSize 預設 512x512,遠距離或大量光源會卡頓。 |
依需求調整 mapSize,或改用 ** baked lighting**(光照貼圖)。 |
| 貼圖跨域被阻擋 | 直接載入外部圖片時,瀏覽器會因 CORS 政策阻擋。 | 確保伺服器回傳 Access-Control-Allow-Origin:*,或自行託管資源。 |
| 相機遠近裁剪不當 | near 設太小或 far 設太大,會產生 Z‑buffer 精度問題,出現深度抖動。 |
根據場景規模調整 near、far,盡可能保持差距小。 |
| 未釋放資源 | 動態載入模型或貼圖後未呼叫 dispose(),導致記憶體泄漏。 |
在不需要時呼叫 geometry.dispose()、material.dispose()、texture.dispose()。 |
最佳實踐總結:
- 模組化:將渲染、相機、控制器分離成獨立檔案。
- 效能優化:使用
requestAnimationFrame、適當的 LOD(Level of Detail)與 InstancedMesh。- 除錯工具:利用 Chrome DevTools 的 WebGL Inspector 或 Three.js 的 Stats.js 觀察 FPS、記憶體與渲染呼叫次數。
實際應用場景
| 領域 | 典型案例 | 為何選擇 Three.js |
|---|---|---|
| 電商 | 3D 商品展示、360° 旋轉視圖 | 直接在瀏覽器呈現高品質模型,提升轉換率。 |
| 建築可視化 | 虛擬看房、室內規劃 | 支援光照、材質與實時陰影,讓客戶感受真實空間。 |
| 教育與培訓 | 交互式科學模擬、解剖圖譜 | 可結合動畫與互動控制,提升學習效果。 |
| 遊戲 | 簡易 WebGL 小遊戲、多人協作平台 | Three.js 提供完整的渲染管線與事件系統,快速原型。 |
| 資料視覺化 | 3D 數據圖表、地理資訊系統 (GIS) | 利用 3D 空間呈現多維度資料,增加資訊密度。 |
| 藝術與互動裝置 | 網頁藝術、AR/VR 體驗 | 支援 WebXR、Post‑Processing 效果,打造沉浸式作品。 |
案例參考:
- Google Arts & Culture:使用 Three.js 建立 3D 藝術品與博物館導覽。
- Sketchfab:提供即時 3D 模型預覽,底層即是 Three.js。
總結
- WebGL 是瀏覽器提供的底層 GPU 渲染介面,功能強大但語法繁瑣。
- Three.js 把 WebGL 包裝成直觀的物件模型(Scene、Camera、Renderer),讓開發者可以專注於 「什麼」 而非 「怎麼」。
- 透過 Mesh、Light、Texture 等核心概念,我們可以快速建立靜態或動態的 3D 場景;再結合 OrbitControls、GLTFLoader 等附加套件,便能完成交互、模型載入與即時動畫。
- 在開發過程中,注意 尺寸調整、陰影效能、資源釋放 以及 CORS 等常見陷阱,遵循模組化與效能優化的最佳實踐,能讓專案更易維護且表現更佳。
- 從電商到教育、從建築可視化到 Web 遊戲,Three.js 已經成為 Web 3D 開發的事實標準,未來隨著 WebXR 與雲端渲染的演進,它的應用範圍將更為廣闊。
下一步:如果你已經熟悉本篇的基礎概念,建議直接動手改寫上面的範例,嘗試載入自己的模型、加入自訂 Shader,或是結合 React、Vue 的元件化框架,開啟屬於自己的 3D 網頁之旅吧! 🚀