Three.js 與工具整合:使用 glTF Viewer 測試模型
簡介
在使用 Three.js 建立 3D 網頁應用時,模型的品質與相容性往往是決定最終使用者體驗的關鍵。
glTF(GL Transmission Format)被稱為「JPEG of 3D」── 輕量、即時、且支援 PBR(Physically‑Based Rendering),已成為 Three.js 生態系統的事實標準。
然而,光有一個 .gltf 或 .glb 檔並不代表它一定能在瀏覽器中正確呈現。模型在匯入前需要 檢查結構、材質、動畫、壓縮 等資訊,這時 glTF Viewer(線上或本機版本)就扮演了「測試床」的角色。本文將說明如何透過 glTF Viewer 快速驗證模型,並示範在 Three.js 專案中配合使用的實務流程,讓你從 初學者 逐步晉升為 中級開發者。
核心概念
1. 為什麼要先用 glTF Viewer 測試模型?
| 目的 | 透過 glTF Viewer 可立即看到的結果 |
|---|---|
| 結構完整性 | JSON/二進位結構是否符合規範、節點層級是否正確 |
| 材質與貼圖 | PBR 參數、貼圖路徑、KTX2/DRACO 壓縮是否被正確讀取 |
| 動畫 | 任何骨骼動畫、形狀動畫(morph target)是否可播放 |
| 效能指標 | 多邊形數、頂點緩衝、記憶體大小等資訊 |
若在 Viewer 中已顯示正常,將模型搬入 Three.js 時出錯的概率會大幅下降,除錯成本也隨之降低。
2. 常見的 glTF Viewer 選擇
| Viewer | 特色 | 使用情境 |
|---|---|---|
官方線上 Viewerhttps://gltf-viewer.donmccurdy.com/ |
零安裝、即時支援 DRACO、KTX2、動畫 | 快速檢查模型、分享網址給同事 |
| 三維編輯器(Three.js Editor) | 可直接編輯場景、加入光源、相機 | 想同時測試渲染設定與模型 |
本機 npm 套件 gltf-viewer |
可在本機跑本地 server,支援離線檔案 | 大型專案、需要自訂 UI 或 CI 測試 |
| Blender 的 glTF Exporter | 直接在建模軟體內檢視 | 調整模型細節、重新匯出 |
本文以官方線上 Viewer 為主,並示範如何在本機使用 gltf-viewer 進行自動化測試。
3. 基本的 Three.js 載入流程
即使已在 Viewer 中驗證,仍需要在程式碼裡正確設定 GLTFLoader、DRACOLoader、KTX2Loader,以下範例逐步說明。
3.1 範例一:最簡單的 GLTF 載入
<!DOCTYPE html>
<html lang="zh-Hant">
<head>
<meta charset="UTF-8">
<title>Three.js + glTF Viewer 測試範例</title>
<style>body { margin:0; overflow:hidden; }</style>
</head>
<body>
<script type="module">
import * as THREE from 'https://cdn.jsdelivr.net/npm/three@0.162.0/build/three.module.js';
import { GLTFLoader } from 'https://cdn.jsdelivr.net/npm/three@0.162.0/examples/jsm/loaders/GLTFLoader.js';
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(60, innerWidth/innerHeight, 0.1, 1000);
camera.position.set(0, 1.5, 3);
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(innerWidth, innerHeight);
document.body.appendChild(renderer.domElement);
// 簡易環境光
scene.add(new THREE.AmbientLight(0xffffff, 0.8));
scene.add(new THREE.DirectionalLight(0xffffff, 0.5));
// 載入 glTF
const loader = new GLTFLoader();
loader.load(
// 👉 這裡放置剛在 glTF Viewer 測試過的檔案 URL
'models/Duck.glb',
gltf => {
scene.add(gltf.scene);
console.log('模型載入成功', gltf);
},
xhr => console.log(`載入進度:${(xhr.loaded / xhr.total * 100).toFixed(1)}%`),
err => console.error('載入失敗', err)
);
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
animate();
</script>
</body>
</html>
說明:
- 使用 ES Module 直接從 CDN 匯入 Three.js 與
GLTFLoader,免除本機安裝。loader.load的三個回呼分別處理 成功、進度、錯誤,在開發時可快速定位問題。
3.2 範例二:加入 DRACO 壓縮支援
若模型使用 DRACO 壓縮(可大幅減少檔案大小),必須先載入 DRACOLoader 並指向解碼器檔案。
import { DRACOLoader } from 'https://cdn.jsdelivr.net/npm/three@0.162.0/examples/jsm/loaders/DRACOLoader.js';
// 建立 DRACO Loader
const dracoLoader = new DRACOLoader();
// 官方 CDN 提供的解碼器路徑
dracoLoader.setDecoderPath('https://www.gstatic.com/draco/v1/decoders/');
// 把 DRACO Loader 設定給 GLTFLoader
const gltfLoader = new GLTFLoader();
gltfLoader.setDRACOLoader(dracoLoader);
gltfLoader.load('models/compressedModel.glb', gltf => {
scene.add(gltf.scene);
});
技巧:在本機開發時,建議把
decoderPath改成相對路徑,將 decoder 檔案放在public/draco/目錄,避免跨域問題。
3.3 範例三:使用 KTX2 (Basis) 壓縮貼圖
KTX2 支援 Basis Universal 壓縮,可在不同平台上自動解碼成最佳格式(ASTC、BC7、ETC2…)。
import { KTX2Loader } from 'https://cdn.jsdelivr.net/npm/three@0.162.0/examples/jsm/loaders/KTX2Loader.js';
import { MeshStandardMaterial } from 'three';
// 設定 KTX2 Loader
const ktx2Loader = new KTX2Loader()
.setTranscoderPath('https://cdn.jsdelivr.net/npm/three@0.162.0/examples/js/libs/basis/') // Basis 解碼器
.detectSupport(renderer); // 自動偵測 GPU 支援
// 把 KTX2 Loader 設定給 GLTFLoader
gltfLoader.setKTX2Loader(ktx2Loader);
gltfLoader.load('models/ktx2Model.glb', gltf => {
// 若想手動覆寫材質,可參考以下範例
gltf.scene.traverse(node => {
if (node.isMesh && node.material instanceof MeshStandardMaterial) {
// 例如強制使用 sRGB 顏色空間
node.material.map.encoding = THREE.sRGBEncoding;
}
});
scene.add(gltf.scene);
});
提醒:若瀏覽器不支援 WebGL2,KTX2 仍會退回到 Basis 軟解碼,但效能會下降。
3.4 範例四:播放模型內建動畫
import { AnimationMixer } from 'three';
let mixer;
gltfLoader.load('models/AnimatedRobot.glb', gltf => {
const model = gltf.scene;
scene.add(model);
// 建立 AnimationMixer
mixer = new AnimationMixer(model);
// 假設檔案內有多段動畫,取第一段播放
const clip = gltf.animations[0];
const action = mixer.clipAction(clip);
action.play();
});
function animate() {
requestAnimationFrame(animate);
const delta = clock.getDelta();
mixer?.update(delta); // 更新動畫
renderer.render(scene, camera);
}
要點:
AnimationMixer必須在每一幀呼叫update(delta),delta為上一幀與此幀的時間差。- 若模型包含 morph target(形狀鍵)動畫,使用
mesh.morphTargetInfluences來控制。
3.5 範例五:本機 gltf-viewer 套件結合 CI
在大型專案中,常需要在 CI/CD 流程中自動驗證新上傳的 glTF。gltf-viewer(npm)提供一個簡易的 CLI,能在 headless 瀏覽器中載入模型並輸出報告。
# 安裝套件
npm i -D gltf-viewer puppeteer
// scripts/validate-gltf.js
const { launch } = require('puppeteer');
const path = require('path');
const fs = require('fs');
(async () => {
const browser = await launch({ headless: true });
const page = await browser.newPage();
// 載入官方線上 Viewer(可自行改為本機 html)
await page.goto('https://gltf-viewer.donmccurdy.com/', { waitUntil: 'networkidle2' });
// 上傳模型(假設在 ./models 資料夾)
const input = await page.$('input[type="file"]');
await input.uploadFile(path.resolve(__dirname, '../models/testModel.glb'));
// 等待解析完成
await page.waitForSelector('.info-panel', { timeout: 5000 });
// 取得模型資訊(多邊形數、材質數等)
const info = await page.evaluate(() => {
const txt = document.querySelector('.info-panel').innerText;
return txt;
});
console.log('模型資訊:\n', info);
await browser.close();
})();
在 .github/workflows/ci.yml 中加入:
- name: Validate glTF models
run: node scripts/validate-gltf.js
效益:每次 PR 時自動檢查模型是否破損、貼圖遺失或動畫錯誤,避免因模型問題卡住前端開發。
常見陷阱與最佳實踐
| 陷阱 | 可能的症狀 | 解決方案 / 最佳實踐 |
|---|---|---|
| 貼圖路徑不一致 | 在 Viewer 正常,Three.js 中顯示黑白或缺少材質 | 確保 glTF 使用相對路徑,或在 GLTFLoader 的 setPath() 設定基礎目錄 |
| 未設定正確的色彩空間 | 亮度過暗或過亮 | renderer.outputEncoding = THREE.sRGBEncoding,同時 texture.encoding = THREE.sRGBEncoding |
| DRACO/KTX2 解碼器路徑錯誤 | 載入失敗、Error: Decoder not found |
使用 CDN 時檢查網址;本機時把解碼器檔案放在公開目錄,並呼叫 setDecoderPath() |
| 動畫播放速度不對 | 動畫過快或過慢 | mixer.timeScale = 0.5(慢速)或 clip.duration 重新計算 |
| 大型模型卡頓 | 首次載入或互動時掉幀 | 使用 LOD(Level of Detail)或 InstancedMesh;在 glTF 中啟用 meshopt 壓縮(需額外 loader) |
| 跨域(CORS)問題 | Failed to load resource |
本機開發時使用 vite、webpack-dev-server 或 http-server;上線時在 CDN 設定正確的 CORS Header |
最佳實踐
- 先在 glTF Viewer 中驗證:確保「模型、材質、動畫」三者皆無錯。
- 版本統一:Three.js、GLTFLoader、DRACOLoader、KTX2Loader 必須使用相同的主版本(例如 0.162.x),避免 API 不匹配。
- 使用
setPath():在程式碼中明確指定模型與貼圖所在的根目錄,降低相對路徑錯誤。 - 開啟
renderer.debug.checkShaderErrors:開發階段可即時捕捉著色器編譯錯誤。 - 自動化測試:如上範例所示,將模型驗證納入 CI,提升團隊品質保證。
實際應用場景
| 場景 | 為什麼需要 glTF Viewer + Three.js 整合 |
|---|---|
| 線上產品展示(家具、汽車) | 需要即時呈現 PBR 材質、環境光照,且模型檔案必須輕量。先在 Viewer 確認貼圖與金屬度、粗糙度正確,再於 Three.js 加入 HDR 環境貼圖。 |
| VR/AR 教育平台 | 動畫與骨架正確是關鍵。使用 Viewer 檢查動畫軌跡、根節點位置,避免在 AR 裝置上出現「模型漂移」的情況。 |
| 遊戲關卡編輯器 | 開發者會持續匯入新模型,透過自動化 gltf-viewer 檢測,確保每個新資產不會破壞關卡載入時間。 |
| 建築資訊模型(BIM)轉換 | 從 Revit、SketchUp 輸出 glTF 前,先在 Viewer 確認座標系統(Y‑up)與比例,確保在 Three.js 中不需要額外的矩陣變換。 |
| 資料視覺化(科學模擬) | 需要在模型上疊加程式生成的點雲或流線,Viewer 能快速驗證基礎模型的法線與 UV 是否正確,減少後續程式錯誤。 |
總結
glTF Viewer 是 Three.js 開發流程中不可或缺的前置工具:它不僅能快速驗證模型完整性,還能在 CI/CD 中自動化檢測,避免因資產問題拖慢開發進度。本文從 Viewer 的選擇、模型驗證要點,到 Three.js 中的載入、壓縮、動畫、貼圖,提供了 5 個實用程式碼範例,並針對常見陷阱給出解決方案與最佳實踐。
掌握了這套 「測試 → 載入 → 調整」 的工作流後,你將能更自信地在任何 Web 3D 專案中使用 glTF,從線上產品展示到複雜的 VR/AR 應用,都能保持高效、穩定與視覺品質。祝你在 Three.js 的旅程中玩得開心、寫得順利!