914 lines
26 KiB
JavaScript
914 lines
26 KiB
JavaScript
|
/**
|
||
|
* World SuperSet - contains the custom world instance
|
||
|
* @param id
|
||
|
* @param name
|
||
|
* @param engine
|
||
|
* @param gravity
|
||
|
* @param broadphase
|
||
|
* @param solver
|
||
|
* @param rigidBodies
|
||
|
* @constructor
|
||
|
*/
|
||
|
R3.D3.World = function(
|
||
|
id,
|
||
|
name,
|
||
|
engine,
|
||
|
gravity,
|
||
|
broadphase,
|
||
|
solver,
|
||
|
rigidBodies
|
||
|
) {
|
||
|
|
||
|
this.id = id;
|
||
|
|
||
|
this.name = name;
|
||
|
|
||
|
if (typeof gravity == 'undefined') {
|
||
|
gravity = new R3.API.Vector3(0, -9.81, 0);
|
||
|
}
|
||
|
this.gravity = gravity;
|
||
|
|
||
|
if (typeof broadphase == 'undefined') {
|
||
|
broadphase = new R3.D3.Broadphase(
|
||
|
null,
|
||
|
'broadPhaseNaive',
|
||
|
R3.D3.Broadphase.BROADPHASE_TYPE_NAIVE,
|
||
|
engine
|
||
|
);
|
||
|
}
|
||
|
this.broadphase = broadphase;
|
||
|
|
||
|
if (typeof solver == 'undefined') {
|
||
|
solver = new R3.D3.Solver(
|
||
|
null,
|
||
|
engine,
|
||
|
R3.D3.Solver.GS_SOLVER
|
||
|
);
|
||
|
}
|
||
|
this.solver = solver;
|
||
|
|
||
|
if (typeof rigidBodies == 'undefined') {
|
||
|
rigidBodies = [];
|
||
|
}
|
||
|
this.rigidBodies = rigidBodies;
|
||
|
|
||
|
this.engine = engine;
|
||
|
|
||
|
this.engine.isNotCannonThrow();
|
||
|
|
||
|
this.instance = this.createInstance();
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* private
|
||
|
* @returns {R3.D3.World|R3.D3.Physics.World|*}
|
||
|
*/
|
||
|
R3.D3.World.prototype.createInstance = function() {
|
||
|
|
||
|
var instance = new this.engine.instance.World();
|
||
|
|
||
|
instance.broadphase = this.broadphase.instance;
|
||
|
|
||
|
instance.solver = this.solver.instance;
|
||
|
|
||
|
instance.gravity.x = this.gravity.x;
|
||
|
instance.gravity.y = this.gravity.y;
|
||
|
instance.gravity.z = this.gravity.z;
|
||
|
|
||
|
instance.name = this.name;
|
||
|
|
||
|
return instance;
|
||
|
};
|
||
|
|
||
|
R3.D3.World.prototype.toApiWorld = function() {
|
||
|
//TODO: create API.World someday
|
||
|
return {
|
||
|
id: this.id,
|
||
|
name: this.name,
|
||
|
engine: this.engine.toApiEngine(),
|
||
|
gravity: this.gravity,
|
||
|
broadphase: this.broadphase.toApiBroadphase(),
|
||
|
solver: this.solver.toApiSolver(),
|
||
|
rigidBodies: this.rigidBodies.map(function(rigidBody){return rigidBody.toApiRigidBody()})
|
||
|
}
|
||
|
};
|
||
|
|
||
|
|
||
|
R3.D3.World.FromObjectWorld = function(engine, objectWorld) {
|
||
|
|
||
|
//todo implement this fully
|
||
|
return new R3.D3.World(
|
||
|
objectWorld.id,
|
||
|
objectWorld.name,
|
||
|
engine,
|
||
|
objectWorld.gravity,
|
||
|
null,
|
||
|
null,
|
||
|
null
|
||
|
);
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
*
|
||
|
* @param rigidBody R3.D3.RigidBody
|
||
|
* @constructor
|
||
|
*/
|
||
|
R3.D3.World.prototype.addRigidBody = function(
|
||
|
rigidBody
|
||
|
) {
|
||
|
this.instance.addBody(rigidBody.instance);
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
*
|
||
|
* @param vehicle (R3.D3.RigidBodyVehicle | R3.D3.RaycastVehicle)
|
||
|
* @constructor
|
||
|
*/
|
||
|
R3.D3.World.prototype.addVehicle = function(
|
||
|
vehicle
|
||
|
) {
|
||
|
vehicle.instance.addToWorld(this.instance);
|
||
|
};
|
||
|
|
||
|
R3.D3.World.prototype.step = function(
|
||
|
fixedStep,
|
||
|
dtStep
|
||
|
) {
|
||
|
this.instance.step(fixedStep, dtStep, 3);
|
||
|
return;
|
||
|
|
||
|
var now = Date.now() / 1000.0;
|
||
|
//var now = null;
|
||
|
if(!this.lastCallTime){
|
||
|
// last call time not saved, cant guess elapsed time. Take a simple step.
|
||
|
this.instance.step(fixedStep);
|
||
|
this.lastCallTime = now;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
var timeSinceLastCall = (now - this.lastCallTime);
|
||
|
|
||
|
this.instance.step(fixedStep, timeSinceLastCall, 4);
|
||
|
|
||
|
this.lastCallTime = now;
|
||
|
};
|
||
|
|
||
|
R3.D3.World.prototype.GetIndexedVertices = function(
|
||
|
triangleMeshShape
|
||
|
) {
|
||
|
|
||
|
if(this.engine.engineType == R3.D3.Physics.TYPE_CANNON) {
|
||
|
|
||
|
return {
|
||
|
vertices : triangleMeshShape.vertices,
|
||
|
indices : triangleMeshShape.indices
|
||
|
};
|
||
|
|
||
|
} else {
|
||
|
// todo: implement this for other physics engines.
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* @param triangleMeshShape R3.D3.Shape
|
||
|
* @param normalLength Number
|
||
|
* @param scale R3.API.Vector3
|
||
|
* @param opacity Number
|
||
|
* @param wireframeColor HexCode
|
||
|
* @param graphics THREE
|
||
|
* @returns {THREE.Mesh|this.meshes}
|
||
|
* @constructor
|
||
|
*/
|
||
|
R3.D3.World.prototype.generateWireframeViewTriangleMesh = function(
|
||
|
graphics,
|
||
|
triangleMeshShape,
|
||
|
normalLength,
|
||
|
scale,
|
||
|
opacity,
|
||
|
wireframeColor
|
||
|
) {
|
||
|
graphics.isNotThreeThrow();
|
||
|
this.engine.isNotCannonThrow();
|
||
|
|
||
|
if(typeof normalLength == 'undefined') {
|
||
|
normalLength = 10;
|
||
|
}
|
||
|
|
||
|
if(typeof scale == 'undefined') {
|
||
|
scale = new graphics.instance.Vector3(1, 1, 1);
|
||
|
}
|
||
|
|
||
|
if(typeof opacity == 'undefined') {
|
||
|
opacity = 0.5;
|
||
|
}
|
||
|
|
||
|
if(typeof wireframeColor == 'undefined') {
|
||
|
wireframeColor = 0xfefefe;
|
||
|
}
|
||
|
|
||
|
var graphicsGeometry = new graphics.instance.Geometry();
|
||
|
|
||
|
var wireframeMesh = new graphics.instance.Mesh(
|
||
|
graphicsGeometry,
|
||
|
new graphics.instance.MeshBasicMaterial({
|
||
|
color: wireframeColor,
|
||
|
wireframe: true,
|
||
|
opacity: opacity
|
||
|
})
|
||
|
);
|
||
|
|
||
|
for(var v = 0, l = triangleMeshShape.instance.vertices.length / 3; v < l; ++v) {
|
||
|
graphicsGeometry.vertices.push(
|
||
|
new graphics.instance.Vector3(
|
||
|
triangleMeshShape.instance.vertices[v * 3],
|
||
|
triangleMeshShape.instance.vertices[v * 3 + 1],
|
||
|
triangleMeshShape.instance.vertices[v * 3 + 2]
|
||
|
)
|
||
|
);
|
||
|
}
|
||
|
|
||
|
for(var i = 0, l = triangleMeshShape.instance.indices.length / 3; i < l; ++i) {
|
||
|
var i0 = triangleMeshShape.instance.indices[i * 3];
|
||
|
var i1 = triangleMeshShape.instance.indices[i * 3 + 1];
|
||
|
var i2 = triangleMeshShape.instance.indices[i * 3 + 2];
|
||
|
|
||
|
graphicsGeometry.faces.push(
|
||
|
new graphics.instance.Face3(
|
||
|
i0,
|
||
|
i1,
|
||
|
i2
|
||
|
)
|
||
|
);
|
||
|
|
||
|
// Center point on the current triangle
|
||
|
|
||
|
var centroid = new graphics.instance.Vector3()
|
||
|
.add(graphicsGeometry.vertices[i0])
|
||
|
.add(graphicsGeometry.vertices[i1])
|
||
|
.add(graphicsGeometry.vertices[i2])
|
||
|
.divideScalar(3);
|
||
|
|
||
|
// Get the normal from the mesh shape itself
|
||
|
var normal = new this.engine.instance.Vec3();
|
||
|
triangleMeshShape.instance.getNormal(i , normal);
|
||
|
|
||
|
var arrow = new graphics.instance.ArrowHelper(
|
||
|
new graphics.instance.Vector3(
|
||
|
normal.x,
|
||
|
normal.y,
|
||
|
normal.z
|
||
|
),
|
||
|
centroid,
|
||
|
normalLength,
|
||
|
new graphics.instance.Color(
|
||
|
normal.x,
|
||
|
normal.y,
|
||
|
normal.z
|
||
|
)
|
||
|
);
|
||
|
wireframeMesh.add( arrow );
|
||
|
}
|
||
|
|
||
|
wireframeMesh.scale.x = scale.x;
|
||
|
wireframeMesh.scale.y = scale.y;
|
||
|
wireframeMesh.scale.z = scale.z;
|
||
|
|
||
|
return wireframeMesh;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* @param convexPolyMeshShape R3.D3.Shape
|
||
|
* @param normalLength Number
|
||
|
* @param scale R3.API.Vector3
|
||
|
* @param opacity Number
|
||
|
* @param wireframeColor HexCode
|
||
|
* @param graphics THREE
|
||
|
* @returns {THREE.Mesh|this.meshes}
|
||
|
* @constructor
|
||
|
*/
|
||
|
R3.D3.World.prototype.generateWireframeViewConvexPolyMesh = function(
|
||
|
graphics,
|
||
|
convexPolyMeshShape,
|
||
|
normalLength,
|
||
|
scale,
|
||
|
opacity,
|
||
|
wireframeColor
|
||
|
) {
|
||
|
graphics.isNotThreeThrow();
|
||
|
this.engine.isNotCannonThrow();
|
||
|
|
||
|
if(typeof normalLength == 'undefined') {
|
||
|
normalLength = 10;
|
||
|
}
|
||
|
|
||
|
if(typeof scale == 'undefined') {
|
||
|
scale = new graphics.instance.Vector3(1, 1, 1);
|
||
|
}
|
||
|
|
||
|
if(typeof opacity == 'undefined') {
|
||
|
opacity = 0.5;
|
||
|
}
|
||
|
|
||
|
if(typeof wireframeColor == 'undefined') {
|
||
|
wireframeColor = 0xfefefe;
|
||
|
}
|
||
|
|
||
|
|
||
|
var graphicsGeometry = new graphics.instance.Geometry();
|
||
|
var wireframeMesh = new graphics.instance.Mesh(
|
||
|
graphicsGeometry,
|
||
|
new graphics.instance.MeshBasicMaterial({
|
||
|
color: wireframeColor,
|
||
|
wireframe: true,
|
||
|
opacity: opacity
|
||
|
})
|
||
|
);
|
||
|
|
||
|
for(var i = 0, l = convexPolyMeshShape.instance.vertices.length; i < l; i++) {
|
||
|
var vertex = convexPolyMeshShape.instance.vertices[i];
|
||
|
graphicsGeometry.vertices.push(new graphics.instance.Vector3(vertex.x, vertex.y, vertex.z));
|
||
|
}
|
||
|
|
||
|
for(var i = 0, l = convexPolyMeshShape.instance.faces.length; i < l; i++) {
|
||
|
var face = convexPolyMeshShape.instance.faces[i];
|
||
|
|
||
|
var i0 = face[0];
|
||
|
var i1 = face[1];
|
||
|
var i2 = face[2];
|
||
|
|
||
|
graphicsGeometry.faces.push(new graphics.instance.Face3(i0, i1, i2));
|
||
|
|
||
|
// Center point on the current triangle
|
||
|
var centroid = new graphics.instance.Vector3()
|
||
|
.add(graphicsGeometry.vertices[i0])
|
||
|
.add(graphicsGeometry.vertices[i1])
|
||
|
.add(graphicsGeometry.vertices[i2])
|
||
|
.divideScalar(3);
|
||
|
|
||
|
var normalVec3 = convexPolyMeshShape.instance.faceNormals[i];
|
||
|
var normal = new graphics.instance.Vector3(
|
||
|
normalVec3.x,
|
||
|
normalVec3.y,
|
||
|
normalVec3.z
|
||
|
);
|
||
|
|
||
|
var arrow = new graphics.instance.ArrowHelper(
|
||
|
normal,
|
||
|
centroid,
|
||
|
normalLength,
|
||
|
new graphics.instance.Color(
|
||
|
normal.x,
|
||
|
normal.y,
|
||
|
normal.z
|
||
|
)
|
||
|
);
|
||
|
|
||
|
wireframeMesh.add( arrow );
|
||
|
}
|
||
|
|
||
|
wireframeMesh.scale.x = scale.x;
|
||
|
wireframeMesh.scale.y = scale.y;
|
||
|
wireframeMesh.scale.z = scale.z;
|
||
|
|
||
|
return wireframeMesh;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* @param graphics R3.D3.Graphics
|
||
|
* @param graphicsMesh THREE.Mesh
|
||
|
* @param mass Number
|
||
|
* @param friction Number
|
||
|
* @param createCollisionSubMeshes Boolean
|
||
|
* @param facesPerSubsection Number
|
||
|
* @param subsectionsToMerge Number
|
||
|
* @returns {Object}
|
||
|
* @constructor
|
||
|
*/
|
||
|
R3.D3.World.prototype.generateTriangleMeshShapeDivided = function(
|
||
|
graphics,
|
||
|
graphicsMesh,
|
||
|
mass,
|
||
|
friction,
|
||
|
createCollisionSubMeshes,
|
||
|
facesPerSubsection,
|
||
|
subsectionsToMerge
|
||
|
) {
|
||
|
graphics.isNotThreeThrow();
|
||
|
this.engine.isNotCannonThrow();
|
||
|
|
||
|
if(mass == null || typeof mass == 'undefined') {
|
||
|
mass = 0;
|
||
|
}
|
||
|
|
||
|
if(friction == null || typeof friction == 'undefined') {
|
||
|
friction = 10;
|
||
|
}
|
||
|
|
||
|
if(createCollisionSubMeshes == null || typeof createCollisionSubMeshes == 'undefined') {
|
||
|
createCollisionSubMeshes = false;
|
||
|
}
|
||
|
|
||
|
var processedFaces = 0;
|
||
|
var facesPerSubSection = facesPerSubsection || 0;
|
||
|
var subMeshesToMerge = subsectionsToMerge || 0;
|
||
|
var totalAmtFaces = graphicsMesh.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;
|
||
|
|
||
|
var meshShape = new this.engine.instance.Trimesh(vertices, indicies);
|
||
|
|
||
|
meshShape.setScale(new this.engine.instance.Vec3(
|
||
|
graphicsMesh.scale.x,
|
||
|
graphicsMesh.scale.y,
|
||
|
graphicsMesh.scale.z
|
||
|
));
|
||
|
|
||
|
meshShape.updateAABB();
|
||
|
meshShape.updateNormals();
|
||
|
meshShape.updateEdges();
|
||
|
meshShape.updateBoundingSphereRadius();
|
||
|
meshShape.updateTree();
|
||
|
|
||
|
body = new this.engine.instance.Body({
|
||
|
mass: mass,
|
||
|
friction: friction
|
||
|
});
|
||
|
body.addShape(meshShape);
|
||
|
|
||
|
pairs.push({
|
||
|
threeObject : createCollisionSubMeshes ? null : graphicsMesh,
|
||
|
physicsObject : body
|
||
|
});
|
||
|
|
||
|
vertices = [];
|
||
|
indicies = [];
|
||
|
processedFaces = 0;
|
||
|
|
||
|
if(i == totalAmtFaces) {
|
||
|
return pairs;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var face = graphicsMesh.geometry.faces[i];
|
||
|
indicies.push(indicies.length);
|
||
|
indicies.push(indicies.length);
|
||
|
indicies.push(indicies.length);
|
||
|
|
||
|
var v0 = graphicsMesh.geometry.vertices[face.a];
|
||
|
var v1 = graphicsMesh.geometry.vertices[face.b];
|
||
|
var v2 = graphicsMesh.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++;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
R3.D3.World.prototype.generateConvexPolyShape = function(
|
||
|
graphics,
|
||
|
mesh
|
||
|
) {
|
||
|
var processedFaces = 0;
|
||
|
var facesPerSubSection = 2; // *2 -> SUBDIVISION MESH
|
||
|
var subMeshesToMerge = 4; // *2 -> SUBDIVISION MESH
|
||
|
var facesToProcess = subMeshesToMerge * facesPerSubSection;
|
||
|
|
||
|
var vertices = [];
|
||
|
var indicies = [];
|
||
|
|
||
|
for(var i = 0; i <= mesh.geometry.faces.length; i++) {
|
||
|
if(processedFaces == facesToProcess || i == mesh.geometry.faces.length) {
|
||
|
|
||
|
// try and create convex poly...........
|
||
|
var convexIndices = [];
|
||
|
for(var index = 0; index < indicies.length / 3; index++) {
|
||
|
convexIndices.push([ indicies[index * 3], indicies[index * 3 + 1], indicies[index * 3 + 2] ]);
|
||
|
}
|
||
|
|
||
|
var convexVertices = [];
|
||
|
for(var vert = 0; vert < vertices.length / 3; vert++) {
|
||
|
convexVertices[vert] = new CANNON.Vec3(vertices[vert * 3] * mesh.scale.x, vertices[vert * 3 + 1] * mesh.scale.y, vertices[vert * 3 + 2] * mesh.scale.z);
|
||
|
}
|
||
|
|
||
|
var meshShape = new R3.D3.Shape(this.engine, R3.D3.Shape.SHAPE_TYPE_CONVEX_HULL, {x:1,y:1,z:1},convexVertices, convexIndices);
|
||
|
|
||
|
var body = new R3.D3.RigidBody(this.engine, 0, 1);
|
||
|
body.addShape(meshShape);
|
||
|
|
||
|
this.addRigidBody(body);
|
||
|
|
||
|
vertices = [];
|
||
|
indicies = [];
|
||
|
processedFaces = 0;
|
||
|
|
||
|
console.log("SPLIT MESH TO CONVEX POLY");
|
||
|
|
||
|
if(i == mesh.geometry.faces.length) {
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var face = mesh.geometry.faces[i];
|
||
|
indicies.push(indicies.length);
|
||
|
indicies.push(indicies.length);
|
||
|
indicies.push(indicies.length);
|
||
|
|
||
|
var v0 = mesh.geometry.vertices[face.a];
|
||
|
var v1 = mesh.geometry.vertices[face.b];
|
||
|
var v2 = mesh.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++;
|
||
|
}
|
||
|
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* @param graphics R3.D3.Graphics
|
||
|
* @param graphicsMesh THREE.Mesh
|
||
|
* @returns {R3.D3.Shape}
|
||
|
* @constructor
|
||
|
*/
|
||
|
R3.D3.World.prototype.generateTriangleMeshShape = function(
|
||
|
graphics,
|
||
|
graphicsMesh
|
||
|
) {
|
||
|
|
||
|
// - - - - - - - - - - - - - - - - - - - - - - - - -
|
||
|
// Note: I did not test this yet with the API data.
|
||
|
// - - - - - - - - - - - - - - - - - - - - - - - - -
|
||
|
|
||
|
var scaledVertices = [];
|
||
|
for(var i = 0, l = graphicsMesh.geometry.vertices.length; i < l; i++) {
|
||
|
|
||
|
var vertex = graphicsMesh.geometry.vertices[i];
|
||
|
|
||
|
scaledVertices.push(new this.engine.instance.Vec3(
|
||
|
vertex.x * graphicsMesh.scale.x,
|
||
|
vertex.y * graphicsMesh.scale.y,
|
||
|
vertex.z * graphicsMesh.scale.z
|
||
|
));
|
||
|
}
|
||
|
|
||
|
var triangleFaces = [];
|
||
|
for(var f = 0, fl = graphicsMesh.geometry.faces.length; f < fl; f++) {
|
||
|
var i0 = graphicsMesh.geometry.faces[f].a;
|
||
|
var i1 = graphicsMesh.geometry.faces[f].b;
|
||
|
var i2 = graphicsMesh.geometry.faces[f].c;
|
||
|
|
||
|
triangleFaces.push([
|
||
|
i0, i1, i2
|
||
|
]);
|
||
|
}
|
||
|
|
||
|
// - - - - - - - - - - - - - - - - - - -
|
||
|
// Create collision mesh
|
||
|
// - - - - - - - - - - - - - - - - - - -
|
||
|
|
||
|
var reindexedFaces = {};
|
||
|
var vertices = [];
|
||
|
var faces = [];
|
||
|
|
||
|
var processedFaces = 0;
|
||
|
var totalFacesToProcess = triangleFaces.length;
|
||
|
var flLastIndex = 0;
|
||
|
|
||
|
for(var f = 0; f < totalFacesToProcess; f++) {
|
||
|
|
||
|
var i0 = triangleFaces[f][0];
|
||
|
var i1 = triangleFaces[f][1];
|
||
|
var i2 = triangleFaces[f][2];
|
||
|
|
||
|
if(typeof reindexedFaces[i0] === 'undefined') {
|
||
|
vertices.push(scaledVertices[i0].x, scaledVertices[i0].y, scaledVertices[i0].z);
|
||
|
reindexedFaces[i0] = flLastIndex;
|
||
|
flLastIndex++;
|
||
|
}
|
||
|
|
||
|
if(typeof reindexedFaces[i1] === 'undefined') {
|
||
|
vertices.push(scaledVertices[i1].x, scaledVertices[i1].y, scaledVertices[i1].z);
|
||
|
reindexedFaces[i1] = flLastIndex;
|
||
|
flLastIndex++;
|
||
|
}
|
||
|
|
||
|
if(typeof reindexedFaces[i2] === 'undefined') {
|
||
|
vertices.push(scaledVertices[i2].x, scaledVertices[i2].y, scaledVertices[i2].z);
|
||
|
reindexedFaces[i2] = flLastIndex;
|
||
|
flLastIndex++;
|
||
|
}
|
||
|
|
||
|
faces.push(reindexedFaces[i0], reindexedFaces[i1], reindexedFaces[i2]);
|
||
|
|
||
|
processedFaces++;
|
||
|
}
|
||
|
|
||
|
return new R3.D3.Shape(this.engine, R3.D3.Shape.SHAPE_TYPE_TRIMESH, {x : 1, y : 1, z : 1}, vertices, faces);
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* @param triangleMeshBody R3.D3.RigidBody
|
||
|
* @param rayscale Number
|
||
|
* @param maxTriangleDistance Number
|
||
|
* @param createCompoundShape Boolean
|
||
|
* @param graphics R3.D3.Graphics
|
||
|
* @param triangleMeshShapes R3.D3.Shape[]
|
||
|
* @param createDebugView Boolean
|
||
|
* @returns {R3.D3.RigidBody}
|
||
|
* @constructor
|
||
|
*/
|
||
|
R3.D3.World.prototype.fixupTriangleMeshShape = function(
|
||
|
triangleMeshBody,
|
||
|
triangleMeshShapes,
|
||
|
rayscale,
|
||
|
maxTriangleDistance,
|
||
|
createCompoundShape,
|
||
|
graphics,
|
||
|
createDebugView
|
||
|
) {
|
||
|
this.engine.isNotCannonThrow();
|
||
|
|
||
|
graphics.isNotThreeThrow();
|
||
|
|
||
|
if(rayscale == null || typeof rayscale == 'undefined' || rayscale == 0) {
|
||
|
rayscale = 10;
|
||
|
}
|
||
|
|
||
|
if(maxTriangleDistance == null || typeof maxTriangleDistance == 'undefined') {
|
||
|
maxTriangleDistance = 13;
|
||
|
}
|
||
|
|
||
|
var world = this.instance;
|
||
|
|
||
|
var raycastResult = new this.engine.instance.RaycastResult();
|
||
|
|
||
|
var brokenFaceIndicators = [];
|
||
|
|
||
|
var totalFaces = 0;
|
||
|
var totalBrokenFaces = 0;
|
||
|
var totalFixedFaces = 0;
|
||
|
var fixedTriangleMeshObjects = [];
|
||
|
|
||
|
for(var i in triangleMeshShapes) {
|
||
|
var trimesh = triangleMeshShapes[i].instance;
|
||
|
|
||
|
var brokenFaces = [];
|
||
|
totalFaces += (trimesh.indices.length / 3);
|
||
|
|
||
|
for(var face = 0; face < trimesh.indices.length / 3; face++) {
|
||
|
|
||
|
var i0 = trimesh.indices[face * 3];
|
||
|
var i1 = trimesh.indices[face * 3 + 1];
|
||
|
var i2 = trimesh.indices[face * 3 + 2];
|
||
|
|
||
|
var triangleCenterPoint = new graphics.instance.Vector3()
|
||
|
.add(new graphics.instance.Vector3(
|
||
|
trimesh.vertices[i0 * 3],
|
||
|
trimesh.vertices[i0 * 3 + 1],
|
||
|
trimesh.vertices[i0 * 3 + 2])
|
||
|
)
|
||
|
.add(new graphics.instance.Vector3(
|
||
|
trimesh.vertices[i1 * 3],
|
||
|
trimesh.vertices[i1 * 3 + 1],
|
||
|
trimesh.vertices[i1 * 3 + 2])
|
||
|
)
|
||
|
.add(new graphics.instance.Vector3(
|
||
|
trimesh.vertices[i2 * 3],
|
||
|
trimesh.vertices[i2 * 3 + 1],
|
||
|
trimesh.vertices[i2 * 3 + 2])
|
||
|
)
|
||
|
.divideScalar(3);
|
||
|
|
||
|
var triangleNormal = new this.engine.instance.Vec3();
|
||
|
trimesh.getNormal(face , triangleNormal);
|
||
|
|
||
|
var from = new this.engine.instance.Vec3(
|
||
|
triangleCenterPoint.x + triangleNormal.x,
|
||
|
triangleCenterPoint.y + triangleNormal.y,
|
||
|
triangleCenterPoint.z + triangleNormal.z
|
||
|
);
|
||
|
|
||
|
var to = new this.engine.instance.Vec3(
|
||
|
from.x - triangleNormal.x * rayscale,
|
||
|
from.y - triangleNormal.y * rayscale,
|
||
|
from.z - triangleNormal.z * rayscale
|
||
|
);
|
||
|
|
||
|
world.raycastClosest(from, to, {}, raycastResult);
|
||
|
|
||
|
// visualize results
|
||
|
if(createDebugView){
|
||
|
var graphicsGeometry = new graphics.instance.Geometry();
|
||
|
var wireframeMesh = new graphics.instance.Mesh(
|
||
|
graphicsGeometry,
|
||
|
new graphics.instance.MeshBasicMaterial({
|
||
|
color: 0xff0000,
|
||
|
wireframe: true,
|
||
|
opacity: 1
|
||
|
})
|
||
|
);
|
||
|
|
||
|
var arrow = new graphics.instance.ArrowHelper(
|
||
|
new graphics.instance.Vector3(
|
||
|
triangleNormal.x,
|
||
|
triangleNormal.y,
|
||
|
triangleNormal.z
|
||
|
).normalize(),
|
||
|
|
||
|
new graphics.instance.Vector3(
|
||
|
from.x,
|
||
|
from.y,
|
||
|
from.z
|
||
|
),
|
||
|
|
||
|
rayscale / 2,
|
||
|
raycastResult.hasHit ? new graphics.instance.Color(0, 1, 0)
|
||
|
: new graphics.instance.Color(1, 0, 0)
|
||
|
);
|
||
|
|
||
|
wireframeMesh.add( arrow );
|
||
|
brokenFaceIndicators.push(wireframeMesh);
|
||
|
}
|
||
|
|
||
|
if(!raycastResult.hasHit) {
|
||
|
brokenFaces.push({
|
||
|
faceIndex : face,
|
||
|
|
||
|
vertices : [
|
||
|
new this.engine.instance.Vec3(
|
||
|
trimesh.vertices[i0 * 3],
|
||
|
trimesh.vertices[i0 * 3 + 1],
|
||
|
trimesh.vertices[i0 * 3 + 2]
|
||
|
),
|
||
|
|
||
|
new this.engine.instance.Vec3(
|
||
|
trimesh.vertices[i1 * 3],
|
||
|
trimesh.vertices[i1 * 3 + 1],
|
||
|
trimesh.vertices[i1 * 3 + 2]
|
||
|
),
|
||
|
|
||
|
new this.engine.instance.Vec3(
|
||
|
trimesh.vertices[i2 * 3],
|
||
|
trimesh.vertices[i2 * 3 + 1],
|
||
|
trimesh.vertices[i2 * 3 + 2]
|
||
|
)
|
||
|
],
|
||
|
|
||
|
center : triangleCenterPoint,
|
||
|
|
||
|
parent : trimesh
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// fix up broken faces
|
||
|
|
||
|
var bFaceIndexed = {};
|
||
|
for(var b = 0; b < brokenFaces.length; b++) {
|
||
|
var brokenFace = brokenFaces[b];
|
||
|
|
||
|
if(brokenFace.marked) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
bFaceIndexed[b] = {
|
||
|
indices : [],
|
||
|
vertices : []
|
||
|
};
|
||
|
|
||
|
var indicesAmount = bFaceIndexed[b].indices.length;
|
||
|
|
||
|
// add the current broken face itself to the array
|
||
|
bFaceIndexed[b].indices.push(
|
||
|
indicesAmount,
|
||
|
indicesAmount + 1,
|
||
|
indicesAmount + 2
|
||
|
);
|
||
|
|
||
|
bFaceIndexed[b].vertices.push(
|
||
|
brokenFace.vertices[0].x,
|
||
|
brokenFace.vertices[0].y,
|
||
|
brokenFace.vertices[0].z
|
||
|
);
|
||
|
|
||
|
bFaceIndexed[b].vertices.push(
|
||
|
brokenFace.vertices[1].x,
|
||
|
brokenFace.vertices[1].y,
|
||
|
brokenFace.vertices[1].z
|
||
|
);
|
||
|
|
||
|
bFaceIndexed[b].vertices.push(
|
||
|
brokenFace.vertices[2].x,
|
||
|
brokenFace.vertices[2].y,
|
||
|
brokenFace.vertices[2].z
|
||
|
);
|
||
|
|
||
|
for(var bb = 0; bb < brokenFaces.length; bb++) {
|
||
|
|
||
|
if(bb == b) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
var otherBrokenFace = brokenFaces[bb];
|
||
|
|
||
|
if(otherBrokenFace.marked) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if(brokenFace.center.distanceTo(otherBrokenFace.center) <= maxTriangleDistance) {
|
||
|
var indicesAmount = bFaceIndexed[b].indices.length;
|
||
|
|
||
|
bFaceIndexed[b].indices.push(
|
||
|
indicesAmount,
|
||
|
indicesAmount + 1,
|
||
|
indicesAmount + 2
|
||
|
);
|
||
|
|
||
|
bFaceIndexed[b].vertices.push(
|
||
|
otherBrokenFace.vertices[0].x,
|
||
|
otherBrokenFace.vertices[0].y,
|
||
|
otherBrokenFace.vertices[0].z
|
||
|
);
|
||
|
|
||
|
bFaceIndexed[b].vertices.push(
|
||
|
otherBrokenFace.vertices[1].x,
|
||
|
otherBrokenFace.vertices[1].y,
|
||
|
otherBrokenFace.vertices[1].z
|
||
|
);
|
||
|
|
||
|
bFaceIndexed[b].vertices.push(
|
||
|
otherBrokenFace.vertices[2].x,
|
||
|
otherBrokenFace.vertices[2].y,
|
||
|
otherBrokenFace.vertices[2].z
|
||
|
);
|
||
|
|
||
|
otherBrokenFace.marked = true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||
|
// Decide if we want to create new rigiwyd bodies, or create a compound mesh
|
||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||
|
|
||
|
for(var e in bFaceIndexed) {
|
||
|
var element = bFaceIndexed[e];
|
||
|
|
||
|
var shape = new R3.D3.Shape(this.engine, R3.D3.Shape.SHAPE_TYPE_TRIMESH, { x : 1, y : 1, z : 1 }, element.vertices, element.indices);
|
||
|
|
||
|
if(createCompoundShape) {
|
||
|
triangleMeshBody.addShape(shape);
|
||
|
} else {
|
||
|
|
||
|
var body = new R3.D3.RigidBody(this.engine, 0, 12);
|
||
|
|
||
|
//TODO: this is just a hack.
|
||
|
body.instance.collisionFilterGroup = 1 | 2; // puts this body in two groups.
|
||
|
|
||
|
body.addShape(shape);
|
||
|
this.addRigidBody(body);
|
||
|
}
|
||
|
|
||
|
fixedTriangleMeshObjects.push(shape);
|
||
|
totalFixedFaces += element.indices.length / 3;
|
||
|
}
|
||
|
|
||
|
// TODO: remove duplicate indices
|
||
|
/*trimesh.updateNormals();
|
||
|
trimesh.updateEdges();
|
||
|
trimesh.updateTree();
|
||
|
trimesh.updateAABB();
|
||
|
trimesh.updateBoundingSphereRadius();*/
|
||
|
|
||
|
// map faceIndex to flat face index (faceIndex * 3) +0, 1, 2 -> triangle indices
|
||
|
console.log("i = " + i, brokenFaces);
|
||
|
totalBrokenFaces += brokenFaces.length;
|
||
|
}
|
||
|
|
||
|
console.log("total faces", totalFaces);
|
||
|
console.log("total broken faces", totalBrokenFaces);
|
||
|
console.log("broken faces in percent", (totalBrokenFaces / totalFaces) * 100);
|
||
|
console.log("total fixed faces", totalFixedFaces);
|
||
|
console.log("fixed triangle mesh shapes", fixedTriangleMeshObjects.length);
|
||
|
|
||
|
return {
|
||
|
brokenFaceIndicators : brokenFaceIndicators,
|
||
|
fixedTriangleMeshShapes : fixedTriangleMeshObjects
|
||
|
};
|
||
|
};
|