// Three.js physics World using ammo.js
// version for AB API
// Highly modified port of "ammo / instancing" from Three.js examples
// https://threejs.org/examples/?q=ammo#physics_ammo_instancing
const UNIT = 2; // unit of distance
const BOXSIZE = UNIT * 0.1 ;
const FLOORSIZE = UNIT * 5 ;
const LIGHTPOS = UNIT * 5 ;
const BOXTIMEOUT = 300 ; // create new box every n milliseconds
const startRadius = UNIT * 2 ;
const maxRadius = UNIT * 1000 ;
const SKYCOLOR = 'lightblue';
const TEXTURE_FILE_0 = '/uploads/starter/smiley.png' ; // textures for boxes
const TEXTURE_FILE_1 = '/uploads/starter/ghost.3.png' ;
var box_texture_0, box_texture_1 ;
// 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 ) )); }
function randomHighPos() { return ( randomPos ( AB.randomFloatAtoB ( 1.5*UNIT, 2*UNIT ) )); }
let physics;
// ---- get AB loaded and physics loaded and then can create scene -----------------
var ABloaded = false;
var physicsLoaded = false;
AB.runReady = false;
AB.world.newRun = function()
{
ABloaded = true;
if ( ABloaded && physicsLoaded ) createScene();
};
loadPhysics();
async function loadPhysics()
{
physics = await AmmoPhysics();
physicsLoaded = true;
if ( ABloaded && physicsLoaded ) createScene();
}
// -------------------------------------------------------------------------------------------
function createScene()
{
// ready to create Three.js scene
// define my own custom renderer and camera
ABWorld.renderer = new THREE.WebGLRenderer ( { antialias: true } );
ABWorld.renderer.setPixelRatio ( window.devicePixelRatio );
ABWorld.renderer.shadowMap.enabled = true;
ABWorld.renderer.outputEncoding = THREE.sRGBEncoding;
ABWorld.camera = new THREE.PerspectiveCamera ( 50, window.innerWidth / window.innerHeight, 0.1, maxRadius ); // near value of 0.1 to allow camera get closer to boxes
ABWorld.init3d ( startRadius, maxRadius, SKYCOLOR );
ABWorld.lookat.copy ( ABWorld.scene.position );
loadResources(); // asynchronous file loads
// calls initScene() when all done
}
function loadResources()
{
var loader0 = new THREE.TextureLoader();
var loader1 = new THREE.TextureLoader();
loader0.load ( TEXTURE_FILE_0, function ( thetexture )
{
thetexture.minFilter = THREE.LinearFilter;
box_texture_0 = thetexture;
if ( box_texture_0 && box_texture_1 ) initScene();
});
loader1.load ( TEXTURE_FILE_1, function ( thetexture )
{
thetexture.minFilter = THREE.LinearFilter;
box_texture_1 = thetexture;
if ( box_texture_0 && box_texture_1 ) initScene();
});
}
function initScene()
{
// files are loaded
// ABWorld.scene is ready to be populated
const hemiLight = new THREE.HemisphereLight();
hemiLight.intensity = 0.35;
ABWorld.scene.add( hemiLight );
const dirLight = new THREE.DirectionalLight();
dirLight.position.set ( LIGHTPOS, LIGHTPOS, LIGHTPOS );
dirLight.castShadow = true;
dirLight.shadow.camera.zoom = 2;
ABWorld.scene.add( dirLight );
// floor
var floorGeometry = new THREE.BoxGeometry ( FLOORSIZE, FLOORSIZE, FLOORSIZE );
var floorMaterial = new THREE.ShadowMaterial ( { color: 0x111111 } );
var floor = new THREE.Mesh ( floorGeometry, floorMaterial );
floor.position.y = -2.5 * UNIT;
floor.receiveShadow = true;
ABWorld.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
// this is important - otherwise boxes fall forever
// now the run can start
ABWorld.render();
AB.runReady = true;
createBox();
}
function createBox()
{
// pick random one of the textures:
var boxMaterial = new THREE.MeshLambertMaterial ( { map: AB.randomPick ( box_texture_0, box_texture_1 ) } );
var boxGeometry = new THREE.BoxGeometry ( BOXSIZE, BOXSIZE, BOXSIZE );
var box = new THREE.Mesh ( boxGeometry, boxMaterial );
box.castShadow = true;
box.receiveShadow = true;
box.position.copy ( randomHighPos() ); // use copy to set position from a vector
box.rotation.set( Math.random() * Math.PI, Math.random() * Math.PI, Math.random() * Math.PI );
ABWorld.scene.add( box );
physics.addMesh ( box, 1 ); // has mass, so it falls
setTimeout ( createBox, BOXTIMEOUT );
}
AB.world.nextStep = function()
{
};