Three.js – 部署與相容性
手機效能最佳化
簡介
在行動裝置上使用 Three.js 建立 3D 互動體驗時,效能往往是成敗關鍵。手機的 CPU、GPU、記憶體與網路頻寬相較於桌面電腦都較為受限,若不加以調校,即使在開發階段看起來流暢的場景,實際部署到手機上也可能出現卡頓、掉幀或甚至崩潰的情況。
本單元將說明在 部署與相容性 章節中,如何針對手機平台進行效能優化。從資源載入、渲染設定、材質簡化到程式碼層面的最佳實踐,我們會提供具體的範例與說明,幫助初學者到中級開發者在實務上快速提升 Three.js 應用的手機體驗。
核心概念
1. 渲染解析度與 DPR(Device Pixel Ratio)
手機螢幕的 DPI 很高,直接使用 window.devicePixelRatio 會讓渲染解析度成倍提升,導致 GPU 負擔過重。常見的做法是 限制 DPR,只在需要清晰文字時才提升。
// 設定渲染器,將 DPR 限制在 2 以內
const renderer = new THREE.WebGLRenderer({ antialias: true });
const maxDPR = Math.min(window.devicePixelRatio, 2);
renderer.setPixelRatio(maxDPR);
renderer.setSize(window.innerWidth, window.innerHeight);
註:
antialias: true會增加額外的 GPU 工作,若效能不足可改為false,改用 FXAA 後期處理。
2. 簡化幾何體與使用 InstancedMesh
大量相同模型(如樹、石頭)若分別建立 Mesh,會產生大量的 draw call。InstancedMesh 允許一次傳遞多個實例,大幅降低 CPU → GPU 的溝通成本。
// 建立 1,000 個相同的箱子實例
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshStandardMaterial({ color: 0x8ac });
const count = 1000;
const instancedMesh = new THREE.InstancedMesh(geometry, material, count);
const dummy = new THREE.Object3D();
for (let i = 0; i < count; i++) {
dummy.position.set(
(Math.random() - 0.5) * 100,
(Math.random() - 0.5) * 100,
(Math.random() - 0.5) * 100
);
dummy.updateMatrix();
instancedMesh.setMatrixAt(i, dummy.matrix);
}
scene.add(instancedMesh);
提示:即使場景中有上千個實例,
InstancedMesh仍只產生 一個 draw call。
3. 使用低多邊形模型與 LOD(Level of Detail)
手機的 GPU 處理高多邊形模型的速度有限。透過 LOD 機制,根據相機距離切換不同細節等級的模型,遠距離時使用低多邊形版本,近距離才切換高細節模型。
const lod = new THREE.LOD();
// 高細節模型(2000 面)
const high = new THREE.Mesh(highGeometry, material);
lod.addLevel(high, 0); // 距離 0 開始顯示
// 中等細節模型(500 面)
const medium = new THREE.Mesh(mediumGeometry, material);
lod.addLevel(medium, 50); // 超過 50 單位距離切換
// 低細節模型(100 面)
const low = new THREE.Mesh(lowGeometry, material);
lod.addLevel(low, 150); // 超過 150 單位距離切換
scene.add(lod);
實務建議:在建模階段就先輸出多個 LOD 版本,或使用工具(如 Blender 的 Decimate Modifier)自動產生。
4. 簡化材質與關閉不必要的特效
MeshStandardMaterial、MeshPhysicalMaterial 雖然寫實,但會觸發 光照與環境貼圖 的計算,對手機效能影響較大。若不需要真實感,可改用 MeshBasicMaterial 或自行關閉部分功能。
// 基本材質,無光照計算,適合 UI 或背景平面
const basicMat = new THREE.MeshBasicMaterial({ map: texture });
// 若仍想保留光照,但減少運算
const simpleMat = new THREE.MeshStandardMaterial({
color: 0xffffff,
roughness: 0.8, // 增大 roughness 減少高光
metalness: 0.0, // 關閉金屬度
envMap: null // 移除環境貼圖
});
此外,後期處理(post‑processing)如 Bloom、DOF 在手機上非常吃資源,建議僅在必要時使用,或改用較輕量的 shader。
5. 針對觸控與動畫的節流(throttling)
手機瀏覽器的主執行緒同時負責 UI、觸控事件與渲染,若在 requestAnimationFrame 內執行過多計算,會導致掉幀。可透過 節流 或 分幀 的方式降低每幀的工作量。
let frameCount = 0;
function animate() {
requestAnimationFrame(animate);
frameCount++;
// 每 2 幀更新一次複雜的粒子模擬
if (frameCount % 2 === 0) {
updateParticleSystem();
}
// 每 3 幀才重新計算一次 UI 位置
if (frameCount % 3 === 0) {
updateUIPositions();
}
renderer.render(scene, camera);
}
animate();
技巧:使用
performance.now()監測每幀耗時,動態調整節流比例。
常見陷阱與最佳實踐
| 陷阱 | 為什麼會發生 | 解決方式 |
|---|---|---|
| 過度使用透明材質 | 每個透明物件都會觸發 深度排序,CPU 負擔提升 | 減少透明物件數量,改用 Alpha Test (material.alphaTest = 0.5) |
| 未針對手機壓縮貼圖 | 大尺寸 PNG/JPG 會佔用大量記憶體與下載時間 | 使用 KTX2 / Basis 壓縮格式,配合 THREE.TextureLoader 的 compressedTextureExtension |
忽略 preserveDrawingBuffer |
若設為 true 會禁用 GPU 內部快取,導致渲染效能下降 |
只在需要截圖或讀取像素時才開啟,平常保持 false |
| 過高的光源數量 | 每個光源都會產生額外的 shader 計算 | 限制光源在 4~6 個以內,使用 光照貼圖 (lightmap) 取代部分光源 |
未使用 requestIdleCallback |
背景任務(如載入模型)占用主執行緒 | 在非關鍵時刻使用 requestIdleCallback 或 setTimeout 分批載入資源 |
最佳實踐總結
- 先測後調:使用 Chrome DevTools 的 Performance 與 Memory 分析工具,找出瓶頸。
- 資源預處理:模型、貼圖、動畫在上傳前即完成 簡化、壓縮。
- 分層渲染:將 UI、特效、主場景分別放在不同的渲染層,必要時可關閉不需要的層。
- 動態適配:根據裝置性能(
navigator.hardwareConcurrency、GPU 渲染時間)動態調整畫質設定。
實際應用場景
1. 行動廣告互動式 3D Banner
- 需求:在手機瀏覽器中展示 30 秒的 3D 產品廣告,需保持 30 FPS。
- 做法:使用 InstancedMesh 渲染多個產品模型,將材質降為
MeshBasicMaterial,貼圖採 Basis 壓縮;動畫僅在可視區域內播放,離開視窗即暫停。
2. 手機遊戲的場景切換
- 需求:在不同關卡之間快速切換場景,避免長時間載入。
- 做法:將每個關卡的資源打包成 GLTF 的 binary (.glb),搭配
DRACOLoader壓縮網格;場景切換時使用renderer.dispose()釋放舊資源,並在背景使用requestIdleCallback預載下一關的貼圖。
3. AR(Augmented Reality)應用
- 需求:在 WebXR 中顯示虛擬模型,保持即時追蹤與渲染。
- 做法:限制模型面數 < 5k,使用 LOD;渲染器開啟 XRSession 時自動把
pixelRatio設為 1.5;使用 FXAA 替代 MSAA,減少 GPU 計算。
總結
手機效能最佳化是 Three.js 部署過程中不可或缺的一環。透過 限制 DPR、使用 InstancedMesh、實作 LOD、簡化材質、節流動畫,可以在保留視覺品質的同時,讓應用在各種行動裝置上保持流暢。面對實務開發時,務必先 量測、再優化,並遵循「資源預處理 → 渲染最小化 → 動態調整」的工作流程。
掌握這些技巧後,你的 Three.js 手機專案將不再因效能問題而受限,使用者也能享受到更順暢、更具沉浸感的 3D 體驗。祝開發順利!