本文 AI 產出,尚未審核

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 特色 使用情境
官方線上 Viewer
https://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

最佳實踐

  1. 先在 glTF Viewer 中驗證:確保「模型、材質、動畫」三者皆無錯。
  2. 版本統一:Three.js、GLTFLoader、DRACOLoader、KTX2Loader 必須使用相同的主版本(例如 0.162.x),避免 API 不匹配。
  3. 使用 setPath():在程式碼中明確指定模型與貼圖所在的根目錄,降低相對路徑錯誤。
  4. 開啟 renderer.debug.checkShaderErrors:開發階段可即時捕捉著色器編譯錯誤。
  5. 自動化測試:如上範例所示,將模型驗證納入 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 的旅程中玩得開心、寫得順利!