本文 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 中驗證,仍需要在程式碼裡正確設定 GLTFLoaderDRACOLoaderKTX2Loader,以下範例逐步說明。

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 使用相對路徑,或在 GLTFLoadersetPath() 設定基礎目錄
未設定正確的色彩空間 亮度過暗或過亮 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 本機開發時使用 vitewebpack-dev-serverhttp-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 ViewerThree.js 開發流程中不可或缺的前置工具:它不僅能快速驗證模型完整性,還能在 CI/CD 中自動化檢測,避免因資產問題拖慢開發進度。本文從 Viewer 的選擇、模型驗證要點,到 Three.js 中的載入、壓縮、動畫、貼圖,提供了 5 個實用程式碼範例,並針對常見陷阱給出解決方案與最佳實踐。

掌握了這套 「測試 → 載入 → 調整」 的工作流後,你將能更自信地在任何 Web 3D 專案中使用 glTF,從線上產品展示到複雜的 VR/AR 應用,都能保持高效、穩定與視覺品質。祝你在 Three.js 的旅程中玩得開心、寫得順利!