本文 AI 產出,尚未審核

Three.js 教學 – CubeTexture 與環境貼圖(Environment Map)


簡介

在 3D 網頁應用中,光影與反射往往是提升真實感的關鍵。CubeTexture(立方體貼圖)與 Environment Map(環境貼圖) 正是實作這類效果的核心工具。透過一組六張貼圖(正負 X、Y、Z 方向)組成的立方體貼圖,我們可以讓金屬、玻璃或水面等材質在 Three.js 中呈現出逼真的環境反射,甚至模擬全局光照(IBL)。

本單元將說明:

  1. CubeTexture 的概念與載入方式
  2. 如何將 CubeTexture 套用為環境貼圖(envMap
  3. 常見的坑與最佳實踐,讓你的專案既美觀又效能友好

適用對象:剛接觸 Three.js 的新手、想在作品中加入環境反射的中階開發者,以及需要優化貼圖載入流程的前端工程師。


核心概念

1. 什麼是 CubeTexture?

CubeTexture 本質上是一組 六張 正方形貼圖,分別對應立方體的六個面:

面向 細節說明
+X 右側 (right)
-X 左側 (left)
+Y 上方 (top)
-Y 下方 (bottom)
+Z 前方 (front)
-Z 後方 (back)

當這六張貼圖被載入後,Three.js 會自動把它們包成一個 立方體環境,供材質的 envMap 使用。這種方式比起單張全景貼圖(equirectangular)更適合即時渲染,因為 GPU 可以直接以立方體貼圖取樣。

2. 為什麼使用環境貼圖?

  • 真實感:金屬、玻璃等材質會根據周圍環境產生高光與反射。
  • 全局光照 (IBL):配合 PMREMGenerator,可將環境光照資訊轉為漫射光照,讓場景的間接光更自然。
  • 簡化光源:只需要一組環境貼圖,即可為整個場景提供統一的光照基礎,減少大量 point/spot light 的使用。

3. 基本載入流程

Three.js 提供兩種主要方式載入 CubeTexture:

方法 說明
THREE.CubeTextureLoader 直接載入六張圖檔,最常用。
THREE.TextureLoader + THREE.EquirectangularToCubeGenerator 先載入 equirectangular 全景圖,再轉換為 CubeTexture(較少用,但可直接使用單張 HDR 圖)。

下面先以 CubeTextureLoader 為例說明。


程式碼範例

:以下範例皆假設已經在 HTML 中加入 Three.js(<script src="https://unpkg.com/three@0.165.0/build/three.min.js"></script>)以及一個基本的渲染迴圈。

1️⃣ 基本 CubeTexture 載入與設定背景

// 建立場景
const scene = new THREE.Scene();

// 使用 CubeTextureLoader 載入六張環境貼圖
const loader = new THREE.CubeTextureLoader();
const envMap = loader.load([
  'textures/skybox/px.jpg', // +X
  'textures/skybox/nx.jpg', // -X
  'textures/skybox/py.jpg', // +Y
  'textures/skybox/ny.jpg', // -Y
  'textures/skybox/pz.jpg', // +Z
  'textures/skybox/nz.jpg'  // -Z
]);

// 設定場景的背景為 CubeTexture
scene.background = envMap;

// 後續相機、渲染器等設定...

說明:載入完成後,scene.background 會自動以立方體形式呈現,讓使用者在瀏覽器中看到完整的天空盒。

2️⃣ 為材質加入環境貼圖(金屬球體)

// 建立一個金屬球體幾何
const geometry = new THREE.SphereGeometry(1, 64, 64);

// 使用 MeshStandardMaterial,並指定 envMap
const material = new THREE.MeshStandardMaterial({
  metalness: 1.0,      // 完全金屬
  roughness: 0.05,     // 稍微粗糙,避免完全鏡面
  envMap: envMap,      // 套用先前載入的 CubeTexture
  envMapIntensity: 1.0 // 環境光照強度,可自行調整
});

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

技巧envMapIntensity 可以控制環境光對材質的影響程度,若場景光源較強,可適度降低此值避免過曝。

3️⃣ 使用 PMREMGenerator 產生預濾環境貼圖(提升 IBL 效果)

PMREMGenerator 會把 CubeTexture 轉換成 預濾的 Mipmap,讓 MeshStandardMaterial 在不同粗糙度下都能得到正確的光照。

// 建立渲染器(必須支援 WebGL2 才能完整支援 PMREM)
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

// 產生 PMREM(預濾環境貼圖)
const pmremGenerator = new THREE.PMREMGenerator(renderer);
pmremGenerator.compileCubemapShader();

// 使用 PMREM 轉換 envMap
const envMapPMREM = pmremGenerator.fromCubemap(envMap).texture;

// 替換材質的 envMap
material.envMap = envMapPMREM;
material.needsUpdate = true;

// 釋放資源
pmremGenerator.dispose();

重點:若不使用 PMREM,粗糙度較高的材質會出現不自然的光斑。PMREM 能讓光線在不同粗糙度下平滑過渡。

4️⃣ 動態切換環境貼圖(例如白天/夜晚切換)

// 先預先載入兩套 CubeTexture
const dayEnv = loader.load([
  'textures/day/px.jpg', 'textures/day/nx.jpg',
  'textures/day/py.jpg', 'textures/day/ny.jpg',
  'textures/day/pz.jpg', 'textures/day/nz.jpg'
]);

const nightEnv = loader.load([
  'textures/night/px.jpg', 'textures/night/nx.jpg',
  'textures/night/py.jpg', 'textures/night/ny.jpg',
  'textures/night/pz.jpg', 'textures/night/nz.jpg'
]);

// 產生 PMREM
const dayPMREM = pmremGenerator.fromCubemap(dayEnv).texture;
const nightPMREM = pmremGenerator.fromCubemap(nightEnv).texture;

// 切換環境的函式
function setEnvironment(isDay) {
  const env = isDay ? dayPMREM : nightPMREM;
  scene.background = env;          // 背景切換
  material.envMap = env;           // 材質環境貼圖切換
  material.needsUpdate = true;
}

// 範例:每 5 秒切換一次
let isDay = true;
setInterval(() => {
  isDay = !isDay;
  setEnvironment(isDay);
}, 5000);

實務建議:若貼圖檔案較大,建議使用 gzip / brotli 壓縮,或採用 KTX2 / Basis 格式以減少載入時間。

5️⃣ 使用 HDR equirectangular 圖檔產生 CubeTexture(進階)

// 載入 HDR 全景圖(需 three/examples/jsm/loaders/RGBELoader)
import { RGBELoader } from 'three/examples/jsm/loaders/RGBELoader.js';
import { PMREMGenerator } from 'three';

const hdrLoader = new RGBELoader();
hdrLoader.setDataType(THREE.UnsignedByteType); // 若使用 .hdr,使用 FloatType 會更準確

hdrLoader.load('textures/hdr/royal_esplanade_1k.hdr', (hdrTexture) => {
  // 轉換為 CubeTexture
  const envMap = pmremGenerator.fromEquirectangular(hdrTexture).texture;

  // 設定背景與材質
  scene.background = envMap;
  material.envMap = envMap;
  material.needsUpdate = true;

  // 釋放原始 HDR 資源
  hdrTexture.dispose();
});

說明:HDR 圖檔提供更寬廣的亮度範圍,搭配 MeshStandardMaterial 可得到更自然的光照與反射。此方法適合高品質的產品可視化或遊戲原型。


常見陷阱與最佳實踐

陷阱 解決方式 為什麼重要
貼圖方向不正確(六張圖的 X/Y/Z 方向錯位) 使用 THREE.CubeTextureLoader 時,檔名順序必須嚴格遵守 px, nx, py, ny, pz, nz。若方向錯誤,可在載入後使用 texture.mapping = THREE.CubeReflectionMapping 強制設定。 方向錯誤會導致環境貼圖的反射「倒置」或「錯位」,破壞真實感。
貼圖尺寸不一致 確保六張圖的寬高相同,且為 2 的次方(256、512、1024…)。 GPU Mipmap 生成需要相同尺寸,否則會自動縮放,影響效能與畫質。
未使用 PMREM MeshStandardMaterial 提供 pmremGenerator.fromCubemap 產出的貼圖。 粗糙材質會出現雜訊或不自然的光斑。
過大的貼圖檔案 採用 KTX2 / BasisDDS 壓縮格式,並在服務器端啟用 gzip/brotli 減少下載時間與記憶體佔用,提升手機端體驗。
環境貼圖與場景光源不協調 使用 THREE.HemisphereLightTHREE.AmbientLight 配合環境貼圖,或直接使用 scene.environment = envMap(Three.js r150+)讓渲染器自動提供環境光。 只靠環境貼圖不會產生間接光,場景會顯得暗淡。
忘記釋放資源 在不再使用時呼叫 texture.dispose()pmremGenerator.dispose() 防止記憶體泄漏,尤其在單頁應用(SPA)中切換場景時。

小技巧

  • 預載 (preload) 環境貼圖:在首次顯示前使用 loader.loadonLoad 回呼,確保使用者不會看到白屏或貼圖閃爍。
  • 使用 scene.environment:自 r150 起,Three.js 支援直接將環境貼圖指定給 scene.environment,渲染器會自動將其作為 IBL 使用,簡化程式碼。
  • 動態模糊 (blur) 背景:若想要「景深」效果,可在渲染後將 scene.backgroundTHREE.ShaderPass 做高斯模糊,保持環境貼圖的反射仍保持清晰。

實際應用場景

場景 為何使用 CubeTexture & Environment Map
產品可視化(金屬手機、玻璃瓶) 讓材質呈現真實的鏡面反射與光澤,提升客戶的購買慾望。
3D 遊戲(太空船、機器人) 使用環境貼圖提供全局光照,減少大量光源的計算,提升 FPS。
虛擬展覽(博物館、畫廊) 透過立方體天空盒營造沉浸式環境,並讓展品表面自然反射展廳光線。
AR/VR 應用 立方體貼圖的取樣方式在 WebXR 中效能較佳,可即時更新環境光。
教學與原型 快速切換白天/夜晚環境,驗證材質在不同光照下的表現。

案例:在一個展示「高光金屬汽車」的網站中,開發者使用 PMREMGenerator 產生的 CubeTexture 作為 scene.environment,再加上 MeshStandardMaterialmetalness: 1roughness: 0.1,最終得到光滑且具備環境反射的車身,且在手機端仍保持 60 FPS 以上的流暢度。


總結

  • CubeTexture 是由六張方向貼圖組成的立方體貼圖,適合即時渲染環境反射與 IBL。
  • Environment Map(環境貼圖)透過 MeshStandardMaterial.envMapscene.environment 為材質提供反射與間接光。
  • 使用 PMREMGenerator 產生預濾環境貼圖,可讓不同粗糙度的材質都呈現自然光照。
  • 常見的錯誤包括貼圖方向、尺寸不一致、未使用 PMREM、資源未釋放等,掌握最佳實踐即可避免效能與畫質問題。
  • 這項技術在 產品展示、遊戲、虛擬展覽與 AR/VR 等領域都有廣泛應用,能顯著提升使用者的沉浸感與視覺品質。

下一步:試著將本教學中的範例套用到你自己的 Three.js 專案,先從簡單的金屬球體開始,逐步加入 HDR 環境貼圖與動態切換,感受環境光對畫面氛圍的巨大影響吧!祝開發順利 🚀