diff --git a/source/export/exporterply.js b/source/export/exporterply.js index cad1775..465a1bc 100644 --- a/source/export/exporterply.js +++ b/source/export/exporterply.js @@ -49,7 +49,6 @@ OV.ExporterPly = class extends OV.ExporterBase let plyFile = new OV.ExportedFile ('model.ply'); files.push (plyFile); - let vertexCount = model.VertexCount (); let triangleCount = model.TriangleCount (); let headerText = this.GetHeaderText ('binary_little_endian', vertexCount, triangleCount); diff --git a/source/model/mesh.js b/source/model/mesh.js index 7da4b51..10b41b8 100644 --- a/source/model/mesh.js +++ b/source/model/mesh.js @@ -95,10 +95,10 @@ OV.Mesh = class extends OV.ModelObject3D } } - EnumerateTriangles (onTriangle) + EnumerateTriangleVertexIndices (onTriangleVertexIndices) { for (const triangle of this.triangles) { - onTriangle (triangle); + onTriangleVertexIndices (triangle.v0, triangle.v1, triangle.v2); } } diff --git a/source/model/meshinstance.js b/source/model/meshinstance.js index f4c96f4..4bcdbdf 100644 --- a/source/model/meshinstance.js +++ b/source/model/meshinstance.js @@ -29,24 +29,32 @@ OV.MeshInstance = class extends OV.Object3D EnumerateVertices (onVertex) { - this.mesh.EnumerateVertices ((vertex) => { - const transformed = this.transformation.TransformCoord3D (vertex); - onVertex (transformed); - }); + if (this.transformation.IsIdentity ()) { + this.mesh.EnumerateVertices (onVertex); + } else { + this.mesh.EnumerateVertices ((vertex) => { + const transformed = this.transformation.TransformCoord3D (vertex); + onVertex (transformed); + }); + } } - EnumerateTriangles (onTriangle) + EnumerateTriangleVertexIndices (onTriangleVertexIndices) { - this.mesh.EnumerateTriangles (onTriangle); + this.mesh.EnumerateTriangleVertexIndices (onTriangleVertexIndices); } EnumerateTriangleVertices (onTriangleVertices) { - this.mesh.EnumerateTriangleVertices ((v0, v1, v2) => { - const v0Transformed = this.transformation.TransformCoord3D (v0); - const v1Transformed = this.transformation.TransformCoord3D (v1); - const v2Transformed = this.transformation.TransformCoord3D (v2); - onTriangleVertices (v0Transformed, v1Transformed, v2Transformed); - }); + if (this.transformation.IsIdentity ()) { + this.mesh.EnumerateTriangleVertices (onTriangleVertices); + } else { + this.mesh.EnumerateTriangleVertices ((v0, v1, v2) => { + const v0Transformed = this.transformation.TransformCoord3D (v0); + const v1Transformed = this.transformation.TransformCoord3D (v1); + const v2Transformed = this.transformation.TransformCoord3D (v2); + onTriangleVertices (v0Transformed, v1Transformed, v2Transformed); + }); + } } }; diff --git a/source/model/model.js b/source/model/model.js index 5fd0a37..99d4d22 100644 --- a/source/model/model.js +++ b/source/model/model.js @@ -116,6 +116,37 @@ OV.Model = class extends OV.ModelObject3D } } + EnumerateMeshInstances (onMeshInstance) + { + function EnumerateNodeMeshInstances (model, node, transformation, onMeshInstance) + { + let nodeTransformation = node.GetTransformation ().Clone (); + nodeTransformation.Append (transformation); + + for (let childNode of node.GetChildNodes ()) { + EnumerateNodeMeshInstances (model, childNode, nodeTransformation, onMeshInstance); + } + + for (let meshIndex of node.GetMeshIndices ()) { + let mesh = model.GetMesh (meshIndex); + let meshInstance = new OV.MeshInstance (mesh, nodeTransformation); + onMeshInstance (meshInstance); + } + } + + let transformation = new OV.Transformation (); + EnumerateNodeMeshInstances (this, this.root, transformation, onMeshInstance); + } + + EnumerateTransformedMeshInstances (onMesh) + { + this.EnumerateMeshInstances ((meshInstance) => { + const mesh = OV.CloneMesh (meshInstance.mesh); + OV.TransformMesh (mesh, meshInstance.transformation); + onMesh (mesh); + }); + } + EnumerateVertices (onVertex) { for (const mesh of this.meshes) { @@ -123,10 +154,10 @@ OV.Model = class extends OV.ModelObject3D } } - EnumerateTriangles (onTriangle) + EnumerateTriangleVertexIndices (onTriangleVertexIndices) { for (const mesh of this.meshes) { - mesh.EnumerateTriangles (onTriangle); + mesh.EnumerateTriangleVertexIndices (onTriangleVertexIndices); } } @@ -135,5 +166,5 @@ OV.Model = class extends OV.ModelObject3D for (const mesh of this.meshes) { mesh.EnumerateTriangleVertices (onTriangleVertices); } - } + } }; diff --git a/source/model/modelutils.js b/source/model/modelutils.js index e36bfb3..cb8fe1e 100644 --- a/source/model/modelutils.js +++ b/source/model/modelutils.js @@ -158,8 +158,8 @@ OV.EnumerateModelVerticesAndTriangles = function (model, callbacks) }); let vertexOffset = 0; model.EnumerateMeshes ((mesh) => { - mesh.EnumerateTriangles ((triangle) => { - callbacks.onTriangle (triangle.v0 + vertexOffset, triangle.v1 + vertexOffset, triangle.v2 + vertexOffset); + mesh.EnumerateTriangleVertexIndices ((v0, v1, v2) => { + callbacks.onTriangle (v0 + vertexOffset, v1 + vertexOffset, v2 + vertexOffset); }); vertexOffset += mesh.VertexCount (); }); diff --git a/source/model/object.js b/source/model/object.js index 7b213a3..a83ddf2 100644 --- a/source/model/object.js +++ b/source/model/object.js @@ -30,7 +30,7 @@ OV.Object3D = class } - EnumerateTriangles (onTriangle) + EnumerateTriangleVertexIndices (onTriangleVertexIndices) { } diff --git a/test/testfiles/o3dv/translateandrotate.o3dv b/test/testfiles/o3dv/translateandrotate.o3dv new file mode 100644 index 0000000..cb605ae --- /dev/null +++ b/test/testfiles/o3dv/translateandrotate.o3dv @@ -0,0 +1,48 @@ +{ + "root" : { + "children" : [ + { + "name" : "Translated", + "transformation" : { + "translation" : [2.0, 0.0, 0.0] + }, + "meshes" : [0] + }, + { + "name" : "Rotated", + "transformation" : { + "rotation" : [0.0, 0.0, 0.7071067811865475, 0.7071067811865476] + + }, + "children" : [ + { + "name" : "Translated", + "transformation" : { + "translation" : [2.0, 0.0, 0.0] + }, + "meshes" : [0] + } + ] + } + ], + "meshes" : [0] + }, + "materials" : [ + { + "name" : "Green", + "color" : [0, 200, 0] + } + ], + "meshes" : [ + { + "name" : "Cube", + "type" : "cuboid", + "material" : 0, + "parameters" : { + "size_x" : 1.0, + "size_y" : 1.0, + "size_z" : 1.0 + } + } + ] +} diff --git a/test/tests/model_test.js b/test/tests/model_test.js index 5c9bb78..b5664df 100644 --- a/test/tests/model_test.js +++ b/test/tests/model_test.js @@ -279,6 +279,48 @@ function CreateHierarchicalModel () return model; } +function CreateTranslatedRotatedCubesModel () +{ + /* + + + + Translated + Cube + + Rotated + + Translated and Rotated + Cube + Cube + */ + + let model = new OV.Model (); + + let mesh = OV.GenerateCuboid (null, 1.0, 1.0, 1.0); + mesh.SetName ('Cube'); + let meshIndex = model.AddMesh (mesh); + + let root = model.GetRootNode (); + root.AddMeshIndex (0); + + let translatedNode = new OV.Node (); + translatedNode.SetName ('Translated'); + translatedNode.SetTransformation (new OV.Transformation (new OV.Matrix ().CreateTranslation (2.0, 0.0, 0.0))); + translatedNode.AddMeshIndex (0); + + let rotatedNode = new OV.Node (); + rotatedNode.SetName ('Rotated'); + rotatedNode.SetTransformation (new OV.Transformation (new OV.Matrix ().CreateRotation (0.0, 0.0, 0.7071067811865475, 0.7071067811865476))); + + let translatedRotatedNode = new OV.Node (); + translatedRotatedNode.SetName ('Translated and Rotated'); + translatedRotatedNode.SetTransformation (new OV.Transformation (new OV.Matrix ().CreateTranslation (2.0, 0.0, 0.0))); + translatedRotatedNode.AddMeshIndex (0); + + root.AddChildNode (translatedNode); + root.AddChildNode (rotatedNode); + rotatedNode.AddChildNode (translatedRotatedNode); + + return model; +} + function GetModelTree (model) { function AddNodeToModelTree (model, node, modelTree) @@ -401,5 +443,99 @@ describe ('Node Hierarchy', function () { ], meshNames : ['Mesh 1', 'Mesh 2'] }); - }); + }); + + it ('Enumerate mesh instances', function () { + let model = CreateTranslatedRotatedCubesModel (); + let modelTree = GetModelTree (model); + assert.deepStrictEqual (modelTree, { + name : '', + childNodes : [ + { + name : 'Translated', + childNodes : [], + meshNames : ['Cube'] + }, + { + name : 'Rotated', + childNodes : [ + { + name : 'Translated and Rotated', + childNodes : [], + meshNames : ['Cube'] + } + ], + meshNames : [] + } + ], + meshNames : ['Cube'] + }); + + let meshInstances = []; + model.EnumerateMeshInstances ((meshInstance) => { + meshInstances.push (meshInstance); + }); + + assert.strictEqual (meshInstances.length, 3); + + let boundingBox1 = OV.GetBoundingBox (meshInstances[0]); + let boundingBox2 = OV.GetBoundingBox (meshInstances[1]); + let boundingBox3 = OV.GetBoundingBox (meshInstances[2]); + + assert (OV.CoordIsEqual3D (boundingBox1.min, new OV.Coord3D (2.0, 0.0, 0.0))); + assert (OV.CoordIsEqual3D (boundingBox1.max, new OV.Coord3D (3.0, 1.0, 1.0))); + + assert (OV.CoordIsEqual3D (boundingBox2.min, new OV.Coord3D (-1.0, 2.0, 0.0))); + assert (OV.CoordIsEqual3D (boundingBox2.max, new OV.Coord3D (0.0, 3.0, 1.0))); + + assert (OV.CoordIsEqual3D (boundingBox3.min, new OV.Coord3D (0.0, 0.0, 0.0))); + assert (OV.CoordIsEqual3D (boundingBox3.max, new OV.Coord3D (1.0, 1.0, 1.0))); + }); + + it ('Enumerate transformed mesh instances', function () { + let model = CreateTranslatedRotatedCubesModel (); + let modelTree = GetModelTree (model); + assert.deepStrictEqual (modelTree, { + name : '', + childNodes : [ + { + name : 'Translated', + childNodes : [], + meshNames : ['Cube'] + }, + { + name : 'Rotated', + childNodes : [ + { + name : 'Translated and Rotated', + childNodes : [], + meshNames : ['Cube'] + } + ], + meshNames : [] + } + ], + meshNames : ['Cube'] + }); + + let meshes = []; + model.EnumerateTransformedMeshInstances ((mesh) => { + meshes.push (mesh); + }); + + assert.strictEqual (meshes.length, 3); + + let boundingBox1 = OV.GetBoundingBox (meshes[0]); + let boundingBox2 = OV.GetBoundingBox (meshes[1]); + let boundingBox3 = OV.GetBoundingBox (meshes[2]); + + assert (OV.CoordIsEqual3D (boundingBox1.min, new OV.Coord3D (2.0, 0.0, 0.0))); + assert (OV.CoordIsEqual3D (boundingBox1.max, new OV.Coord3D (3.0, 1.0, 1.0))); + + assert (OV.CoordIsEqual3D (boundingBox2.min, new OV.Coord3D (-1.0, 2.0, 0.0))); + assert (OV.CoordIsEqual3D (boundingBox2.max, new OV.Coord3D (0.0, 3.0, 1.0))); + + assert (OV.CoordIsEqual3D (boundingBox3.min, new OV.Coord3D (0.0, 0.0, 0.0))); + assert (OV.CoordIsEqual3D (boundingBox3.max, new OV.Coord3D (1.0, 1.0, 1.0))); + }); });