本文 AI 產出,尚未審核

Three.js 課程 – 燈光 (Lights)

主題:PointLight、SpotLight、HemisphereLight


簡介

在 3D 場景中,燈光是決定畫面氛圍與物件可見度的關鍵因素。沒有適當的光源,模型只會呈現平淡的顏色,失去立體感與真實感。Three.js 提供了多種燈光類型,讓開發者可以依需求模擬自然光、聚光燈、環境光等不同效果。本單元聚焦於 PointLight、SpotLight、HemisphereLight 三種最常使用的燈光,說明它們的工作原理、使用時機以及實務上的最佳實踐,幫助你在 WebGL 專案中快速建立出具有層次感與氛圍的場景。


核心概念

1. PointLight(點光源)

PointLight 模擬一個無方向的光點,光線會向四面八方均勻散射,類似日常生活中的燈泡或螢火蟲。它的主要屬性包括:

屬性 說明
color 光的顏色(THREE.Color 或十六進位字串)
intensity 強度,預設 1,數值越大光越亮
distance 光照最遠距離,超過此距離光線會隨距離衰減,0 表示無限制
decay 衰減指數,2 為物理上正確的平方衰減(預設)

範例 1:基本 PointLight

// 建立場景、相機與渲染器(略)
const scene = new THREE.Scene();

// 1️⃣ 建立白色點光源,強度 2,距離 100
const pointLight = new THREE.PointLight(0xffffff, 2, 100);
pointLight.position.set(5, 10, 5); // 放置在場景上方
scene.add(pointLight);

// 為了看得更清楚,加入光源的輔助球體
const sphere = new THREE.Mesh(
  new THREE.SphereGeometry(0.2, 12, 12),
  new THREE.MeshBasicMaterial({ color: 0xffff00 })
);
sphere.position.copy(pointLight.position);
scene.add(sphere);

小技巧:在開發階段加入 THREE.PointLightHelper 可以即時觀察光源位置與範圍。

scene.add(new THREE.PointLightHelper(pointLight, 1));

2. SpotLight(聚光燈)

SpotLight 類似舞台燈光,從一個點向特定方向投射錐形光束,常用於聚焦某個物件或營造光斑效果。重要屬性:

屬性 說明
angle 錐形半角(弧度),預設 Math.PI / 3
penumbra 銳角的柔和程度,0~1,數值越大邊緣越柔和
target 指向的目標 THREE.Object3D(預設為原點)
decaydistance PointLight,控制衰減與範圍

範例 2:聚光燈聚焦模型

// 建立聚光燈,顏色淡藍,強度 1.5
const spotLight = new THREE.SpotLight(0x88ccff, 1.5, 200, Math.PI / 6, 0.3, 2);
spotLight.position.set(-10, 20, 10);
scene.add(spotLight);

// 設定聚光目標為場景中心 (0,0,0)
spotLight.target.position.set(0, 0, 0);
scene.add(spotLight.target);

// 加入輔助視覺化工具
scene.add(new THREE.SpotLightHelper(spotLight));

注意SpotLightHelper 只在光源屬性改變後需要手動呼叫 update(),否則不會即時反映。

spotLightHelper.update(); // 在每次改變 angle、penumbra 等時呼叫

3. HemisphereLight(半球光)

HemisphereLight 用來模擬天空與地面的環境光,光線從上方的「天空」顏色向下混合「地面」顏色,適合快速營造大範圍的柔和光照,常與其他光源結合使用。屬性:

屬性 說明
skyColor 上方光的顏色
groundColor 下方光的顏色
intensity 強度

範例 3:半球光 + 環境光

// 天藍色的天空光、淡橘色的地面光
const hemiLight = new THREE.HemisphereLight(0x87ceeb, 0xffe0b2, 0.6);
hemiLight.position.set(0, 50, 0); // 位置不影響光照,只是視覺化
scene.add(hemiLight);

// 為了更自然,可再加上一盞弱的 AmbientLight
const ambient = new THREE.AmbientLight(0xffffff, 0.2);
scene.add(ambient);

實務小提醒HemisphereLight 只能影響 材質支援的光照模型(如 MeshStandardMaterialMeshPhysicalMaterial),對 MeshBasicMaterial 無效。


程式碼範例(綜合實作)

以下示範一個完整的 Three.js 場景,結合三種光源,並展示如何在不同情況下切換或調整參數。

// ==================== 基本設定 ====================
import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';

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

const scene  = new THREE.Scene();
scene.background = new THREE.Color(0x202030);

const camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(10, 10, 20);
const controls = new OrbitControls(camera, renderer.domElement);

// ==================== 物件 ====================
const geometry = new THREE.BoxGeometry(4, 4, 4);
const material = new THREE.MeshStandardMaterial({ color: 0x8888ff, metalness: 0.2, roughness: 0.7 });
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);

// ==================== 燈光 ====================
// 1. PointLight
const pointLight = new THREE.PointLight(0xffaa33, 1.8, 80);
pointLight.position.set(5, 12, 5);
scene.add(pointLight);
scene.add(new THREE.PointLightHelper(pointLight, 1));

// 2. SpotLight
const spotLight = new THREE.SpotLight(0xffffff, 1.2, 150, Math.PI / 8, 0.4, 1);
spotLight.position.set(-15, 20, 10);
spotLight.target = cube; // 聚焦在立方體
scene.add(spotLight);
scene.add(new THREE.SpotLightHelper(spotLight));

// 3. HemisphereLight
const hemiLight = new THREE.HemisphereLight(0x87ceeb, 0x444444, 0.5);
scene.add(hemiLight);

// ==================== 渲染迴圈 ====================
function animate() {
  requestAnimationFrame(animate);
  cube.rotation.x += 0.005;
  cube.rotation.y += 0.01;
  controls.update();
  renderer.render(scene, camera);
}
animate();

// ==================== 互動調整(示範) ====================
// 按鍵 1~3 切換光源強度
window.addEventListener('keydown', (e) => {
  switch (e.key) {
    case '1': pointLight.intensity = pointLight.intensity === 0 ? 1.8 : 0; break;
    case '2': spotLight.intensity = spotLight.intensity === 0 ? 1.2 : 0; break;
    case '3': hemiLight.intensity = hemiLight.intensity === 0 ? 0.5 : 0; break;
  }
});

重點說明

  1. 光源位置PointLightSpotLight 的位置會直接影響陰影與高光位置。
  2. 目標設定SpotLight.target 必須是 THREE.Object3D,不設定則預設指向原點。
  3. Helper 使用:開發階段加入 Helper,可快速定位光源與光錐範圍。

常見陷阱與最佳實踐

陷阱 說明 解決方案
光源太多導致效能下降 每個光源都會觸發著色器計算,過多會讓 GPU 負荷過大。 只保留必要光源,使用 AmbientLight 補足環境光;或利用 光照貼圖(Lightmap) 減少即時計算。
陰影未顯示 忘記啟用 renderer.shadowMap.enabled = true,或未為光源與物件設定 castShadow / receiveShadow 在光源與需要投射/接受陰影的 Mesh 上分別設定 castShadow = truereceiveShadow = true
SpotLight 目標不正確 spotLight.target 若未加入場景,光錐會指向錯誤位置。 scene.add(spotLight.target); 確保目標物件被加入場景。
HemisphereLight 無效 使用了不支援光照的材質(如 MeshBasicMaterial)。 改用 MeshStandardMaterialMeshPhysicalMaterialMeshLambertMaterial
光衰減不自然 distance 設為 0 或過大,導致光線無法隨距離衰減。 設定合理的 distancedecay(建議使用 decay = 2),並根據場景大小調整。

最佳實踐

  1. 分層光源:先使用 HemisphereLightAmbientLight 打底,再加上局部光(PointLightSpotLight)做強調。
  2. 使用 Helper:開發階段加上 *Helper,上線前記得移除或隱藏。
  3. 動態調整:透過 UI(如 dat.GUI、Tweakpane)即時調整光源參數,快速找到最佳光照配置。
  4. 考慮實際場景尺度:光源的 distanceintensity 應與相機遠近、模型大小成比例,避免過亮或過暗。

實際應用場景

場景 推薦光源組合 為何適合
室內住宅展示 HemisphereLight(模擬天光)+ PointLight(吊燈)+ SpotLight(聚焦藝術品) 半球光提供柔和的環境光,點光源模擬室內燈具,聚光燈突出關鍵擺設。
夜間城市街道 SpotLight(街燈)+ PointLight(車燈)+ AmbientLight(微弱環境光) 聚光燈營造街燈光斑,點光源模擬車頭燈,環境光提供整體暗色調。
遊戲角色聚焦 SpotLight(聚光)+ HemisphereLight(天光) 聚光燈將視線集中在角色身上,半球光保持場景自然的光照基調。
產品渲染(商品展示) PointLight(環繞多點)+ HemisphereLight(基礎環境) 多點光源避免陰影死角,半球光提供均衡的環境光,使產品材質呈現更真實。

總結

本篇文章從 概念、屬性、程式範例 逐步說明了 Three.js 中三種常用光源的使用方式,並提供了 實務上的最佳實踐與常見陷阱。掌握 PointLightSpotLightHemisphereLight 的特性後,你可以:

  • 靈活組合光源,營造出日夜、室內外、聚焦與散射等多樣光照效果。
  • 透過 Helper 與 UI 調整,即時微調光照參數,提升開發效率。
  • 在效能與畫質之間取得平衡,避免過度使用光源造成的卡頓。

只要在實作時遵循「先環境光 → 再局部光 → 最後聚光」的層次思考,你的 Three.js 專案將會呈現更自然、更具沉浸感的視覺體驗。祝你在 3D 網頁開發的路上光芒四射! 🚀