The way to implement soft body in Babylon.js is by calling the Ammo physics engine through its built-in AmmoJS plugin.
The AmmoJSPlugin here is actually an interface provided to Babylon.js and does not include Ammo itself, so you also need to prepare Ammo.js on your own.
Here, the version with type definitions, ammojs-typed, is used.
Then use its recommended initialization method:
The result is an error Uncaught TypeError: Cannot set properties of undefined (setting 'Ammo')
.
It is important to note that this error was not caught properly; the error occurred directly in Ammo()
.
It seems to have gone wrong while setting the global variable.
In the official Babylon.js example code, there is no mention of importing or initializing Ammo.
I suspect that Ammo is directly imported via script, providing a usable global Ammo.
In the Babylon.js physics enabling code:
The first parameter is gravity; if not specified, the default Earth gravity is used. The second parameter specifies the plugin.
When no parameters are passed to the plugin call function, the default global Ammo is used.
According to the devtool's prompt, you can directly see that the error originates from a line in ammojs-typed:
this.Ammo = b;
It can be guessed that Ammo tries to assign the exported API to the global object during initialization, but the current top-level this
in ES modules is undefined.
Ammo.js is a Bullet physics engine compiled with Emscripten, and the glue JS code generated by Emscripten traditionally assigns exports to the global object, similar to this.Ammo = b;
or window.Ammo = b;
.
However, in ES modules, due to encapsulation and pollution prevention, the top-level scope is undefined.
So the final solution comes from:
https://forum.babylonjs.com/t/using-ammojs-with-babylon/26413/18?u=lz_k
Using .call
to manually specify the this
inside the function to a newly passed parameter, here specified as an empty object.
Using a temporary empty object does not affect anything; we just need to ensure that the initialization process does not error out because the Promise returned by Ammo()
will also contain the usable Ammo API.
Then, passing the initialized ammo instance to Babylon's AmmoJS plugin will allow the Babylon AmmoJS plugin to be enabled normally.
This little trick successfully bypassed the issue of Ammo.js trying to assign to the global variable.
Next, you can proceed with creating soft bodies and other operations normally.👻