Cheeku
Cheeku

Reputation: 873

cannonjs with Three.js associating a body with mesh

I am using the following code to generate two spheres in cannonjs with Three.js as rendering module.

var world, mass, body, shape, timeStep=1/60,
    camera, scene, renderer, geometry, material, mesh;
    initThree();
    initCannon();
    animate();

    function initCannon() {
        world = new CANNON.World();
        world.gravity.set(0,0,0);
        world.broadphase = new CANNON.NaiveBroadphase();
        world.solver.iterations = 10;

        geometry = new THREE.SphereGeometry( 3);
        material = new THREE.MeshBasicMaterial( { color: 0xff0000, wireframe: true } ); 
        mesh = new THREE.Mesh( geometry, material );
        body = new CANNON.Body({mass:0.2});
        body.angularVelocity.set(0,5,0);
        body.angularDamping = 0.9;
        world.add(body);
        scene.add(mesh);

        geometry = new THREE.SphereGeometry(2);
        material = new THREE.MeshBasicMaterial( { color: 0x00ff00, wireframe: true } );
        mesh = new THREE.Mesh(geometry,material);
        body = new CANNON.Body({mass: 1});
        body.angularVelocity.set(0,10,0);
        body.angularDamping = 0.5;
        world.add(body);
        scene.add(mesh);
    }

    function initThree() {
        scene = new THREE.Scene();
        camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 100 );
        camera.position.z = 5;
        scene.add( camera );

        renderer = new THREE.WebGLRenderer();
        renderer.setSize( window.innerWidth, window.innerHeight );
        document.body.appendChild( renderer.domElement );
    }

    function animate() {
        requestAnimationFrame( animate );
        updatePhysics();
        render();
    }

    function updatePhysics() {
        // Step the physics world
        world.step(timeStep);
        // Copy coordinates from Cannon.js to Three.js
        mesh.position.copy(body.position);
        mesh.quaternion.copy(body.quaternion);
    }

    function render() {
        renderer.render( scene, camera );
    }

As a result, I do get two spheres on display, but only the second body declared in initCannon() animates. The cannonjs body is somehow not associated with the Three.js mesh. I tried "body.mesh=mesh", but it doesn't help.

The declaration for the mesh was originally done in initThree() but I don't figure if that matters anyway.

What am I doing wrong? Please help. Ask for any more details if needed.

Upvotes: 0

Views: 2325

Answers (1)

Jonas Grumann
Jonas Grumann

Reputation: 10776

You're overwriting variables. In the beginning you declare a variable body, and then you say body = new CANNON.Body... and after that you use the same sentence for the second sphere, so the first one gets overwritten. You should have a variable body2, a variable mesh2 to avoid this. This approach would work ok if you only need two bodies, but if you're planning to have more you need a different approach: Arrays. In an Array you can store all your bodies and then loop through it and handle each one singularly. Example:

Here we create 10 bodies:

var bodies= []; //create the array

for (var i = 0; i < 10; i++) {
    bodies.push({ //insert into the array an object that contains the information for each body/mesh
        body: new CANNON.Body({mass:0.2}),
        mesh = new THREE.Mesh(geometry,material)
    })
};

And then we use them:

for (var i=0, l=bodies.length; i < l; i++) { //we loop through each body
    var body = bodies[i]; //this will be the current body
    //MOVE THE BODY AND UPDATE THE MESH HERE
}

This would be a better approach. It's more maintainable and you can have as many bodies as the browser can handle. If you only need two, your fastest fix would to add a second variable for the second body and handle it separately.

EDIT: Watch this: https://www.youtube.com/watch?v=tW6pmzd34Hc he stores the circles into an array as well. I hope it makes it a little bit clearer.

Upvotes: 1

Related Questions