// Three.js physics World using ammo.js
// Highly modified port of "ammo / instancing" from Three.js examples
// https://threejs.org/examples/?q=ammo#physics_ammo_instancing
AB.backgroundMusic ( '/uploads/starter/Interstellar.mp3' );
const UNIT = 2; // unit of distance
const BOXSIZE = UNIT * 0.1 ;
const FLOORSIZE = UNIT * 5 ;
const LIGHTPOS = UNIT * 5 ;
const NOBOXES = 100; // initial number of boxes - we then make more
const BOXTIMEOUT = 200 ; // create new box every n milliseconds
// random start positions for falling objects
// x and z near origin, height y is argument:
function randomPos ( y ) { return ( new THREE.Vector3 ( AB.randomFloatAtoB ( -0.5*UNIT, 0.5*UNIT ), y, AB.randomFloatAtoB ( -0.5*UNIT, 0.5*UNIT ) )); }
// y is high or low:
function randomHighPos() { return ( randomPos ( AB.randomFloatAtoB ( 1.5*UNIT, 2*UNIT ) )); }
function randomLowPos() { return ( randomPos ( AB.randomFloatAtoB ( 0*UNIT, 2*UNIT ) )); }
function randomColor() { return ( AB.randomPick ( 'firebrick', 'teal' )); }
let camera, scene, renderer;
let physics, boxes;
init();
async function init()
{
physics = await AmmoPhysics();
camera = new THREE.PerspectiveCamera ( 60, window.innerWidth / window.innerHeight, 1, 1000*UNIT );
camera.position.set ( -UNIT, UNIT*1.5, UNIT*2 );
camera.lookAt ( 0, 0.5*UNIT, 0 );
scene = new THREE.Scene();
scene.background = new THREE.Color( 'lightblue' );
const dirLight = new THREE.DirectionalLight();
dirLight.position.set ( LIGHTPOS, LIGHTPOS, LIGHTPOS );
scene.add( dirLight );
// floor
var floorGeometry = new THREE.BoxGeometry ( FLOORSIZE, FLOORSIZE, FLOORSIZE );
var floorMaterial = new THREE.MeshBasicMaterial ( { color: 'palegoldenrod' } );
var floor = new THREE.Mesh ( floorGeometry, floorMaterial );
floor.position.y = -2.5 * UNIT;
scene.add( floor );
physics.addMesh ( floor, 0 );
// see function addMesh in AmmoPhysics.js
// addMesh ( mesh, mass = 0 )
// floor has no mass - will not fall - will stay in place
// boxes
var boxGeometry = new THREE.BoxGeometry ( BOXSIZE, BOXSIZE, BOXSIZE );
var boxMaterial = new THREE.MeshLambertMaterial();
boxes = new THREE.InstancedMesh ( boxGeometry, boxMaterial, NOBOXES );
scene.add( boxes );
var matrix = new THREE.Matrix4();
for ( let i = 0; i < boxes.count; i++ )
{
matrix.setPosition ( randomLowPos() );
boxes.setMatrixAt ( i, matrix );
var color = new THREE.Color ( randomColor() );
boxes.setColorAt ( i, color );
}
physics.addMesh ( boxes, 1 ); // added with mass, so they fall
// init Three.js
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.outputEncoding = THREE.sRGBEncoding;
document.body.appendChild( renderer.domElement );
createBox();
animate();
}
function createBox()
{
var boxGeometry = new THREE.BoxGeometry ( BOXSIZE, BOXSIZE, BOXSIZE );
var boxMaterial = new THREE.MeshLambertMaterial ( { color: randomColor() } );
var box = new THREE.Mesh ( boxGeometry, boxMaterial );
box.position.copy ( randomHighPos() ); // use copy to set position from a vector
scene.add( box );
physics.addMesh ( box, 1 ); // has mass, so it falls
setTimeout ( createBox, BOXTIMEOUT ); // make new box is on a different timer to animate()
}
function animate()
{
requestAnimationFrame( animate );
// original code would make a "new" box as follows:
// pick one box at random and suddenly move its position to up in the air to make the "new" box
// strange effect - boxes vanishing at random
// var i = AB.randomIntAtoB ( 0, boxes.count -1 ); // random 0 to (boxes.count - 1)
// physics.setMeshPosition ( boxes, randomPos(), i ); // see function setMeshPosition in AmmoPhysics.js
renderer.render( scene, camera );
}