InstancedGltfModelMeshDesc
InstancedGltfModelMeshDesc クラスは、単一の GLTF/GLB モデルを読み込み、その複数の変換済みコピー(インスタンス)をレンダリングするメッシュです。GLTF を一度だけ読み込み、各 Mesh ノードを兄弟の InstancedMesh に展開して、モデルインスタンスごとに 1 つのインスタンス行列スロットを共有します。
以下のプロパティに加えて、基底クラスの共通プロパティ(position、rotation、scale、matrix、matrixWorld、geodetic、visible)が利用できます。詳細は MeshDesc を参照してください。
GLTF の内容に基づき、2 つの内部レンダリングパスのいずれかが自動的に選択されます:
- 非スキンドパス(インスタンス化): 各
MeshノードがInstancedMeshになります。すべてのインスタンスはソースシーン上で動作する 1 つのAnimationMixerを共有し、毎フレーム各ソースメッシュのmatrixWorldを再サンプリングして、各インスタンスの行列をT_i * sourceLocal_sとして書き換えます。Node-TRS およびモーフターゲットアニメーションはどちらも正しく再生されます。 - スキンドパス(インスタンスごとのクローンフォールバック): three.js の
InstancedMeshはスキニングを適用できないため、スキンド GLTF はインスタンスごとにSkeletonUtils.cloneでフォールバックされ、それぞれが独自のAnimationMixerを持ちます。スキン部分のインスタンス化レンダリングは犠牲になりますが、同じ desc API を維持し、クローン間で共有クリップを同期して再生します。
メッシュは Relative-To-Eye (RTE) 精度を使用するため、浮動小数点精度の問題なく地球上のどこにでもアンカリングできます。
ピッキングは非スキンドパスでのみサポートされます。スキンドパスでは batchIds は空になります。
共有プロパティ (InstancedModelsDescription)
Section titled “共有プロパティ (InstancedModelsDescription)”gltfModels 設定オブジェクト内で指定します。
Type: string
Description: 読み込む GLTF/GLB モデルの URL。
Example:
{ gltfModels: { url: "/models/tree.glb", }}castShadow
Section titled “castShadow”Type: boolean
Description: インスタンスが影を落とすかどうかを指定します。
Default: false
receiveShadow
Section titled “receiveShadow”Type: boolean
Description: インスタンスが影を受けるかどうかを指定します。
Default: false
animationActiveClip
Section titled “animationActiveClip”Type: string (optional)
Description: 再生するアニメーションクリップ名を指定します。クリップはすべてのインスタンス間で共有されます。利用可能なクリップ一覧はモデル読み込み後に handle.ref.animationClips から取得できます。
animationSpeed
Section titled “animationSpeed”Type: number
Description: アニメーション再生速度の倍率。すべてのインスタンス間で共有されます。
Default: 1
animationLoop
Section titled “animationLoop”Type: boolean
Description: アクティブなアニメーションクリップをループ再生するかどうかを指定します。
Default: true
animationAutoPlay
Section titled “animationAutoPlay”Type: boolean
Description: 読み込み完了時に設定済みのクリップを自動再生するかどうかを指定します。
Default: false
インスタンスごとのプロパティ (ModelChildConfig)
Section titled “インスタンスごとのプロパティ (ModelChildConfig)”各モデルインスタンスのプロパティを children 配列内で指定します。変換はそのインスタンスのすべてのサブメッシュに適用されます。
position
Section titled “position”Type: { x: number, y: number, z: number } | undefined
Description: 親グループに対するローカル位置を指定します。
Default: { x: 0, y: 0, z: 0 }
rotation
Section titled “rotation”Type: { x: number, y: number, z: number } | undefined
Description: ローカル回転(オイラー角、ラジアン)を指定します。
Default: undefined
Type: { x: number, y: number, z: number } | undefined
Description: ローカルスケールを指定します。
Default: { x: 1, y: 1, z: 1 }
matrix
Section titled “matrix”Type: Matrix4 | undefined
Description: 事前計算された変換行列を指定します。設定時は position、rotation、scale は無視されます。
Default: undefined
Config
Section titled “Config”pickable
Section titled “pickable”Type: boolean (optional)
Description: 個々のインスタンスのピッキングを有効にします。非スキンドパスでのみ有効です。
Default: false
handle.ref.on(event, handler) で購読します。
Description: GLTF の読み込みが完了し、インスタンスが初期化されたときに発火します。
Handler Type:
() => voidDescription: GLTF の読み込みに失敗したときに発火します。
Handler Type:
(error: unknown) => voidneedsUpdate
Section titled “needsUpdate”Description: descriptor のインスタンス状態が変化(追加・削除・更新・置換・クリア)したときに発火します。
Handler Type:
() => voidインスタンス管理
Section titled “インスタンス管理”handle.ref.add(config)
Section titled “handle.ref.add(config)”新しいインスタンスを追加し、そのインデックスを返します。非スキンドパスでは容量は自動的に拡張されます。
const index = handle.ref.add({ position: { x: 100, y: 0, z: 0 }, scale: { x: 2, y: 2, z: 2 },});handle.ref.removeAt(index)
Section titled “handle.ref.removeAt(index)”指定インデックスのインスタンスを削除します。swap-with-last による O(1) 削除のため、順序は保持されません。
handle.ref.updateAt(index, config)
Section titled “handle.ref.updateAt(index, config)”指定インデックスのインスタンスを部分更新します。未指定のフィールドは保持されます。
handle.ref.updateAt(0, { position: { x: 50, y: 0, z: 0 },});handle.ref.clear()
Section titled “handle.ref.clear()”すべてのインスタンスを削除します。
handle.ref.replaceAll(configs)
Section titled “handle.ref.replaceAll(configs)”全インスタンスをバッチ置換します。clear() と複数回の add() よりも効率的です。
handle.ref.count
Section titled “handle.ref.count”アクティブなインスタンス数を取得します。
handle.ref.animationClips
Section titled “handle.ref.animationClips”読み込まれた GLTF に含まれるアニメーションクリップ名の読み取り専用リスト。load イベント発火までは空です。
handle.ref.on("load", () => { console.log("Available clips:", handle.ref.animationClips);});handle.ref.playAnimation(name)
Section titled “handle.ref.playAnimation(name)”指定名のアニメーションクリップをすべてのインスタンスで再生します。非スキンドパスでは全インスタンスが単一のミキサーから同期再生され、スキンドパスでは各クローンが同じクリップの独自コピーを再生します。
handle.ref.playAnimation("Fly");handle.ref.stopAnimation()
Section titled “handle.ref.stopAnimation()”すべてのインスタンスで現在再生中のアニメーションを停止します。
基本的な使い方
Section titled “基本的な使い方”import ThreeView from "@navaramap/three";import { InstancedGltfModelMeshDesc } from "@navaramap/three-default-descs";
const view = new ThreeView();view.registerMesh("gltfModels", InstancedGltfModelMeshDesc);await view.init();
const handle = view.addMesh<InstancedGltfModelMeshDesc>({ gltfModels: { url: "/models/tree.glb", castShadow: true, children: [ { position: { x: 0, y: 0, z: 0 } }, { position: { x: 50, y: 0, z: 0 }, scale: { x: 1.5, y: 1.5, z: 1.5 } }, { position: { x: 100, y: 0, z: 0 }, rotation: { x: 0, y: Math.PI / 4, z: 0 } }, ], }, position: { x: 0, y: 0, z: 6378137 },});アニメーション付きスキンドモデル
Section titled “アニメーション付きスキンドモデル”const handle = view.addMesh<InstancedGltfModelMeshDesc>({ gltfModels: { url: "/glTF/animated_bird_pigeon/scene.gltf", animationActiveClip: "Fly", animationSpeed: 1.5, animationLoop: true, animationAutoPlay: true, children: [ { position: { x: 0, y: 0, z: 0 } }, { position: { x: 20, y: 0, z: 0 } }, { position: { x: 40, y: 0, z: 0 } }, ], }, position: { x: 0, y: 0, z: 6378137 },});
handle.ref.on("load", () => { console.log("Clips:", handle.ref.animationClips);});アニメーションの動的制御
Section titled “アニメーションの動的制御”// 実行時にクリップを切り替えhandle.ref.playAnimation("Walk");
// すべてのアニメーションを停止handle.ref.stopAnimation();
// アニメーション再生中に新規インスタンスを追加handle.ref.add({ position: { x: 60, y: 0, z: 0 } });