ammo.js icon indicating copy to clipboard operation
ammo.js copied to clipboard

ES6 modules in ammo.js

Open sasha240100 opened this issue 9 years ago • 24 comments

I know it sounds a bit stupid and it's more emscripten-related rather than to Ammo.js, but:

  • Is it possible to port Bullet Physics with keeping classes as modules?
  • If it is possible: will it keep being asm.js?

I personally would like to have it modular as i have a framework that uses it and usage of Vehicles, Softbodies, etc. could be depending on if developer needs it.

sasha240100 avatar Oct 17 '16 12:10 sasha240100

What do you mean by modules here? ES6 modules?

kripken avatar Oct 17 '16 17:10 kripken

@kripken Yes. Is it possible to compile it as separate files?

sasha240100 avatar Oct 17 '16 19:10 sasha240100

@kripken Because current build is about 2-3Mb.

sasha240100 avatar Oct 18 '16 07:10 sasha240100

We don't have ES6 module support in that way. It would need to share the heap and other stuff, for example - not sure how would be best.

But if it's build size that concerns you, you can edit the idl file and remove things you don't need, and make a custom build with only the parts you want.

kripken avatar Oct 18 '16 17:10 kripken

@kripken Yes, i know that. (I even have my own build already). The reason of why i am asking is that i am writing a 3D framework and i want to let users choose parts of physics that they need or not(that will be included in result app), so only imported parts of framework will be used by webpack(or not webpack) in their apps.

Anyway, thanks for reply!

sasha240100 avatar Oct 18 '16 18:10 sasha240100

Oh, I see - nice! Yeah, if this modularity were possible after building, it would be great. Perhaps eventually we can do it with wasm modules.

kripken avatar Oct 18 '16 23:10 kripken

@kripken I see that wasm has modules. Another question is when it will be implemented or what should i start with (if you want to me discover this topic)?

sasha240100 avatar Oct 19 '16 20:10 sasha240100

Emscripten doesn't yet support dynamic linking of wasm modules. It might over the next few months. But even so, it would do it using c++ or dlopen style linking, and it might be possible to do something more efficient for your purposes here by using wasm modules directly from JS somehow. So it might be interesting to experiment with that if you want.

kripken avatar Oct 19 '16 22:10 kripken

@kripken WebAssembly is now in Browser Preview: http://webassembly.org/roadmap/ so it's time to talk about this topic more. By the way, i ported Bullet3 to WhitestormJS / AmmoNext You can check these examples running AmmoNext physics.

sasha240100 avatar Nov 09 '16 15:11 sasha240100

It's in preview, but no dynamic linking in the toolchain yet. Hopefully soon though.

Nice about Bullet3. I don't follow Bullet development these days, is 3 a big change over 2?

Your demos don't work for me though, I just see a flat plane but no objects.

kripken avatar Nov 09 '16 23:11 kripken

@kripken Did you open demos with safari?

sasha240100 avatar Nov 09 '16 23:11 sasha240100

@kripken if so - remove "#" from url. For example "https://whs-dev.surge.sh/examples/#basic/helloworld" will become "https://whs-dev.surge.sh/examples/basic/helloworld"

sasha240100 avatar Nov 09 '16 23:11 sasha240100

@kripken They made it more stable (I noticed that my example with 320 sticks became smooth and without lags after porting Bullet3)

sasha240100 avatar Nov 09 '16 23:11 sasha240100

No, I'm on Firefox.

I tried again. Looks like the console shows an asm.js error, which makes it very slow. Waiting a while, I do see objects fall down, so I think that was the issue (noticeable here as I am now on a quite slow machine).

With what version of emscripten was that compiled?

kripken avatar Nov 11 '16 17:11 kripken

@kripken seems like tratata.36.13 (or something like that)

sasha240100 avatar Nov 11 '16 18:11 sasha240100

@kripken How can i solve that error?

sasha240100 avatar Nov 11 '16 18:11 sasha240100

@kripken See https://github.com/WhitestormJS/whitestorm.js - this projects. All examples are from here. It uses AmmoNext

sasha240100 avatar Nov 11 '16 18:11 sasha240100

If it's on 1.36.13, then this is likely a bug in emscripten. Maybe you can point me to the build instructions for that file, and I'll try it?

kripken avatar Nov 11 '16 19:11 kripken

@kripken May I contact you in real-time chat somewhere? You can find me in discord in this chat: https://discordapp.com/invite/frNetGE

sasha240100 avatar Nov 11 '16 19:11 sasha240100

I'm usually on the emscripten irc channel (as azakai).

kripken avatar Nov 14 '16 18:11 kripken

@kripken I can't catch you online there. P.s.: I will play with making wasm builds this time

sasha240100 avatar Nov 20 '16 19:11 sasha240100

Hello, guys) What about ammo.js es6 modules? 4 years gone)

tokarev-i-v avatar Dec 21 '20 01:12 tokarev-i-v

For those who came to this thread to enable Ammo as an ES module. Here is the solution: https://discourse.threejs.org/t/how-to-convert-ammo-js-to-es6-module/30633/4

But later I had this problem: Three.js and Ammo-ES. Error: ammo-es.js:37 Uncaught TypeError: ia[J[((J[(a >> 2)] + 8) >> 2)]] is not a function

8Observer8 avatar Jun 08 '22 13:06 8Observer8

I solved my problem above. Now Ammo.js works as ES6 module. Playground: Ammo.js as ES6-module. Falling Box

index.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <title>Document</title>

    <style>
        html,
        body {
            overflow: hidden;
            width: 100%;
            height: 100%;
            margin: 0;
            padding: 0;
        }

        #renderCanvas {
            width: 100%;
            height: 100%;
        }
    </style>
</head>

<body>
    <script async src="https://unpkg.com/[email protected]/dist/es-module-shims.js"></script>

    <script type="importmap">
        {
            "imports": {
                "three": "https://unpkg.com/[email protected]/build/three.module.js",
                "collada-loader": "https://unpkg.com/[email protected]/examples/jsm/loaders/ColladaLoader.js",
                "orbit-controls": "https://unpkg.com/[email protected]/examples/jsm/controls/OrbitControls.js",
                "ammo-es": "https://dl.dropboxusercontent.com/s/1os9vvoo1pa3ajk/ammo-es.js"
            }
        }
    </script>

    <!-- https://dl.dropboxusercontent.com/s/1os9vvoo1pa3ajk/ammo-es.js -->
    <!-- https://dl.dropboxusercontent.com/s/v9fu59gb5h0st6b/ammo-es6-module.js -->

    <script type="module" src="js/main.js"></script>
</body>

</html>

js/main.js

import * as THREE from "three";
import AmmoLib from "ammo-es";
import { OrbitControls } from "orbit-controls";

let Ammo, world, scene;
const rigidBodies = [];
let tmpTrans;
const clock = new THREE.Clock();
let deltaTime;

AmmoLib().then((re) =>
{
    Ammo = re;
    setupPhysicsWorld();
    initScene();
    createGround();
    createBox({ x: 0, y: 3, z: 0 });
});

function setupPhysicsWorld()
{
    const collisionConfiguration = new Ammo.btDefaultCollisionConfiguration();
    const dispatcher = new Ammo.btCollisionDispatcher(collisionConfiguration);
    const overlappingPairCache = new Ammo.btDbvtBroadphase();
    const solver = new Ammo.btSequentialImpulseConstraintSolver();

    world = new Ammo.btDiscreteDynamicsWorld(dispatcher, overlappingPairCache, solver, collisionConfiguration);
    world.setGravity(new Ammo.btVector3(0, -10, 0));
    tmpTrans = new Ammo.btTransform();
}

function createGround()
{
    const pos = { x: 0, y: 0, z: 0 };
    const scale = { x: 50, y: 2, z: 50 };
    const quat = { x: 0, y: 0, z: 0, w: 1 };
    const mass = 0;

    // Three.js section

    const ground = new THREE.Mesh(
        new THREE.BoxBufferGeometry(),
        new THREE.MeshPhongMaterial({ color: 0xa0afa4 }));

    ground.position.set(pos.x, pos.y, pos.z);
    ground.scale.set(scale.x, scale.y, scale.z);

    scene.add(ground);

    // Ammo.js section

    const transform = new Ammo.btTransform();
    transform.setIdentity();
    transform.setOrigin(new Ammo.btVector3(pos.x, pos.y, pos.z));
    transform.setRotation(new Ammo.btQuaternion(quat.x, quat.y, quat.z, quat.w));
    const motionState = new Ammo.btDefaultMotionState(transform);

    const colShape = new Ammo.btBoxShape(new Ammo.btVector3(scale.x / 2, scale.y / 2, scale.z / 2));
    colShape.setMargin(0.05);

    const localInertia = new Ammo.btVector3(0, 0, 0);
    colShape.calculateLocalInertia(mass, localInertia);

    const rbInfo = new Ammo.btRigidBodyConstructionInfo(mass, motionState, colShape, localInertia);
    const body = new Ammo.btRigidBody(rbInfo);

    world.addRigidBody(body);
}

function createBox(pos)
{
    const scale = { x: 1, y: 1, z: 1 };
    const quat = { x: 0, y: 0, z: 0, w: 1 };
    const mass = 10;

    // Three.js section

    const box = new THREE.Mesh(
        new THREE.BoxGeometry(1, 1, 1),
        new THREE.MeshPhongMaterial({ color: 0x00ff00 }));
    scene.add(box);

    box.position.set(pos.x, pos.y, pos.z);
    box.scale.set(scale.x, scale.y, scale.z);

    scene.add(box);

    // Ammo.js section

    const transform = new Ammo.btTransform();
    transform.setIdentity();
    transform.setOrigin(new Ammo.btVector3(pos.x, pos.y, pos.z));
    transform.setRotation(new Ammo.btQuaternion(quat.x, quat.y, quat.z, quat.w));
    const motionState = new Ammo.btDefaultMotionState(transform);

    const colShape = new Ammo.btBoxShape(new Ammo.btVector3(scale.x / 2, scale.y / 2, scale.z / 2));
    colShape.setMargin(0.05);

    const localInertia = new Ammo.btVector3(0, 0, 0);
    colShape.calculateLocalInertia(mass, localInertia);

    const rbInfo = new Ammo.btRigidBodyConstructionInfo(mass, motionState, colShape, localInertia);
    const body = new Ammo.btRigidBody(rbInfo);

    world.addRigidBody(body);

    box.userData.physicsBody = body;
    rigidBodies.push(box);
}

function updatePhysics(deltaTime)
{
    world.stepSimulation(deltaTime, 10);

    for (let i = 0; i < rigidBodies.length; i++)
    {
        let objThree = rigidBodies[i];
        let objAmmo = objThree.userData.physicsBody;
        let ms = objAmmo.getMotionState();
        if (ms)
        {
            ms.getWorldTransform(tmpTrans);
            const p = tmpTrans.getOrigin();
            const q = tmpTrans.getRotation();

            objThree.position.set(p.x(), p.y(), p.z());
            objThree.quaternion.set(q.x(), q.y(), q.z(), q.w());
        }
    }
}

function initScene()
{
    scene = new THREE.Scene();

    const ambientLight = new THREE.AmbientLight(0xffffff, 0.7);
    scene.add(ambientLight);

    const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
    directionalLight.position.set(5, 5.5, 5.8);
    scene.add(directionalLight);

    const renderer = new THREE.WebGLRenderer({ antialias: true });
    renderer.setSize(window.innerWidth, window.innerHeight);
    document.body.appendChild(renderer.domElement);

    const camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.01, 1000);
    camera.position.set(0, 3, 7);

    const orbitControls = new OrbitControls(camera, renderer.domElement);
    orbitControls.target = new THREE.Vector3(0, 0, 0);

    (function anim()
    {
        requestAnimationFrame(anim);
        orbitControls.update();
        deltaTime = clock.getDelta();
        updatePhysics(deltaTime);
        renderer.render(scene, camera);
    })();

    window.onresize =
        () =>
        {
            camera.aspect = window.innerWidth / window.innerHeight;
            camera.updateProjectionMatrix();
            renderer.setSize(window.innerWidth, window.innerHeight);
        };
}

8Observer8 avatar Oct 14 '22 21:10 8Observer8