メインコンテンツまでスキップ

MMDモデルに物理を適用

このセクションでは、MMDモデルに物理シミュレーションを適用する方法について説明します。

MMDモデルは物理シミュレーションをサポートしており、物理エンジンを使用してモデルのボーンに物理効果を適用できます。

babylon-mmdは、これを実装するための様々なオプションを提供します。各オプションの特性を確認し、使用シナリオに最も適したものを選択できます。

物理エンジンオプション

babylon-mmdは、MMD物理シミュレーションを処理するために3つの物理エンジンをサポートします:

  • Bullet Physics:MMDで使用される物理エンジン。Rust wasm-bindgenを使用してWebAssemblyにコンパイルされ、babylon-mmdパッケージに含まれています。
  • Ammo.js:Bullet PhysicsのEmscriptenベースのJavaScriptポート。EmscriptenでコンパイルされたWebAssemblyバイナリとして提供されます。
  • Havok Physics:Babylon.jsでサポートされる商用物理エンジン。WebAssemblyバイナリとして提供されます。

MMDモデルに適用した場合の各物理エンジンの特性は以下の通りです:

物理エンジンパフォーマンス安定性ポータビリティ使いやすさ
Bullet Physics★★★★☆ - 最適化されたバインディング★★★★★ - 優秀なMMD動作再現★★★☆☆ - WebAssemblyをサポートする環境でのみ利用可能★★★☆☆ - APIで開発者エクスペリエンスの配慮が相対的に少ない
Ammo.js★★★☆☆ - 自動生成バインディングによるパフォーマンス低下★★★☆☆ - 良好なMMD動作再現、しかし相対的に高いクラッシュ可能性★★★★★ - asm.jsビルドを使用時、WebAssemblyサポートなしの環境でも使用可能★★★★★ - Babylon.jsとの良好な互換性と利便性
Havok Physics★★★★★ - 最適化されたバインディング、より高速なエンジンパフォーマンス★☆☆☆☆ - 悪いMMD動作再現、深刻な数値不安定性★★★☆☆ - WebAssemblyをサポートする環境でのみ利用可能★★★★★ - Babylon.jsとの良好な互換性と利便性

以下、各物理エンジンの初期化方法について説明します。

Bullet Physicsインプリメンテーション

Bullet Physicsエンジンを使用してMMD物理シミュレーションを処理できます。

このBullet Physicsエンジンは、C++からRustへのFFIバインディング後にWebAssemblyにコンパイルされ、babylon-mmdパッケージの一部として含まれています。

Ammo.jsとは完全に独立したバインディングで、優れたパフォーマンスと安定性を提供します。

以下は、Bullet Physicsエンジンを使用してMmdRuntimeを作成するサンプルコードです:

const mmdWasmInstance = await getMmdWasmInstance(new MmdWasmInstanceTypeSPR());
const physicsRuntime = new MultiPhysicsRuntime(mmdWasmInstance);
physicsRuntime.setGravity(new Vector3(0, -9.8 * 10, 0));
physicsRuntime.register(scene);

const mmdRuntime = new MmdRuntime(scene, new MmdBulletPhysics(physicsRuntime));

Bullet Physicsエンジンを使用するには、まずbabylon-mmdが提供するWebAssemblyバイナリをロードする必要があります。これはgetMmdWasmInstance()ファンクションを使用して行うことができます。

ここで、4つのWebAssemblyインスタンスタイプのうち1つを選択できます:

  • MmdWasmInstanceTypeSPRシングルスレッド、フィジックス、リリースビルド
  • MmdWasmInstanceTypeSPDシングルスレッド、フィジックス、デバッグビルド
  • MmdWasmInstanceTypeMPRマルチスレッド、フィジックス、リリースビルド
  • MmdWasmInstanceTypeMPDマルチスレッド、フィジックス、デバッグビルド

マルチスレッドバージョンは**SharedArrayBuffer**をサポートする環境でのみ動作します。環境に応じて適切なバイナリを選択してください。

上記の例では、シングルスレッドリリースビルドを使用しています。

const mmdWasmInstance = await getMmdWasmInstance(new MmdWasmInstanceTypeSPR());

MultiPhysicsRuntimeクラスは、Bullet Physicsエンジンを使用して物理シミュレーションを処理するランタイムクラスです。MultiPhysicsRuntimeのインスタンスを作成した後、重力ベクターを設定し、Sceneアップデートコールバックを登録します。

const physicsRuntime = new MultiPhysicsRuntime(mmdWasmInstance);
physicsRuntime.setGravity(new Vector3(0, -9.8 * 10, 0));
physicsRuntime.register(scene);

MultiPhysicsRuntimeが提供する様々なメソッドを使用して、重力の設定リジッドボディやコンストレイントの直接追加など、物理シミュレーションを制御できます。詳細については、Bullet Physicsドキュメントを参照してください。

備考

MmdWasmRuntimeを使用している場合は、代わりにMmdWasmPhysicsを使用できます。

これは内部的に同じコードを使用しますが、JavaScriptからWASMへのバインディングレイヤーを排除し、優れたパフォーマンスを提供します。

const mmdRuntime = new MmdWasmRuntime(mmdWasmInstance, scene, new MmdWasmPhysics(scene));

const physicsRuntime = mmdRuntime.physics!.getImpl(MmdWasmPhysicsRuntimeImpl);

// MMD WASMランタイムによって作成された物理ワールドの重力は
// デフォルトで(0, -9.8*10, 0)に設定されるため、このコードは省略可能です
physicsRuntime.setGravity(new Vector3(0, -9.8 * 10, 0));

Ammo.jsインプリメンテーション

Ammo.jsは、EmscriptenでコンパイルされたBullet PhysicsエンジンのJavaScriptポートです。これを使用してMMD物理シミュレーションを処理できます。

以下は、Ammo.jsを使用してMmdRuntimeを作成するサンプルコードです:

import ammo from "babylon-mmd/esm/Runtime/Physics/External/ammo.wasm";

const physicsInstance = await ammo();
const physicsPlugin = new MmdAmmoJSPlugin(true, physicsInstance);
scene.enablePhysics(new Vector3(0, -9.8 * 10, 0), physicsPlugin);

const mmdRuntime = new MmdRuntime(scene, new MmdAmmoPhysics(scene));

babylon-mmdパッケージには、EmscriptenでコンパイルされたBullet Physics 3.25バージョンammo.wasmバイナリとして含まれています。これは"babylon-mmd/esm/Runtime/Physics/External/ammo.wasm"パスからインポートできます。

備考

Ammo.jsは特定のデータに対してコンストレイントの不安定性問題があるため、可能であればBullet Physicsエンジンの使用が推奨されます。

Babylon.js PhysicsPluginV1インターフェースを使用してAmmo.js物理エンジンを管理することもできます。詳細については、Babylon.js Physicsドキュメントを参照してください。

Havok Physicsインプリメンテーション

Havok Physicsエンジンを使用してMMD物理シミュレーションを処理できます。

以下は、Havok Physicsエンジンを使用してMmdRuntimeを作成するサンプルコードです:

import havok from "@babylonjs/havok";

const physicsInstance = await havok();
const physicsPlugin = new HavokPlugin(true, physicsInstance);
scene.enablePhysics(new Vector3(0, -9.8 * 10, 0), havokPlugin);

const mmdRuntime = new MmdRuntime(scene, new MmdPhysics(scene));
備考

Havok Physicsエンジンは良好な数値安定性を持たないため、MMD物理シミュレーションには適さない可能性があります。可能であればBullet Physicsエンジンの使用が推奨されます。

Babylon.js PhysicsPluginV2インターフェースを使用してHavok Physicsエンジンを管理することもできます。詳細については、Babylon.js Physics V2ドキュメントを参照してください。

MMDモデルの物理ビルド

上記の物理エンジンのいずれかでMmdRuntimeインスタンスを作成した後、buildPhysicsオプションをtrueに設定してMmdModelインスタンスを作成することで、MMDモデルで物理シミュレーションを有効にできます。

const mmdModel = mmdRuntime.createMmdModel(mmdMesh, {
buildPhysics: true
});

buildPhysicsオプションがtrueに設定されると、MMDランタイムはPMXファイルで定義された物理データに基づいて、MMDモデルのリジッドボディとコンストレイントを自動的に作成します。

物理ビルドオプション

物理を有効にしてMmdModelインスタンスを作成する際、物理シミュレーションをカスタマイズするための追加オプションを渡すことができます。

const mmdModel = mmdRuntime.createMmdModel(mmdMesh, {
buildPhysics: {
worldId: undefined,
kinematicSharedWorldIds: [],
disableOffsetForConstraintFrame: false
}
});

利用可能なオプションは以下の通りです:

  • worldId:物理シミュレーションのカスタムワールドIDを指定できます。指定されない場合、新しいワールドIDが自動的に割り当てられます。
  • kinematicSharedWorldIdsキネマティックオブジェクトを共有するワールドIDの配列を指定できます。これは、複数のMMDモデル間でキネマティックオブジェクトを共有したい場合に便利です。
  • disableOffsetForConstraintFrame:コンストレイントフレームのオフセットを無効にするかどうかを指定できます。モデルのコンストレイントが正しく動作しない場合、このオプションをtrueに設定してみてください。

マルチワールド物理シミュレーション

まず、worldIdkinematicSharedWorldIdsオプションは物理シミュレーションワールドを制御します。これらのオプションはBullet Physicsを物理バックエンドとして使用する場合にのみ有効です。babylon-mmdのBullet Physics APIは、複数の物理ワールドを作成し、マルチスレッドで処理し、ワールド間で同期する機能を提供します。

デフォルトでは、MMDモデルが作成されるたびに、各モデルは独自の独立した物理ワールドを取得します。しかし、worldIdオプションを使用して特定のIDを指定すると、そのIDの物理ワールドが既に存在する場合はそのワールドを再利用します。これにより、複数のMMDモデルが同じ物理ワールドを共有できます。

さらに、異なるワールド間でキネマティックオブジェクトを共有したい場合は、kinematicSharedWorldIdsオプションを使用して共有するワールドIDのリストを指定できます。このオプションにより、異なるワールドに属するMMDモデルのキネマティックボディが、それぞれのワールドで相互作用できるようになります。

コンストレイント動作の修正

disableOffsetForConstraintFrameオプションは、MMDモデルのコンストレイントが正しく動作しない場合に使用されます。デフォルトでは、このオプションはfalseに設定されています。

MMDはBullet Physics バージョン2.75を使用して物理シミュレーションを処理します。しかし、新しいBullet Physics バージョン3.25では、コンストレイントの動作が変更されており、一部のMMDモデルでコンストレイントが正しく動作しない問題が発生する可能性があります。

このオプションをtrueに設定すると、コンストレイントソルバーがバージョン2.75と同じ方法で動作し、これらの問題を解決できます。MMDモデルのコンストレイントが期待通りに動作しない場合は、このオプションをtrueに設定してみてください。

ただし、古いコンストレイントソルバーはより深刻な数値不安定性を持つ傾向があることに注意してください。