/** * World SuperSet - contains the custom world instance * @param id * @param name * @param engine * @param gravity * @param broadphase * @param solver * @param rigidBodies * @constructor */ GameLib.D3.World = function( id, name, engine, gravity, broadphase, solver, rigidBodies ) { this.id = id; this.name = name; if (typeof gravity == 'undefined') { gravity = new GameLib.D3.Vector3(0, -9.81, 0); } this.gravity = gravity; if (typeof broadphase == 'undefined') { broadphase = new GameLib.D3.Physics.Broadphase( null, 'broadPhaseNaive', GameLib.D3.Physics.BROADPHASE_TYPE_NAIVE ); } this.broadphase = broadphase; if (typeof solver == 'undefined') { solver = new GameLib.D3.Physics.Solver( null, 'GSSolver', GameLib.D3.Physics.GS_SOLVER ); } this.solver = solver; if (typeof rigidBodies == 'undefined') { rigidBodies = []; } this.rigidBodies = rigidBodies; this.engine = null; this.worldInstance = null; /** * We only set the physics property if we pass it in the constructor, * because we don't always want the physics object (ex. when we store this world to the API - we also don't then * want to store the custom worlds - we want to generate them after loading from API) */ if (engine) { this.engine = engine; this.worldInstance = this.createWorldInstance(); } }; GameLib.D3.World.prototype.createWorldInstance = function() { this.engine.isNotCannonThrow(); var customWorld = new this.engine.instance.World(); var cannonBroadphase = null; customWorld.broadphase = cannonBroadphase; var cannonSolver = null; if (this.solver.solverType == GameLib.D3.Physics.SPLIT_SOLVER) { cannonSolver = new this.engine.instance.SplitSolver(); } else if (this.solver.solverType == GameLib.D3.Physics.GS_SOLVER) { cannonSolver = new this.engine.instance.GSSolver(); cannonSolver.iterations = this.solver.iterations; } customWorld.solver = cannonSolver; customWorld.gravity.x = this.gravity.x; customWorld.gravity.y = this.gravity.y; customWorld.gravity.z = this.gravity.z; for (var b = 0; b < this.rigidBodies.length; b++) { var customBody = this.createCustomBody(this.rigidBodies[b]); //customWorld.AddRigidBody(); } customWorld.name = this.name; return customWorld; }; GameLib.D3.World.prototype.AddShape = function( shape, // d3.physics.shape rigidBody, offset, // vec3 orientation //quaternion ) { shape.shape = shape; /** * TODO:: fix this? */ if (this.physics.engineType === GameLib.D3.Physics.TYPE_CANNON) { var _offset = null; var _orientation = null; if(offset != null && typeof offset !== 'undefined') { _offset = new this.physics.CANNON.Vec3(offset.x, offset.y, offset.z); } if(orientation != null && typeof orientation !== 'undefined') { _orientation = new this.physics.CANNON.Quaternion(orientation.x, orientation.y, orientation.z, orientation.w); } rigidBody.bodyObject.addShape(shape.shapeObject, _offset, _orientation); } }; GameLib.D3.World.prototype.Wheel = function() { }; GameLib.D3.World.prototype.CreateRigidVehicle = function( chassisBody // Physics.RigidBody ) { var rigidVehicle = new GameLib.D3.Physics.RigidVehicle(); if (this.physics.engineType == GameLib.D3.Physics.TYPE_CANNON) { var vehicle = new this.physics.CANNON.RigidVehicle({ chassisBody: chassisBody.bodyObject }); rigidVehicle.vehicleObject = vehicle; return rigidVehicle; } }; GameLib.D3.World.prototype.CreateRaycastVehicle = function( chassisBody // Physics.RigidBody ) { var raycastVehicle = new GameLib.D3.Physics.RaycastVehicle(); if(this.physics.engineType == GameLib.D3.Physics.TYPE_CANNON) { var vehicle = new this.physics.CANNON.RaycastVehicle({ chassisBody: chassisBody.bodyObject }); raycastVehicle.vehicleObject = vehicle; return raycastVehicle; } }; GameLib.D3.World.prototype.AddWheelToRigidVehicle = function( vehicle, rigidBody, position, axis, direction ) { if(this.physics.engineType == GameLib.D3.Physics.TYPE_CANNON) { vehicle.vehicleObject.addWheel({ body: rigidBody.bodyObject, position: new this.physics.CANNON.Vec3(position.x, position.y, position.z), axis: new this.physics.CANNON.Vec3(axis.x, axis.y, axis.z), direction: new this.physics.CANNON.Vec3(direction.x, direction.y, direction.z) }); } }; GameLib.D3.World.prototype.AddWheelToRaycastVehicle = function ( vehicle, // physics.raycastvehicle options // cannon options ) { if (this.physics.engineType == GameLib.D3.Physics.TYPE_CANNON) { vehicle.vehicleObject.addWheel(options); } else { console.log("function for engine not implemented"); } }; GameLib.D3.World.prototype.CreateTriMeshShape = function( vertices, // flat list of floats indices // flat list of floats ) { if(this.physics.engineType == GameLib.D3.Physics.TYPE_CANNON) { return new GameLib.D3.Physics.Shape(new this.physics.CANNON.Trimesh(vertices, indices), GameLib.D3.Physics.SHAPE_TYPE_TRIMESH); } }; GameLib.D3.World.prototype.CreateSphereShape = function ( radius ) { if(this.physics.engineType == GameLib.D3.Physics.TYPE_CANNON) { return new GameLib.D3.Physics.Shape(new this.physics.CANNON.Sphere(radius), GameLib.D3.Physics.SHAPE_TYPE_SPHERE); } }; GameLib.D3.World.prototype.CreateBoxShape = function( halfExtensions // vec3 ) { if(this.physics.engineType == GameLib.D3.Physics.TYPE_CANNON) { return new GameLib.D3.Physics.Shape(new this.physics.CANNON.Box(new this.physics.CANNON.Vec3(halfExtensions.x, halfExtensions.y, halfExtensions.z)), GameLib.D3.Physics.SHAPE_TYPE_BOX); } }; GameLib.D3.World.prototype.CreateCylinderShape = function( radiusTop, radiusBottom, height, numSegments ) { if(this.physics.engineType == GameLib.D3.Physics.TYPE_CANNON) { return new GameLib.D3.Physics.Shape(new this.physics.CANNON.Cylinder(radiusTop, radiusBottom, height, numSegments), GameLib.D3.Physics.SHAPE_TYPE_CYLINDER); } }; GameLib.D3.World.prototype.AddRigidBody = function( rigidBody // Physics.RigidBody ) { if(this.physics.engineType === GameLib.D3.Physics.TYPE_CANNON) { this.worldObject.addBody(rigidBody.bodyObject); } }; GameLib.D3.World.prototype.AddVehicle = function( vehicle // note: physics.vehicle ) { if(this.physics.engineType == GameLib.D3.Physics.TYPE_CANNON) { vehicle.vehicleObject.addToWorld(this.worldObject); } }; GameLib.D3.World.prototype.Step = function( timeStep ) { if(this.physics.engineType == GameLib.D3.Physics.TYPE_CANNON) { // todo: figure out, why this call to internal step is more stable for trimesh collisions..... //this.worldObject.internalStep(timeStep); //return; var now = performance.now() / 1000; if(!this.lastCallTime){ // last call time not saved, cant guess elapsed time. Take a simple step. this.worldObject.step(timeStep); this.lastCallTime = now; return; } var timeSinceLastCall = now - this.lastCallTime; this.worldObject.step(timeStep, timeSinceLastCall); this.lastCallTime = now; } }; GameLib.D3.World.prototype.GetIndexedVertices = function( triangleMeshShape ) { if(this.engine.engineType == GameLib.D3.Physics.TYPE_CANNON) { return { vertices : triangleMeshShape.vertices, indices : triangleMeshShape.indices }; } else { // todo: implement this for other physics engines. return null; } }; GameLib.D3.World.prototype.GenerateWireframeViewMesh = function( triangleMeshShape, normalLength, scale, opacity, wireframeColor ) { var geometryTHREE = new THREE.Geometry(); var wireframeTHREEMesh = new THREE.Mesh ( geometryTHREE, new THREE.MeshBasicMaterial({ color: wireframeColor ? wireframeColor : 0xfefefe, wireframe: true, opacity: opacity ? opacity : 0.5 }) ); var data = this.GetIndexedVertices(triangleMeshShape); for(var i = 0, l = data.vertices.length / 3; i < l; i++) { geometryTHREE.vertices.push(new THREE.Vector3(data.vertices[i * 3], data.vertices[i * 3 + 1], data.vertices[i * 3 + 2])); } for(var i = 0, l = data.indices.length / 3; i < l; i++) { var i0 = data.indices[i * 3]; var i1 = data.indices[i * 3 + 1]; var i2 = data.indices[i * 3 + 2]; geometryTHREE.faces.push(new THREE.Face3(i0, i1, i2)); // Create debug view for normals // Center point on the mesh itself var centroid = new THREE.Vector3() .add(geometryTHREE.vertices[i0]) .add(geometryTHREE.vertices[i1]) .add(geometryTHREE.vertices[i2]) .divideScalar(3); var normal = null; if(this.engine.engineType == GameLib.D3.Physics.TYPE_CANNON) { var normal = new this.physics.CANNON.Vec3(); triangleMeshShape.getNormal(i, normal); } else { // todo: calculate the normal for v0, v1 & v2 here. } var arrow = new THREE.ArrowHelper(new THREE.Vector3(normal.x, normal.y, normal.z), centroid, normalLength, new THREE.Color(normal.x, normal.y, normal.z)); wireframeTHREEMesh.add( arrow ); } wireframeTHREEMesh.scale.x = scale.x; wireframeTHREEMesh.scale.y = scale.y; wireframeTHREEMesh.scale.z = scale.z; return wireframeTHREEMesh; }; GameLib.D3.World.prototype.GenerateTriangleCollisionMesh = function( threeMesh, mass, // default = 0 friction, // default = 10 createCollisionSubMeshes, // boolean. default = false facesPerSubsection, // int. default = 0 subsectionsToMerge // int. default = 0 ) { var processedFaces = 0; var facesPerSubSection = facesPerSubsection || 0; var subMeshesToMerge = subsectionsToMerge || 0; var totalAmtFaces = threeMesh.geometry.faces.length; var facesToProcess = createCollisionSubMeshes ? (subMeshesToMerge * facesPerSubSection) : totalAmtFaces; var pairs = []; // output var vertices = []; var indicies = []; for(var i = 0; i <= totalAmtFaces; i++) { if(processedFaces == facesToProcess || i == totalAmtFaces) { var body = null; if(this.engine.engineType == GameLib.D3.Physics.TYPE_CANNON) { var meshShape = new this.physics.CANNON.Trimesh(vertices, indicies); meshShape.setScale(new this.physics.CANNON.Vec3(threeMesh.scale.x, threeMesh.scale.y, threeMesh.scale.z)); meshShape.updateAABB(); meshShape.updateNormals(); meshShape.updateEdges(); meshShape.updateBoundingSphereRadius(); meshShape.updateTree(); body = new this.physics.CANNON.Body({ mass: mass ? mass : 0, friction: friction ? friction : 10 }); body.addShape(meshShape); } else if (this.engine.engineType == GameLib.D3.Physics.Engine.TYPE_AMMO) { } else if (this.engine.engineType == GameLib.D3.Physics.Engine.TYPE_GOBLIN) { } pairs.push({ threeObject : createCollisionSubMeshes ? null : threeMesh, physicsObject : body }); vertices = []; indicies = []; processedFaces = 0; if(i == totalAmtFaces) { return pairs; } } var face = threeMesh.geometry.faces[i]; indicies.push(indicies.length); indicies.push(indicies.length); indicies.push(indicies.length); var v0 = threeMesh.geometry.vertices[face.a]; var v1 = threeMesh.geometry.vertices[face.b]; var v2 = threeMesh.geometry.vertices[face.c]; vertices.push(v0.x, v0.y, v0.z); vertices.push(v1.x, v1.y, v1.z); vertices.push(v2.x, v2.y, v2.z); processedFaces++; } };