Using AmmoJS with Babylon

Oh wow thanks! It works! :smiley:

2 Likes

I’ve tried both const ammo = await Ammo(); and const ammo = await Ammo.call(this); directly inside an async function that runs my entire BabylonJS app, and I keep getting an Uncaught (in promise) TypeError: this is undefined message in my console. I even tried this as specified in the README for ammojs-typed:

const App = async function() {
    // ...

    await Ammo(Ammo).then(() => {
        scene01.enablePhysics(new Vector3(0, -9.81, 0), new AmmoJSPlugin(true, this));
    });

    // ...
}
App();

Still the same error. How do I call ammojs-typed in TypeScript for my case? I’m also using Vite

thats kind of an incomplete example, but arrow functions do not have a “this” context, which you may not be expecting? also await Ammo(Ammo) is wrong. If anything, it’d be
await Ammo().then((ammo) => { ammo maybe available here } . Idk if the ammo module returns itself, but either way, you’re probably better off just assigning ammo to the window instead of expecting it to be in the return value of the promise.

so like:
async funciton App() {

window.Ammo = await Ammo()

scene01.enablePhysics(new Vector3(0, -9.81, 0), new AmmoJSPlugin(true, window.Ammo));

}

@wavetro a repro could help @RaananW to do his magic a lot

@jeremy-coleman You’re right, I should probably provide more context.

@sebavan @RaananW You got it!

Here’s a copy of my dev environment: debug/houseDev at main · wavetro/debug · GitHub

Oh, I just posted a quick code snippet in the tutorial section on this topic. Getting ammo setup with webpack - #3 by bigrig

1 Like

@bigrig Legendary timing! Will look into how to apply this same method in Vite

UPDATE: This Webpack solution doesn’t seem to be as plug-and-play with Vite. I tried porting that Webpack method into a vite.config.js file like this, even after running npm install on kripken/ammo.js and fs:

export default {
    resolve: {
      alias: {
        fs: false,
        'path': false,
      },
    },
  }

Doesn’t seem to work…

change your index.html to:

<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>houseDev</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="./style.css">
  </head>
  <body>
    <script src="https://preview.babylonjs.com/ammo.js"></script>
    <script type="module" src="./src/app.ts"></script>
  </body>
</html>

then in app.ts

//you can can remove this
//import “ammojs-typed”;

window.Ammo = await Ammo()
scene01.enablePhysics(new Vector3(0, -9.81, 0), new AmmoJSPlugin(true));

(no errors)

maybe eventually you want to find a wasm copy of ammo and use that, but thats fine for now

1 Like

This is an emscripten issue that I hope they will resolve.
Short explanation - when running as es module, you don’t have the global context (when running functions in a module. i.e. - this is undefined). hence - it is not possible to assign anything to the global namespace. but emscripten is still trying to do it. and it fails.

fun fun fun!

The solution is simple! :slight_smile:

First import ammo:

import ammo from 'ammojs-typed';

then, in your scene init function use this:

const ImportedAmmo = await ammo.call({});
scene01.enablePhysics(new Vector3(0, -9.81, 0), new AmmoJSPlugin(true, ImportedAmmo));

Setting the context in which the ammo function is called is enough. And - it works:

Avoid polluting the global namespace, avoid importing using different mechanisms. Stick with vite and es modules - this is a wonderful way to get your app performing wonderfully, loading fast, and compiling even faster :slight_smile:

1 Like

It will actually load faster and compile faster by using the script tag. It will load faster because it will be parsed in a different thread by chrome and compile faster because it wont be compiled at all. Doesnt really matter tho i guess.

1 Like

Not sure what you mean exactly with

but i am not going to argue :slight_smile:
My very personal opinion is that if your system works one way, and your build system works one way, and the framework you have decided to use works one way, use this way.
I also will not use someone else’s CDN when serving production code, because then you trust a system you don’t control. But that’s a different issue.

Anyhow - there are 100 different ways to solve this. I can only provide my 2 cents, and the way I personally think will be the cleanest.

1 Like

I just mean if you import ammo or ammo typed from node_modules, it’ll get parsed in the build process. If you do it as a separate tag , the build tool wont see it at all

1 Like

This is why I don’t get loading Babylon via es6 imports. Especially if you’re using 70 -80% of the modules where tree shaking has limited value. It slows load down by 20 seconds or so versus a script import b/c it’s loading a giant bundle versus multi-threading load. Is the proper technique to break up the build into smaller vendor files? But even so, it then slows down the build process. For something like ammo that doesn’t get updated, i can’t imagine it making much sense to include in the build. Anyway, bit of a ramble, but webpack drives me up the wall.

that’s not webpack. this is vite :slight_smile:
Try it, you won’t regret it.
And webpack SHOULD cache this and not rebuild it when running the dev server.

Anyhow - this is just a suggestion. Make up your mind after making a clear decision based on your use case.

Eventually there will not be any need for a build process. You will just host modules and import them when needed. We are “half way there”, IMO.

Also, babylon mutates prototypes, which causes v8 to recompile every instance of that object every time the prototype changes. If you do it all up front it’ll feel less janky. Idk for sure but i suspect this is a pretty big roadblock to individual imports ever being faster for bjs. You can still do individual imports into kind of a app specific bundle of bjs, that definitely helps

A totally different subject/thread TBH, but this is an issue that will be addressed soon. I actually think we discussed it already.
Anyhow - if you want to continue this - open a new thread. Let’s let the OP have an answer without the extra overhead.

Hai hai

@jeremy-coleman @RaananW Thank you for the great suggestions! I’ll try both of them out

Though I am leaning a bit towards the ES6 module solution with ammojs-typed because i want to prioritize loading speed over a network over anything else, meaning sending as little data to the user as possible, even if it means crowding a single thread just to shave 20% of the entire JS that makes up Ammo.

I would like to assume that the target user of Babylon apps already has a somewhat decent processor to load and display a WebGL scene, but a good internet connection is not as guaranteed

1 Like