本文 AI 產出,尚未審核

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 物件的容器,類似「舞台」 backgroundadd()remove()
Camera 定義觀察者的位置、視角與投影方式 positionlookAt()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 事件或時間軸,通常會結合 requestAnimationFrameOrbitControls(相機控制)或 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.mapSizecamera.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 時加上 onLoadonProgressonError 回呼,以利除錯與載入提示。


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
過度使用全局變數 scenecamerarenderer 放在全局,造成程式難以維護。 使用 ES6 模組或 Class 包裝,保持單一職責。
陰影效能過低 shadow.mapSize 預設 512x512,遠距離或大量光源會卡頓。 依需求調整 mapSize,或改用 ** baked lighting**(光照貼圖)。
貼圖跨域被阻擋 直接載入外部圖片時,瀏覽器會因 CORS 政策阻擋。 確保伺服器回傳 Access-Control-Allow-Origin:*,或自行託管資源。
相機遠近裁剪不當 near 設太小或 far 設太大,會產生 Z‑buffer 精度問題,出現深度抖動。 根據場景規模調整 nearfar,盡可能保持差距小。
未釋放資源 動態載入模型或貼圖後未呼叫 dispose(),導致記憶體泄漏。 在不需要時呼叫 geometry.dispose()material.dispose()texture.dispose()

最佳實踐總結

  1. 模組化:將渲染、相機、控制器分離成獨立檔案。
  2. 效能優化:使用 requestAnimationFrame、適當的 LOD(Level of Detail)與 InstancedMesh
  3. 除錯工具:利用 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 網頁之旅吧! 🚀