Introduction – Before you start
In this example of using physics with the coupling of Three.JS and Ammo.js, we start from the final state of the code put in place in the previous chapter :
In this chapter, our objective will be to demolish a wall thanks to a physical collision. If you’re ready, let’s begin!
Light code modifications
Let’s return to the code from the previous chapter. We will begin our modifications with a very light recasting of the createCube
function. We will create a color
parameter, used to define the color of the cube.
We also modify the scale
parameter. Initially, this parameter was a simple Integer
; we will transform it into a Vector3
in order to define a different measurement on each XYZ axis.
Here is our slightly modified createCube
function :
function createCube(scale , position, mass, color, rot_quaternion) { let quaternion = undefined; if(rot_quaternion == null) { quaternion = {x: 0, y: 0, z: 0, w: 1}; } else { quaternion = rot_quaternion; } // ------ Graphics Universe - Three.JS ------ let newcube = new THREE.Mesh(new THREE.BoxBufferGeometry(scale.x, scale.y, scale.z), new THREE.MeshPhongMaterial({color: color})); newcube.position.set(position.x, position.y, position.z); scene.add(newcube); // ------ Physics Universe - Ammo.js ------ let transform = new Ammo.btTransform(); transform.setIdentity(); transform.setOrigin( new Ammo.btVector3( position.x, position.y, position.z ) ); transform.setRotation( new Ammo.btQuaternion( quaternion.x, quaternion.y, quaternion.z, quaternion.w ) ); let defaultMotionState = new Ammo.btDefaultMotionState( transform ); let structColShape = new Ammo.btBoxShape( new Ammo.btVector3( scale.x*0.5, scale.y*0.5, scale.z*0.5 ) ); structColShape.setMargin( 0.05 ); let localInertia = new Ammo.btVector3( 0, 0, 0 ); structColShape.calculateLocalInertia( mass, localInertia ); let RBody_Info = new Ammo.btRigidBodyConstructionInfo( mass, defaultMotionState, structColShape, localInertia ); let RBody = new Ammo.btRigidBody( RBody_Info ); physicsUniverse.addRigidBody( RBody ); newcube.userData.physicsBody = RBody; rigidBody_List.push(newcube); }
Setting up the Scene
Once these modifications are done, let’s return to the AmmoStart
function. Next, use createCube
to put in place the actors of our scene.
Let’s begin with the support, the ground of our dynamic scene :
createCube(new THREE.Vector3(50, 2, 90) , new THREE.Vector3(15, -5, 30) , 0 , 0x2c3e50, null);
Here are the details of the parameters used :
scale
– Height on the XYZ axes :(50, 2, 90)
.position
– Position on the XYZ axes :(15, -5, 30)
.mass
– Mass of our object :0
(Infinite mass, static object).color
– Color of our object in hexadecimal form :0x2c3e50
.rot_quaternion
– Quaternion, initial rotation of the object :null
so{x: 0, y: 0, z: 0, w: 1}
by default.
In the same manner, let’s create a block oriented at a slant :
createCube(new THREE.Vector3(8, 1, 15) , new THREE.Vector3(15, 0, 0) , 0 , 0xffffff, {x: 0.383, y: 0, z: 0, w: 0.924} );
Thus, we use the rot_quaternion
parameter to define an initial rotation, turn the object and orient it on a slant.
Here are our two static blocks :
Next, remaining with createCube
, let’s create all our dynamic bricks with the help of loops :
for(var z = 30 ; z > 15 ; z -= 5) { for(var j = 0 ; j < 10 ; j += 2.2) { for(var i = 0 ; i < 30 ; i += 2.1) { createCube(new THREE.Vector3(2, 2, 1.5) , new THREE.Vector3(i, j, z) , 1 , 0xffffff, null); } } }
Thus, we create stacked bricks, with the mass 1
. Here is the current state of our scene :
To finish, let’s create a cube in freefall above the slope. The latter will fall on the top of the slope and will be propelled towards the walls of bricks :
setTimeout( function() { createCube(new THREE.Vector3(6, 6, 6) , new THREE.Vector3(15, 500, -1) , 10000 , 0xc0392b, {x: 0.383, y: 0, z: 0.383, w: 0.924} ); }, 3000);
We choose to make a cube appear with a mass of 10000
at an altitude of 500
, after an elapsed time of 3
seconds (3000 ms
).
Final code and result
Here is the final code of our AmmoStart
function :
function AmmoStart() { tmpTransformation = new Ammo.btTransform(); initPhysicsUniverse(); initGraphicsUniverse(); createCube(new THREE.Vector3(50, 2, 90) , new THREE.Vector3(15, -5, 30) , 0 , 0x2c3e50, null); for(var z = 30 ; z > 15 ; z -= 5) { for(var j = 0 ; j < 10 ; j += 2.2) { for(var i = 0 ; i < 30 ; i += 2.1) { createCube(new THREE.Vector3(2, 2, 1.5) , new THREE.Vector3(i, j, z) , 1 , 0xffffff, null); } } } createCube(new THREE.Vector3(8, 1, 15) , new THREE.Vector3(15, 0, 0) , 0 , 0xffffff, {x: 0.383, y: 0, z: 0, w: 0.924} ); setTimeout( function() { createCube(new THREE.Vector3(6, 6, 6) , new THREE.Vector3(15, 500, -1) , 10000 , 0xc0392b, {x: 0.383, y: 0, z: 0.383, w: 0.924} ); }, 3000); render(); }
And to finish this chapter, here is an overview of our creation :