本文 AI 產出,尚未審核

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. 簡化材質與關閉不必要的特效

MeshStandardMaterialMeshPhysicalMaterial 雖然寫實,但會觸發 光照與環境貼圖 的計算,對手機效能影響較大。若不需要真實感,可改用 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.TextureLoadercompressedTextureExtension
忽略 preserveDrawingBuffer 若設為 true 會禁用 GPU 內部快取,導致渲染效能下降 只在需要截圖或讀取像素時才開啟,平常保持 false
過高的光源數量 每個光源都會產生額外的 shader 計算 限制光源在 4~6 個以內,使用 光照貼圖 (lightmap) 取代部分光源
未使用 requestIdleCallback 背景任務(如載入模型)占用主執行緒 在非關鍵時刻使用 requestIdleCallbacksetTimeout 分批載入資源

最佳實踐總結

  1. 先測後調:使用 Chrome DevTools 的 PerformanceMemory 分析工具,找出瓶頸。
  2. 資源預處理:模型、貼圖、動畫在上傳前即完成 簡化、壓縮
  3. 分層渲染:將 UI、特效、主場景分別放在不同的渲染層,必要時可關閉不需要的層。
  4. 動態適配:根據裝置性能(navigator.hardwareConcurrency、GPU 渲染時間)動態調整畫質設定。

實際應用場景

1. 行動廣告互動式 3D Banner

  • 需求:在手機瀏覽器中展示 30 秒的 3D 產品廣告,需保持 30 FPS。
  • 做法:使用 InstancedMesh 渲染多個產品模型,將材質降為 MeshBasicMaterial,貼圖採 Basis 壓縮;動畫僅在可視區域內播放,離開視窗即暫停。

2. 手機遊戲的場景切換

  • 需求:在不同關卡之間快速切換場景,避免長時間載入。
  • 做法:將每個關卡的資源打包成 GLTFbinary (.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 體驗。祝開發順利!