debugviews, triangle & convex hull collision shape generation, ray cast fixup for triangle meshes
parent
4ba7a43d0a
commit
318500d9b0
|
@ -5037,97 +5037,248 @@ GameLib.D3.World.prototype.GetIndexedVertices = function(
|
|||
};
|
||||
|
||||
/**
|
||||
* TODO: FIX
|
||||
* @param triangleMeshShape
|
||||
* @param normalLength
|
||||
* @param scale
|
||||
* @param opacity
|
||||
* @param wireframeColor
|
||||
* @param triangleMeshShape GameLib.D3.Shape
|
||||
* @param normalLength Number
|
||||
* @param scale GameLib.D3.Vector3
|
||||
* @param opacity Number
|
||||
* @param wireframeColor HexCode
|
||||
* @param graphics THREE
|
||||
* @returns {THREE.Mesh|this.meshes}
|
||||
* @constructor
|
||||
*/
|
||||
GameLib.D3.World.GenerateWireframeViewMesh = function(
|
||||
GameLib.D3.World.prototype.generateWireframeViewTriangleMesh = function(
|
||||
graphics,
|
||||
triangleMeshShape,
|
||||
normalLength,
|
||||
scale,
|
||||
opacity,
|
||||
wireframeColor
|
||||
) {
|
||||
var geometryTHREE = new THREE.Geometry();
|
||||
var wireframeTHREEMesh = new THREE.Mesh
|
||||
(
|
||||
geometryTHREE,
|
||||
new THREE.MeshBasicMaterial({
|
||||
color: wireframeColor ? wireframeColor : 0xfefefe,
|
||||
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 ? opacity : 0.5
|
||||
opacity: opacity
|
||||
})
|
||||
);
|
||||
|
||||
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 = triangleMeshShape.instance.vertices.length / 3; i < l; ++i) {
|
||||
graphicsGeometry.vertices.push(
|
||||
new graphics.instance.Vector3(
|
||||
triangleMeshShape.instance.vertices[i * 3],
|
||||
triangleMeshShape.instance.vertices[i * 3 + 1],
|
||||
triangleMeshShape.instance.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];
|
||||
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];
|
||||
|
||||
geometryTHREE.faces.push(new THREE.Face3(i0, i1, i2));
|
||||
graphicsGeometry.faces.push(
|
||||
new graphics.instance.Face3(
|
||||
i0,
|
||||
i1,
|
||||
i2
|
||||
)
|
||||
);
|
||||
|
||||
// Create debug view for normals
|
||||
// Center point on the current triangle
|
||||
|
||||
// Center point on the mesh itself
|
||||
var centroid = new THREE.Vector3()
|
||||
.add(geometryTHREE.vertices[i0])
|
||||
.add(geometryTHREE.vertices[i1])
|
||||
.add(geometryTHREE.vertices[i2])
|
||||
var centroid = new graphics.instance.Vector3()
|
||||
.add(graphicsGeometry.vertices[i0])
|
||||
.add(graphicsGeometry.vertices[i1])
|
||||
.add(graphicsGeometry.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.
|
||||
// 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 );
|
||||
}
|
||||
|
||||
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 );
|
||||
}
|
||||
wireframeMesh.scale.x = scale.x;
|
||||
wireframeMesh.scale.y = scale.y;
|
||||
wireframeMesh.scale.z = scale.z;
|
||||
|
||||
wireframeTHREEMesh.scale.x = scale.x;
|
||||
wireframeTHREEMesh.scale.y = scale.y;
|
||||
wireframeTHREEMesh.scale.z = scale.z;
|
||||
|
||||
return wireframeTHREEMesh;
|
||||
return wireframeMesh;
|
||||
};
|
||||
|
||||
/**
|
||||
* TODO: FIX
|
||||
* @param threeMesh
|
||||
* @param mass
|
||||
* @param friction
|
||||
* @param createCollisionSubMeshes
|
||||
* @param facesPerSubsection
|
||||
* @param subsectionsToMerge
|
||||
* @returns {Array}
|
||||
* @param convexPolyMeshShape GameLib.D3.Shape
|
||||
* @param normalLength Number
|
||||
* @param scale GameLib.D3.Vector3
|
||||
* @param opacity Number
|
||||
* @param wireframeColor HexCode
|
||||
* @param graphics THREE
|
||||
* @returns {THREE.Mesh|this.meshes}
|
||||
* @constructor
|
||||
*/
|
||||
GameLib.D3.World.GenerateTriangleCollisionMesh = function(
|
||||
threeMesh,
|
||||
mass, // default = 0
|
||||
friction, // default = 10
|
||||
createCollisionSubMeshes, // boolean. default = false
|
||||
facesPerSubsection, // int. default = 0
|
||||
subsectionsToMerge // int. default = 0
|
||||
GameLib.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 GameLib.D3.Graphics
|
||||
* @param graphicsMesh THREE.Mesh
|
||||
* @param mass Number
|
||||
* @param friction Number
|
||||
* @param createCollisionSubMeshes Boolean
|
||||
* @param facesPerSubsection Number
|
||||
* @param subsectionsToMerge Number
|
||||
* @returns {Object}
|
||||
* @constructor
|
||||
*/
|
||||
GameLib.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 = threeMesh.geometry.faces.length;
|
||||
var totalAmtFaces = graphicsMesh.geometry.faces.length;
|
||||
var facesToProcess = createCollisionSubMeshes ? (subMeshesToMerge * facesPerSubSection) : totalAmtFaces;
|
||||
|
||||
var pairs = []; // output
|
||||
|
@ -5140,27 +5291,28 @@ GameLib.D3.World.GenerateTriangleCollisionMesh = function(
|
|||
|
||||
var body = null;
|
||||
|
||||
if(this.engine.engineType == GameLib.D3.Physics.TYPE_CANNON) {
|
||||
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
|
||||
));
|
||||
|
||||
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 = new this.engine.instance.Body({
|
||||
mass: mass,
|
||||
friction: friction
|
||||
});
|
||||
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,
|
||||
threeObject : createCollisionSubMeshes ? null : graphicsMesh,
|
||||
physicsObject : body
|
||||
});
|
||||
|
||||
|
@ -5173,14 +5325,14 @@ GameLib.D3.World.GenerateTriangleCollisionMesh = function(
|
|||
}
|
||||
}
|
||||
|
||||
var face = threeMesh.geometry.faces[i];
|
||||
var face = graphicsMesh.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];
|
||||
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);
|
||||
|
@ -5190,6 +5342,395 @@ GameLib.D3.World.GenerateTriangleCollisionMesh = function(
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @param graphics GameLib.D3.Graphics
|
||||
* @param graphicsMesh THREE.Mesh
|
||||
* @returns {GameLib.D3.RigidBody}
|
||||
* @constructor
|
||||
*/
|
||||
GameLib.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++;
|
||||
}
|
||||
|
||||
var shape = GameLib.D3.Shape(this.engine, GameLib.D3.Shape.SHAPE_TYPE_TRIMESH, graphicsMesh.scale, vertices, faces);
|
||||
var body = GameLib.D3.RigidBody(this.engine, 0, 12);
|
||||
|
||||
body.addShape(shape);
|
||||
this.addRigidBody(body);
|
||||
|
||||
// process the mesh children recursively
|
||||
for(var c in graphicsMesh.children) {
|
||||
this.generateTriangleMeshShape(graphics, graphicsMesh.children[c]);
|
||||
}
|
||||
|
||||
return body;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param triangleMeshBody GameLib.D3.RigidBody
|
||||
* @param rayscale Number
|
||||
* @param maxTriangleDistance Number
|
||||
* @param createCompoundShape Boolean
|
||||
* @param graphics GameLib.D3.Graphics
|
||||
* @param triangleMeshShapes GameLib.D3.Shape[]
|
||||
* @param createDebugView Boolean
|
||||
* @returns {GameLib.D3.RigidBody}
|
||||
* @constructor
|
||||
*/
|
||||
GameLib.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 wireframeMeshes = [];
|
||||
|
||||
var totalFaces = 0;
|
||||
var totalBrokenFaces = 0;
|
||||
var totalFixedFaces = 0;
|
||||
var fixedTriangleMeshObjects = [];
|
||||
|
||||
for(var i in triangleMeshShapes) {
|
||||
var trimesh = triangleMeshShapes[i];
|
||||
|
||||
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 );
|
||||
|
||||
wireframeMeshes.add(wireframeMesh);
|
||||
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 rigid bodies, or create a compound mesh
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
for(var e in bFaceIndexed) {
|
||||
var element = bFaceIndexed[e];
|
||||
|
||||
var shape = new GameLib.D3.Shape(this.engine, GameLib.D3.Shape.SHAPE_TYPE_TRIMESH, null, element.vertices, element.indices);
|
||||
|
||||
if(createCompoundShape) {
|
||||
triangleMeshBody.addShape(shape);
|
||||
} else {
|
||||
|
||||
var body = new GameLib.D3.RigidBody(this.engine, 0, 12);
|
||||
body.addShape(shape);
|
||||
this.instance.addRigidBody(body);
|
||||
}
|
||||
|
||||
fixedTriangleMeshObjects.push(shape);
|
||||
totalFixedFaces += element.indices.length / 3;
|
||||
|
||||
console.log("created mesh shape", 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,
|
||||
wireframeMeshes : wireframeMeshes
|
||||
};
|
||||
};
|
||||
if (typeof module !== 'undefined') {
|
||||
module.exports = GameLib;
|
||||
}
|
|
@ -142,97 +142,248 @@ GameLib.D3.World.prototype.GetIndexedVertices = function(
|
|||
};
|
||||
|
||||
/**
|
||||
* TODO: FIX
|
||||
* @param triangleMeshShape
|
||||
* @param normalLength
|
||||
* @param scale
|
||||
* @param opacity
|
||||
* @param wireframeColor
|
||||
* @param triangleMeshShape GameLib.D3.Shape
|
||||
* @param normalLength Number
|
||||
* @param scale GameLib.D3.Vector3
|
||||
* @param opacity Number
|
||||
* @param wireframeColor HexCode
|
||||
* @param graphics THREE
|
||||
* @returns {THREE.Mesh|this.meshes}
|
||||
* @constructor
|
||||
*/
|
||||
GameLib.D3.World.GenerateWireframeViewMesh = function(
|
||||
GameLib.D3.World.prototype.generateWireframeViewTriangleMesh = function(
|
||||
graphics,
|
||||
triangleMeshShape,
|
||||
normalLength,
|
||||
scale,
|
||||
opacity,
|
||||
wireframeColor
|
||||
) {
|
||||
var geometryTHREE = new THREE.Geometry();
|
||||
var wireframeTHREEMesh = new THREE.Mesh
|
||||
(
|
||||
geometryTHREE,
|
||||
new THREE.MeshBasicMaterial({
|
||||
color: wireframeColor ? wireframeColor : 0xfefefe,
|
||||
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 ? opacity : 0.5
|
||||
opacity: opacity
|
||||
})
|
||||
);
|
||||
|
||||
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 = triangleMeshShape.instance.vertices.length / 3; i < l; ++i) {
|
||||
graphicsGeometry.vertices.push(
|
||||
new graphics.instance.Vector3(
|
||||
triangleMeshShape.instance.vertices[i * 3],
|
||||
triangleMeshShape.instance.vertices[i * 3 + 1],
|
||||
triangleMeshShape.instance.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];
|
||||
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];
|
||||
|
||||
geometryTHREE.faces.push(new THREE.Face3(i0, i1, i2));
|
||||
graphicsGeometry.faces.push(
|
||||
new graphics.instance.Face3(
|
||||
i0,
|
||||
i1,
|
||||
i2
|
||||
)
|
||||
);
|
||||
|
||||
// Create debug view for normals
|
||||
// Center point on the current triangle
|
||||
|
||||
// Center point on the mesh itself
|
||||
var centroid = new THREE.Vector3()
|
||||
.add(geometryTHREE.vertices[i0])
|
||||
.add(geometryTHREE.vertices[i1])
|
||||
.add(geometryTHREE.vertices[i2])
|
||||
var centroid = new graphics.instance.Vector3()
|
||||
.add(graphicsGeometry.vertices[i0])
|
||||
.add(graphicsGeometry.vertices[i1])
|
||||
.add(graphicsGeometry.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.
|
||||
// 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 );
|
||||
}
|
||||
|
||||
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 );
|
||||
}
|
||||
wireframeMesh.scale.x = scale.x;
|
||||
wireframeMesh.scale.y = scale.y;
|
||||
wireframeMesh.scale.z = scale.z;
|
||||
|
||||
wireframeTHREEMesh.scale.x = scale.x;
|
||||
wireframeTHREEMesh.scale.y = scale.y;
|
||||
wireframeTHREEMesh.scale.z = scale.z;
|
||||
|
||||
return wireframeTHREEMesh;
|
||||
return wireframeMesh;
|
||||
};
|
||||
|
||||
/**
|
||||
* TODO: FIX
|
||||
* @param threeMesh
|
||||
* @param mass
|
||||
* @param friction
|
||||
* @param createCollisionSubMeshes
|
||||
* @param facesPerSubsection
|
||||
* @param subsectionsToMerge
|
||||
* @returns {Array}
|
||||
* @param convexPolyMeshShape GameLib.D3.Shape
|
||||
* @param normalLength Number
|
||||
* @param scale GameLib.D3.Vector3
|
||||
* @param opacity Number
|
||||
* @param wireframeColor HexCode
|
||||
* @param graphics THREE
|
||||
* @returns {THREE.Mesh|this.meshes}
|
||||
* @constructor
|
||||
*/
|
||||
GameLib.D3.World.GenerateTriangleCollisionMesh = function(
|
||||
threeMesh,
|
||||
mass, // default = 0
|
||||
friction, // default = 10
|
||||
createCollisionSubMeshes, // boolean. default = false
|
||||
facesPerSubsection, // int. default = 0
|
||||
subsectionsToMerge // int. default = 0
|
||||
GameLib.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 GameLib.D3.Graphics
|
||||
* @param graphicsMesh THREE.Mesh
|
||||
* @param mass Number
|
||||
* @param friction Number
|
||||
* @param createCollisionSubMeshes Boolean
|
||||
* @param facesPerSubsection Number
|
||||
* @param subsectionsToMerge Number
|
||||
* @returns {Object}
|
||||
* @constructor
|
||||
*/
|
||||
GameLib.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 = threeMesh.geometry.faces.length;
|
||||
var totalAmtFaces = graphicsMesh.geometry.faces.length;
|
||||
var facesToProcess = createCollisionSubMeshes ? (subMeshesToMerge * facesPerSubSection) : totalAmtFaces;
|
||||
|
||||
var pairs = []; // output
|
||||
|
@ -245,27 +396,28 @@ GameLib.D3.World.GenerateTriangleCollisionMesh = function(
|
|||
|
||||
var body = null;
|
||||
|
||||
if(this.engine.engineType == GameLib.D3.Physics.TYPE_CANNON) {
|
||||
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
|
||||
));
|
||||
|
||||
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 = new this.engine.instance.Body({
|
||||
mass: mass,
|
||||
friction: friction
|
||||
});
|
||||
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,
|
||||
threeObject : createCollisionSubMeshes ? null : graphicsMesh,
|
||||
physicsObject : body
|
||||
});
|
||||
|
||||
|
@ -278,14 +430,14 @@ GameLib.D3.World.GenerateTriangleCollisionMesh = function(
|
|||
}
|
||||
}
|
||||
|
||||
var face = threeMesh.geometry.faces[i];
|
||||
var face = graphicsMesh.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];
|
||||
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);
|
||||
|
@ -294,3 +446,393 @@ GameLib.D3.World.GenerateTriangleCollisionMesh = function(
|
|||
processedFaces++;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @param graphics GameLib.D3.Graphics
|
||||
* @param graphicsMesh THREE.Mesh
|
||||
* @returns {GameLib.D3.RigidBody}
|
||||
* @constructor
|
||||
*/
|
||||
GameLib.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++;
|
||||
}
|
||||
|
||||
var shape = GameLib.D3.Shape(this.engine, GameLib.D3.Shape.SHAPE_TYPE_TRIMESH, graphicsMesh.scale, vertices, faces);
|
||||
var body = GameLib.D3.RigidBody(this.engine, 0, 12);
|
||||
|
||||
body.addShape(shape);
|
||||
this.addRigidBody(body);
|
||||
|
||||
// process the mesh children recursively
|
||||
for(var c in graphicsMesh.children) {
|
||||
this.generateTriangleMeshShape(graphics, graphicsMesh.children[c]);
|
||||
}
|
||||
|
||||
return body;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param triangleMeshBody GameLib.D3.RigidBody
|
||||
* @param rayscale Number
|
||||
* @param maxTriangleDistance Number
|
||||
* @param createCompoundShape Boolean
|
||||
* @param graphics GameLib.D3.Graphics
|
||||
* @param triangleMeshShapes GameLib.D3.Shape[]
|
||||
* @param createDebugView Boolean
|
||||
* @returns {GameLib.D3.RigidBody}
|
||||
* @constructor
|
||||
*/
|
||||
GameLib.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 wireframeMeshes = [];
|
||||
|
||||
var totalFaces = 0;
|
||||
var totalBrokenFaces = 0;
|
||||
var totalFixedFaces = 0;
|
||||
var fixedTriangleMeshObjects = [];
|
||||
|
||||
for(var i in triangleMeshShapes) {
|
||||
var trimesh = triangleMeshShapes[i];
|
||||
|
||||
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 );
|
||||
|
||||
wireframeMeshes.add(wireframeMesh);
|
||||
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 rigid bodies, or create a compound mesh
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
for(var e in bFaceIndexed) {
|
||||
var element = bFaceIndexed[e];
|
||||
|
||||
var shape = new GameLib.D3.Shape(this.engine, GameLib.D3.Shape.SHAPE_TYPE_TRIMESH, null, element.vertices, element.indices);
|
||||
|
||||
if(createCompoundShape) {
|
||||
triangleMeshBody.addShape(shape);
|
||||
} else {
|
||||
|
||||
var body = new GameLib.D3.RigidBody(this.engine, 0, 12);
|
||||
body.addShape(shape);
|
||||
this.instance.addRigidBody(body);
|
||||
}
|
||||
|
||||
fixedTriangleMeshObjects.push(shape);
|
||||
totalFixedFaces += element.indices.length / 3;
|
||||
|
||||
console.log("created mesh shape", 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,
|
||||
wireframeMeshes : wireframeMeshes
|
||||
};
|
||||
};
|
Loading…
Reference in New Issue