mcpField
T
threejs-gltf-loading

threejs-gltf-loading

github.com/gamedev-skills開発5.4k6.3k 回インストール今日更新
リポジトリ

threejs-gltf-loading について

three.js に glTF・GLB モデルを組み込む開発者向けのスキルです。ノード階層の確認、アニメーション再生、圧縮ジオメトリやテクスチャのデコードを扱います。

主な機能

  1. 01glTF・GLB モデルの読み込み
  2. 02モデルのノード階層の確認
  3. 03アニメーションクリップの再生とブレンド
  4. 04DRACO・KTX2 アセットのデコード
  5. 05変更した glTF ファイルの検証

活用シーン

  1. 01three.js シーンへの 3D モデルの読み込み
  2. 02スキン付きキャラクターのアニメーション再生
  3. 03名前付きモデルパーツの検索と制御

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/gamedev-skills/awesome-gamedev-agent-skills --skill threejs-gltf-loading

インストール後、Claude Code で/threejs-gltf-loadingを入力して読み込まれたか確認します。

同梱ファイルreferences/loaders-and-animation.md

詳細

three.js glTF の読み込み

.gltf/.glb モデルを読み込み、three.js でアニメーションを再生します。圧縮ジオメトリ(DRACO/Meshopt)とテクスチャ(KTX2)にも対応しています。パターンは r186 を対象としています。移行を求められていない限り、既存プロジェクトで固定されているリリースを維持してください。

使用する場面

  • 3D モデルをインポートしてシーンに追加し、ノード階層を調べ、AnimationMixer でベイク済みアニメーションクリップやスキニングアニメーションを再生する場合に使用します。
  • ファイルが .gltf/.glb の場合や、コードが three/addons/loaders/... から GLTFLoader/DRACOLoader/KTX2Loader をインポートしている場合に使用します。

使用しない場面: レンダラー/カメラ/ループの作成 → threejs-scene-setup。読み込んだモデルの表面の見た目、ライト、影の調整 → threejs-materials-lighting。モデル自体の作成/エクスポート(Blender)は対象外です。実行時には OBJ/FBX より glTF を優先してください。

基本的なワークフロー

  1. glTF を選ぶ理由。 glTF は伝送用フォーマットです。バイナリの頂点データ、PBR マテリアル、アニメーションが、最小限の解析で描画できる状態になっています。Web では、シーングラフやアニメーションのない OBJ や、重い FBX より glTF を優先してください。
  2. GLTFLoader で読み込む。 loader.load(url, onLoad, onProgress, onError) を呼び出します。結果の gltf には、gltf.scene(Object3D のルート)、gltf.animations(AnimationClip[])、gltf.cameras、gltf.asset が含まれます。
  3. gltf.scene をシーンに追加し、フレームに収めます。 traverse/getObjectByName で階層を調べ、操作するパーツを見つけます。
  4. AnimationMixer でアニメーションを再生する。 アニメーション対象のルートごとにミキサーを1つ作成します。mixer.clipAction(clip).play() を呼び出し、毎フレーム mixer.update(delta) で更新します。
  5. 圧縮アセットをデコードする。 DRACOLoader(および/または KTX2Loader と Meshopt)をアタッチして、DRACO メッシュと KTX2 テクスチャを読み込めるようにします。デコーダーのファイルを指定してください。
  6. プロジェクトにツールがすでにある場合は、変更した glTF ファイルを検証します。 変更した .gltf または .glb ごとに gltf-transform validate path/to/model.glb を実行し、報告されたエラーを修正してから読み込みます。
  7. 読み込まれた内容を確認する。 シーングラフと gltf.animations をログに出力し、モデルが表示されること(適切なスケールで、ライティングされていること)と、クリップが実際に再生されることを確認します。

パターン

1. モデルを読み込んでフレームに収める
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';

const loader = new GLTFLoader();
loader.load(
  'assets/robot.glb',
  (gltf) => {
    const root = gltf.scene;
    scene.add(root);
    // Inspect: gltf.animations is an array of AnimationClip.
    console.log('clips:', gltf.animations.map((c) => c.name));
  },
  (event) => console.log(`${(event.loaded / event.total) * 100}% loaded`),
  (error) => console.error('glTF load failed:', error)
);
2. AnimationMixer でスキニングアニメーションを再生する
import * as THREE from 'three';
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';

let mixer;                                  // declare outside so the loop can see it
const timer = new THREE.Timer();            // THREE.Clock is deprecated since r183

new GLTFLoader().load('assets/character.glb', (gltf) => {
  scene.add(gltf.scene);
  mixer = new THREE.AnimationMixer(gltf.scene);          // one mixer per animated root
  const clip = THREE.AnimationClip.findByName(gltf.animations, 'Run')
            ?? gltf.animations[0];
  mixer.clipAction(clip).play();
});

renderer.setAnimationLoop((time) => {
  timer.update(time);
  const dt = timer.getDelta();
  if (mixer) mixer.update(dt);              // advance the animation by real seconds
  renderer.render(scene, camera);
});
3. 2つのクリップをクロスフェードする
const actions = {};
mixer = new THREE.AnimationMixer(gltf.scene);
for (const clip of gltf.animations) {
  actions[clip.name] = mixer.clipAction(clip);
}
actions['Idle'].play();

function transitionTo(name, duration = 0.3) {
  const next = actions[name];
  next.reset().play();
  for (const [n, action] of Object.entries(actions)) {
    if (n !== name) action.crossFadeTo(next, duration, false);
  }
}
4. DRACO 圧縮ジオメトリ
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
import { DRACOLoader } from 'three/addons/loaders/DRACOLoader.js';

const draco = new DRACOLoader();
// Point at the decoder files you ship (or a pinned CDN copy of the same version).
draco.setDecoderPath('https://cdn.jsdelivr.net/npm/[email protected]/examples/jsm/libs/draco/');

const loader = new GLTFLoader();
loader.setDRACOLoader(draco);
loader.load('assets/city-draco.glb', (gltf) => scene.add(gltf.scene));
5. 名前付きパーツを探してアニメーションさせる
new GLTFLoader().load('assets/car.glb', (gltf) => {
  scene.add(gltf.scene);
  const wheels = [];
  gltf.scene.traverse((node) => {
    if (node.name.startsWith('Wheel')) wheels.push(node);
  });
  renderer.setAnimationLoop((time) => {
    timer.update(time);
    const dt = timer.getDelta();
    for (const w of wheels) w.rotation.x += dt * 4;
    renderer.render(scene, camera);
  });
});

注意点

  • モデルは読み込まれるが表示されない → ライティングが必要な(PBR)マテリアルを使用している一方で、シーンにライトも環境もありません。ライトまたは scene.environment を追加し(threejs-materials-lighting を参照)、スケールも確認してください。glTF の単位はメートルなので、スケールが 0.01 のアセットは非常に小さくなります。
  • load は非同期です → gltf が使えるのはコールバック内だけです。mixer/参照を外側で宣言し、コールバック内で代入するか、await loader.loadAsync(url) を使用してください。
  • アニメーションが動かない → 毎フレーム mixer.update(delta) を呼び出していないか、ミリ秒を秒として渡している可能性があります(timer.update(time) の後に timer.getDelta() を使用してください)。または、action.play() を忘れています。
  • DRACO/KTX2 モデルの読み込みに失敗する → デコーダー/トランスコーダーのパスが間違っているか、バージョンが一致していません。setDecoderPath/setTranscoderPath は、three.js のバージョンに対応したファイルを指す必要があります。
  • 複数のミキサーが競合する → アニメーション対象のルートごとに AnimationMixer を1つだけ使用し、すべてのアクションをそこから作成してください。クリップごとに新しいミキサーを作成しないでください。
  • ベイク済みトランスフォームに注意する → エクスポーターによっては、スケール/回転が子ノードにベイクされることがあります。ノードのローカルトランスフォームを前提にする前に、階層(名前+位置/回転/スケール)を出力してください。リグが使えない場合は、ソースから再エクスポートしてください。
  • 原点がずれている → ベイクされたオフセットを調整するのではなく、パーツを新しい Object3D の下に再配置して、適切なピボットを設定してください。

参考資料

  • DRACO、Meshopt、KTX2 を組み合わせた完全なデコード/トランスコードのセットアップ、LoadingManager のプログレスバーを使った loadAsync、SkeletonUtils.clone によるモデルの再利用、エクスポーターに関するガイダンス(トランスフォームを適用する、クリーンなルートを 1 つにする)については、 references/loaders-and-animation.md を参照してください。

関連スキル

  • threejs-scene-setup — このモデルを描画するレンダラー、カメラ、ループです。
  • threejs-materials-lighting — PBR モデルを適切に見せるためのライティング/環境です。
  • fps-shooter — three.js のスキルを組み合わせた 3D ジャンルです。

コメント