2016-10-14 12:32:53 +02:00
|
|
|
/**
|
|
|
|
* 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;
|
|
|
|
};
|
|
|
|
|
2016-10-18 13:37:38 +02:00
|
|
|
GameLib.D3.World.prototype.AddShape = function(
|
2016-10-14 12:32:53 +02:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2016-10-18 13:37:38 +02:00
|
|
|
GameLib.D3.World.prototype.Wheel = function() {
|
2016-10-14 12:32:53 +02:00
|
|
|
|
|
|
|
};
|
|
|
|
|
2016-10-18 13:37:38 +02:00
|
|
|
GameLib.D3.World.prototype.CreateRigidVehicle = function(
|
2016-10-14 12:32:53 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2016-10-18 13:37:38 +02:00
|
|
|
GameLib.D3.World.prototype.CreateRaycastVehicle = function(
|
2016-10-14 12:32:53 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2016-10-18 13:37:38 +02:00
|
|
|
GameLib.D3.World.prototype.AddWheelToRigidVehicle = function(
|
2016-10-14 12:32:53 +02:00
|
|
|
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)
|
|
|
|
});
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2016-10-18 13:37:38 +02:00
|
|
|
GameLib.D3.World.prototype.AddWheelToRaycastVehicle = function (
|
2016-10-14 12:32:53 +02:00
|
|
|
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");
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
2016-10-18 13:37:38 +02:00
|
|
|
GameLib.D3.World.prototype.CreateTriMeshShape = function(
|
2016-10-14 12:32:53 +02:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2016-10-18 13:37:38 +02:00
|
|
|
GameLib.D3.World.prototype.CreateSphereShape = function (
|
2016-10-14 12:32:53 +02:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2016-10-18 13:37:38 +02:00
|
|
|
GameLib.D3.World.prototype.CreateBoxShape = function(
|
2016-10-14 12:32:53 +02:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2016-10-18 13:37:38 +02:00
|
|
|
GameLib.D3.World.prototype.CreateCylinderShape = function(
|
2016-10-14 12:32:53 +02:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2016-10-18 13:37:38 +02:00
|
|
|
GameLib.D3.World.prototype.AddRigidBody = function(
|
2016-10-14 12:32:53 +02:00
|
|
|
rigidBody // Physics.RigidBody
|
|
|
|
) {
|
|
|
|
if(this.physics.engineType === GameLib.D3.Physics.TYPE_CANNON) {
|
|
|
|
this.worldObject.addBody(rigidBody.bodyObject);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2016-10-18 13:37:38 +02:00
|
|
|
GameLib.D3.World.prototype.AddVehicle = function(
|
2016-10-14 12:32:53 +02:00
|
|
|
vehicle // note: physics.vehicle
|
|
|
|
) {
|
|
|
|
if(this.physics.engineType == GameLib.D3.Physics.TYPE_CANNON) {
|
|
|
|
vehicle.vehicleObject.addToWorld(this.worldObject);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2016-10-18 13:37:38 +02:00
|
|
|
GameLib.D3.World.prototype.Step = function(
|
2016-10-14 12:32:53 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2016-10-18 13:37:38 +02:00
|
|
|
GameLib.D3.World.prototype.GetIndexedVertices = function(
|
2016-10-14 12:32:53 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
2016-10-18 13:37:38 +02:00
|
|
|
GameLib.D3.World.prototype.GenerateWireframeViewMesh = function(
|
2016-10-14 12:32:53 +02:00
|
|
|
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;
|
|
|
|
};
|
|
|
|
|
2016-10-18 13:37:38 +02:00
|
|
|
GameLib.D3.World.prototype.GenerateTriangleCollisionMesh = function(
|
2016-10-14 12:32:53 +02:00
|
|
|
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++;
|
|
|
|
}
|
|
|
|
};
|