Ammo.js: Help with setup/import errors

Hi there.

I am trying to use three.js to write a program in which I can import a model file (likely .obj), turn it into a cloth/softbody and interact with it using my mouse (for example to pull at the cloth).

I have used the obj-importer and THREE.x successfully so far. Now I would like to turn the .obj into a softbody using ammo.js for the physics part. However, I am having trouble with the initialization: I either get a TypeError for my first instance calling on Ammo

Ammo.btSoftBodyRigidBodyCollisionConfiguration is a undefined
TypeError: Ammo.btSoftBodyRigidBodyCollisionConfiguration is not a constructor

or, when I try to initialize ammo.js in an asynchronous way using

Ammo().then((lib) => {
    Ammo = lib;
    init()
  });

the ouput is

Ammo: object
TypeError: Ammo is not a function

I have downloaded ammo.js using

npm install github:kripken/ammo.js

and I use vite for the localhost.

I feel like I’m missing something, but I’ve looked at example codes and searched around both the forum and stackoverflow and not really found a solution. Any help would be greatly appreciated.

I use the following code:

index.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Ammo.js Softbody-OBJ</title>
    <link rel="icon" href="images/favicon.ico" type="image/x-icon">
    <style>
        body { margin: 0; }
        canvas { display: block; }
    </style>
</head>
<body>
    <script type="module" src="./node_modules/ammo.js/builds/ammo.wasm.js"></script>
    <script type="module" src="./src/main.js"></script>
</body>
</html>

main.js:

import * as THREE from 'three';
import * as Ammo from '../node_modules/ammo.js/builds/ammo.wasm.js';

let scene, camera, renderer, controls, softBody, dynamicsWorld, softBodyMesh;

Ammo().then((lib) => {
    Ammo = lib;
    init()
  });

async function init() {
    //THREE.scene setup

// Set up Ammo.js physics
    console.log('Ammo.btSoftBodyRigidBodyCollisionConfiguration is a ', Ammo.btSoftBodyRigidBodyCollisionConfiguration);
    var collisionConfiguration = new Ammo.btSoftBodyRigidBodyCollisionConfiguration();
    var dispatcher = new Ammo.btCollisionDispatcher(collisionConfiguration);
    var broadphase = new Ammo.btDbvtBroadphase();
    var solver = new Ammo.btSequentialImpulsevarraintSolver();
    var softBodySolver = new Ammo.btDefaultSoftBodySolver();

...
}

Wats “btSequentialImpulsevarraintSolver” ? that looks like a typo…
r.e. how to load it etc. Can you use the setup from one of the examples like:

https://threejs.org/examples/?q=amm#physics_ammo_volume

(code: three.js/examples/physics_ammo_volume.html at 134ff886792734a75c0a9b30aa816d19270f8526 · mrdoob/three.js · GitHub )

you can use ammo as module inporter too, in ammo.js:
change first line ‘var Ammo’ to ‘var AmmoLoader’
on ending lines comment ‘//this[“Ammo”]=Module;’
and change the exporter type

  export { AmmoLoader }
  /*if (typeof exports === 'object' && typeof module === 'object')
    module.exports = Ammo;
  else if (typeof define === 'function' && define['amd'])
    define([], function() { return Ammo; });
  else if (typeof exports === 'object')
    exports["Ammo"] = Ammo;
  */

now in your project use:

import { AmmoLoader } from "./ammo.js"
async createAmmo() { //modified initialization
        window.Ammo = await AmmoLoader();
        while (typeof Ammo.ready === 'undefined') {
            await new Promise(resolve => setTimeout(resolve, 100));
        }
        this._initialize();
        return this;
    }

here as working one with Ammo.btSoftBodyRigidBodyCollisionConfiguration
didisoftwares.ddns.net/7

1 Like

you’re right, btSequentialImpulsevarraintSolver was a typo for btSequentialImpulseConstraintSolver.

I had tried importing like in the examples, but the importmap in the .html-file didn’t seem to work for me. However, I have since combined the importmap style with the createAmmo() function that @didi_softwares suggested, and at least I get a different error now, further down in my world setup!

1 Like

thanks for the help! the AmmoLoader approach got me the same ‘not a function’ error initially, but I combined it with an importmap style import in the html file and the following edits, it seems to work for now.

import * as THREE from 'three';
// delete "import * as Ammo from '../node_modules/ammo.js/builds/ammo.wasm'"
import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader.js';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';

createAmmo();

async function createAmmo() {
    window.Ammo = await Ammo();
    while (typeof Ammo.ready === 'undefined') {
        await new Promise(resolve => setTimeout(resolve, 100));
    }
    init()
}

async function init() {...}

edit: this is the html edits:

<body>
    <script> type='importmap'> {
            'imports': {
                'three': 'C:/Users/320254491/Documents/node_modules/three/build/three.module.js',
                'three/addons/': './node_modules/'
            }
    }</script>
    <script src="./node_modules/ammo.js/builds/ammo.wasm.js"></script>
    <script type="module" src="./src/main.js"></script>
</body>

strange, modules supposedly can’t be loaded with the file path, only with URLs and blobs
‘C:/Users/320254491/’ on importmap target a file path
you need a webserver