本文 AI 產出,尚未審核

Three.js 基礎概念 – 架構與核心組件

簡介

在現代 Web 開發中,3D 互動體驗已成為提升使用者黏著度的重要手段。Three.js 作為最成熟、最廣為使用的 WebGL 包裝函式庫,讓開發者不必直接與低階的 WebGL API 打交道,就能在瀏覽器裡建立、渲染與控制 3D 內容。本單元將從 架構核心組件 兩個層面,說明 Three.js 的設計哲學與實作概念,幫助你快速掌握「從零到可用」的基本流程。

為什麼要先了解架構?
只有真正理解 Three.js 各個模組之間的關係,才能在開發過程中正確選擇、擴充與優化,避免「只會套用範例」的表層使用,進而打造高效、可維護的 3D 專案。


核心概念

1. Scene(場景)

Scene 是所有 3D 物件的容器,類似於「舞台」的概念。所有的 Mesh、Light、Camera 等都必須加入到 Scene 中,渲染器才會把它們畫出來。

// 建立一個空的場景
const scene = new THREE.Scene();
// 也可以設定背景色或背景貼圖
scene.background = new THREE.Color(0x202020);

2. Camera(相機)

相機決定了「觀察者」的視角與投影方式。Three.js 主要提供兩種相機:

類型 用途 主要屬性
PerspectiveCamera 模擬人眼透視效果,適合大多數 3D 應用 fovaspectnearfar
OrthographicCamera 平行投影,常用於 2.5D 或 UI 叠加 leftrighttopbottomnearfar
// 建立透視相機,視野 75°、寬高比根據視窗自動調整
const camera = new THREE.PerspectiveCamera(
  75,
  window.innerWidth / window.innerHeight,
  0.1,
  1000
);
camera.position.set(0, 2, 5); // 把相機拉遠一點

3. Renderer(渲染器)

渲染器負責把 Scene 內的物件依照相機的視角,以 WebGL 的方式繪製到 <canvas> 上。最常用的是 WebGLRenderer,它支援抗鋸齒、陰影、HDR 等功能。

const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

// 開啟陰影
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;

4. Mesh(網格)與 Geometry(幾何)

Mesh 是「形狀」+「材質」的組合。Geometry(或 BufferGeometry)定義頂點、索引與其他屬性;Material 則決定表面的光照、顏色與貼圖。

// 建立一個簡單的盒子幾何
const geometry = new THREE.BoxGeometry(1, 1, 1);

// 使用標準材質,支援光照與環境貼圖
const material = new THREE.MeshStandardMaterial({
  color: 0x156289,
  metalness: 0.5,
  roughness: 0.4
});

const cube = new THREE.Mesh(geometry, material);
cube.castShadow = true;   // 允許投射陰影
cube.receiveShadow = true;
scene.add(cube);

5. Light(光源)

光源提供場景中的光照資訊,常見的光源類型有:

  • AmbientLight:全局均勻光,無方向性,常用來提升基礎亮度。
  • DirectionalLight:類似太陽光,光線平行,可投射陰影。
  • PointLight:點光源,光線向四面八方擴散。
  • SpotLight:聚光燈,有錐形範圍與衰減。
// 環境光
const ambient = new THREE.AmbientLight(0xffffff, 0.4);
scene.add(ambient);

// 平行光(模擬太陽)
const dirLight = new THREE.DirectionalLight(0xffffff, 1);
dirLight.position.set(5, 10, 7);
dirLight.castShadow = true;
scene.add(dirLight);

6. 控制器(Controls)

為了讓使用者能在瀏覽器中自由旋轉、平移或縮放視角,Three.js 提供了多種控制器(在 three/examples/jsm/controls/ 中)。最常用的是 OrbitControls

import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';

const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true; // 平滑慣性
controls.dampingFactor = 0.05;

7. Animation Loop(動畫迴圈)

Three.js 並不自動啟動渲染,必須自行寫一個渲染迴圈,通常使用 requestAnimationFrame

function animate() {
  requestAnimationFrame(animate);

  // 讓立方體持續旋轉
  cube.rotation.x += 0.01;
  cube.rotation.y += 0.01;

  controls.update(); // 只在 enableDamping 時需要呼叫
  renderer.render(scene, camera);
}
animate();

程式碼範例

以下提供 5 個實用範例,涵蓋從最簡單的「Hello Three」到加入貼圖與陰影的完整流程。

範例 1:最小 Hello Three

import * as THREE from 'three';

const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, innerWidth / innerHeight, 0.1, 100);
camera.position.z = 3;

const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(innerWidth, innerHeight);
document.body.appendChild(renderer.domElement);

// 只要一個紅色方塊
const geometry = new THREE.BoxGeometry();
const material = new THREE.MeshBasicMaterial({ color: 0xff0000 });
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);

function render() {
  requestAnimationFrame(render);
  renderer.render(scene, camera);
}
render();

範例 2:加入光照與陰影

// ...(前半段同上)
// 替換 MeshBasicMaterial 為 MeshStandardMaterial
const material = new THREE.MeshStandardMaterial({ color: 0x156289 });
cube.castShadow = true;
cube.receiveShadow = true;

// 設定渲染器陰影
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;

// 平行光投射陰影
const dirLight = new THREE.DirectionalLight(0xffffff, 1);
dirLight.position.set(5, 10, 5);
dirLight.castShadow = true;
scene.add(dirLight);

// 加一個平面接收陰影
const planeGeo = new THREE.PlaneGeometry(10, 10);
const planeMat = new THREE.MeshStandardMaterial({ color: 0x808080 });
const plane = new THREE.Mesh(planeGeo, planeMat);
plane.rotation.x = -Math.PI / 2;
plane.position.y = -0.5;
plane.receiveShadow = true;
scene.add(plane);

範例 3:載入外部貼圖(Texture)

import { TextureLoader } from 'three';

// 建立貼圖載入器
const loader = new TextureLoader();
loader.load('textures/brick_diffuse.jpg', (texture) => {
  const mat = new THREE.MeshStandardMaterial({ map: texture });
  const box = new THREE.Mesh(new THREE.BoxGeometry(2, 2, 2), mat);
  box.castShadow = true;
  scene.add(box);
});

範例 4:使用 GLTF 模型

import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';

const gltfLoader = new GLTFLoader();
gltfLoader.load('models/scene.gltf', (gltf) => {
  const model = gltf.scene;
  model.traverse((obj) => {
    if (obj.isMesh) obj.castShadow = true;
  });
  scene.add(model);
});

範例 5:結合 OrbitControls 與自適應視窗

window.addEventListener('resize', () => {
  const w = window.innerWidth;
  const h = window.innerHeight;
  camera.aspect = w / h;
  camera.updateProjectionMatrix();
  renderer.setSize(w, h);
});

常見陷阱與最佳實踐

陷阱 可能原因 解決方式 / 最佳實踐
模型載入後不顯示 未加入場景、相機遠近裁切範圍不夠、材質未啟用光照 確認 scene.add(gltf.scene)、調整 camera.near/far、使用 MeshStandardMaterial
陰影看不見 渲染器未開啟陰影、光源未設置 castShadow、物件未設定 receiveShadow renderer.shadowMap.enabled = truelight.castShadow = truemesh.castShadow / receiveShadow = true
畫面卡頓 幾何體過於複雜、貼圖過大、未使用 requestAnimationFrame 的節流 使用 BufferGeometry、壓縮貼圖(DDS / KTX2)、在 animate 中只更新需要改變的部分
視窗變動後比例失真 相機寬高比未更新、渲染器尺寸未同步 監聽 resize 事件,重新設定 camera.aspectrenderer.setSize
控制器失靈 控制器未傳入正確的 DOM 元素或未呼叫 update() new OrbitControls(camera, renderer.domElement),在動畫迴圈中 controls.update()(若使用阻尼)

最佳實踐

  1. 模組化:把 scenecamerarenderercontrols 分別封裝成獨立檔案,提升可維護性。
  2. 資源預載:使用 LoadingManager 統一管理模型、貼圖的載入狀態,避免畫面閃爍。
  3. 效能監控:利用 stats.js 或 Chrome DevTools 的 GPU 時間,持續檢測幀率與渲染成本。
  4. 適度使用後處理EffectComposer 提供 Bloom、SSAO 等效果,但過度堆疊會大幅降低效能,務必根據目標裝置做取捨。

實際應用場景

領域 典型案例 為何選 Three.js
電商 3D 商品展示、虛擬試穿 輕量、即時渲染、支援手機瀏覽器
教育 交互式分子結構、天文模擬 可自訂動畫、結合資料驅動視覺化
建築 虛擬看房、室內佈局規劃 支援 GLTF/OBJ、可加入實時光照與陰影
遊戲 簡易 WebGL 遊戲、AR/VR 體驗 完整的渲染管線、與 WebXR API 無縫整合
資料視覺化 3D 圖表、地圖投影 支援自訂 Shader、可與 D3.js、Three.js 共同使用

以上範例均展示了 Three.js 在 即時互動、跨平台、低門檻 等特性上的優勢,使其成為前端 3D 開發的首選。


總結

  • Three.js 的核心組件SceneCameraRendererMeshLightControls,相互協作完成 3D 渲染。
  • 透過 模組化、資源預載與效能監控,可以在保持開發效率的同時,確保最終作品在桌面與行動裝置上流暢運行。
  • 熟悉 光照、陰影與貼圖 的概念,能讓你的作品從「平面」躍升為「具備真實感」的 3D 體驗。
  • 最後,別忘了 持續練習與閱讀官方範例three/examples),那裡匯聚了最完整的實務技巧與最新的 API 變更。

掌握了架構與核心組件之後,你就能自如地在任何 Web 專案中加入 3D 元素,為使用者創造更豐富、更具沉浸感的互動體驗。祝你玩得開心,創作無限!