babylonjs のソフトボディの実装方法は、内蔵の ammojs プラグインを通じて ammo 物理エンジンを呼び出すことです。
scene.enablePhysics(null, new BABYLON.AmmoJSPlugin());
ここでの AmmoJSPlugin は実際には babylonjs に提供されるインターフェースであり、ammo 自体は含まれていないため、ammojs を自分で準備する必要があります。
import Ammo from 'ammojs-typed'
ここでは型定義のある ammojs-typed を使用しています。
次に、推奨される初期化方法を使用します:
Ammo()
.then(() => {
console.log('Ammo.jsが正常に初期化されました。');
})
.catch((err) => {
console.error('Ammo.jsの初期化に失敗しました:', err);
});
結果として、エラーUncaught TypeError: Cannot set properties of undefined (setting 'Ammo')
が得られました。
このエラーは catch で正常に捕捉されず、エラーは直接Ammo()
内で発生しています。
どうやらグローバル変数を設定する際にエラーが発生しているようです。
babylonjs の公式サンプルコードには、ammo のインポートや初期化については言及されていません。
私の推測では、ammo は直接 script でインポートされており、すぐに使用可能なグローバル Ammo を提供しているのだと思います。
babylonjs の物理を有効にするコードでは、
scene.enablePhysics(null, new BABYLON.AmmoJSPlugin());
最初の引数は重力で、指定しない場合はデフォルトの地球重力が使用され、2 番目の引数はプラグインを指定します。
プラグイン呼び出し関数に引数を渡さない場合は、デフォルトのグローバル Ammo が使用されます。
devtool のヒントに基づいて、エラーが ammojs-typed の一行から来ていることが直接確認できます。
this.Ammo = b;
実際、Ammo は初期化時にエクスポートされた API をグローバルオブジェクトに割り当てようとしていることが推測できますが、現在の ES モジュールのトップレベル this は undefined です。
ammojs は emscripten でコンパイルされた bullet 物理エンジンであり、emscripten が生成するグルー js コードは伝統的にエクスポートをグローバルオブジェクトに割り当てます。例えば、this.Ammo = b;
やwindow.Ammo = b;
のように。
しかし、es モジュールではカプセル化と汚染防止のため、トップレベルのスコープは undefined です。
したがって、最終的な解決策は
https://forum.babylonjs.com/t/using-ammojs-with-babylon/26413/18?u=lz_k
から得られました。
const ammo = await Ammo.call({});
scene.enablePhysics(null, new AmmoJSPlugin(true, ammo));
.call
を使用して関数内部の this を新しく渡されたパラメータに手動で指定します。ここでは空のオブジェクトを指定しています。
一時的な空のオブジェクトを使用しても何も影響はありません。私たちは初期化プロセスがエラーを出さないようにするだけでいいのです。なぜなら、Ammo()
が実際に返す Promise には使用可能な Ammo API も含まれているからです。
そして、初期化された ammo インスタンスを babylon の ammojs プラグインに渡すことで、正常に babylon の ammojs プラグインを有効にすることができます。
この小技は、ammojs がグローバル変数への割り当て問題を回避するのに成功しました。
これで、ソフトボディの作成などの操作を正常に行うことができます👻