From 0eee8014460de656f5c3e26ecf516e128bd36419 Mon Sep 17 00:00:00 2001 From: kovacsv Date: Tue, 28 Dec 2021 21:15:33 +0100 Subject: [PATCH] Store vertex colors for triangles. --- source/import/importergltf.js | 19 +++++-- source/import/importerply.js | 2 + source/model/meshbuffer.js | 92 ++++++++++++++++++++++--------- source/model/modelfinalization.js | 3 +- source/model/modelutils.js | 10 ++++ source/model/triangle.js | 32 ++++++++--- source/threejs/threeconverter.js | 16 ++++-- source/threejs/threeutils.js | 3 + test/tests/meshbuffer_test.js | 22 ++++++++ 9 files changed, 155 insertions(+), 44 deletions(-) diff --git a/source/import/importergltf.js b/source/import/importergltf.js index ce68059..f8ea2cc 100644 --- a/source/import/importergltf.js +++ b/source/import/importergltf.js @@ -406,6 +406,7 @@ OV.GltfExtensions = class } let vertexOffset = mesh.VertexCount (); + let vertexColorOffset = mesh.VertexColorCount (); let normalOffset = mesh.NormalCount (); let uvOffset = mesh.TextureUVCount (); @@ -443,7 +444,7 @@ OV.GltfExtensions = class let v0 = indexArray[i]; let v1 = indexArray[i + 1]; let v2 = indexArray[i + 2]; - importer.AddTriangle (primitive, mesh, v0, v1, v2, hasNormals, hasUVs, vertexOffset, normalOffset, uvOffset); + importer.AddTriangle (primitive, mesh, v0, v1, v2, hasVertexColors, hasNormals, hasUVs, vertexOffset, vertexColorOffset, normalOffset, uvOffset); } this.draco._free (indexDataPtr); @@ -795,6 +796,7 @@ OV.ImporterGltf = class extends OV.ImporterBase } let vertexOffset = mesh.VertexCount (); + let vertexColorOffset = mesh.VertexColorCount (); let normalOffset = mesh.NormalCount (); let uvOffset = mesh.TextureUVCount (); @@ -867,7 +869,7 @@ OV.ImporterGltf = class extends OV.ImporterBase let v0 = vertexIndices[i]; let v1 = vertexIndices[i + 1]; let v2 = vertexIndices[i + 2]; - this.AddTriangle (primitive, mesh, v0, v1, v2, hasNormals, hasUVs, vertexOffset, normalOffset, uvOffset); + this.AddTriangle (primitive, mesh, v0, v1, v2, hasVertexColors, hasNormals, hasUVs, vertexOffset, vertexColorOffset, normalOffset, uvOffset); } } else if (mode === OV.GltfRenderMode.TRIANGLE_STRIP) { for (let i = 0; i < vertexIndices.length - 2; i++) { @@ -879,21 +881,28 @@ OV.ImporterGltf = class extends OV.ImporterBase v1 = v2; v2 = tmp; } - this.AddTriangle (primitive, mesh, v0, v1, v2, hasNormals, hasUVs, vertexOffset, normalOffset, uvOffset); + this.AddTriangle (primitive, mesh, v0, v1, v2, hasVertexColors, hasNormals, hasUVs, vertexOffset, vertexColorOffset, normalOffset, uvOffset); } } else if (mode === OV.GltfRenderMode.TRIANGLE_FAN) { for (let i = 1; i < vertexIndices.length - 1; i++) { let v0 = vertexIndices[0]; let v1 = vertexIndices[i]; let v2 = vertexIndices[i + 1]; - this.AddTriangle (primitive, mesh, v0, v1, v2, hasNormals, hasUVs, vertexOffset, normalOffset, uvOffset); + this.AddTriangle (primitive, mesh, v0, v1, v2, hasVertexColors, hasNormals, hasUVs, vertexOffset, vertexColorOffset, normalOffset, uvOffset); } } } - AddTriangle (primitive, mesh, v0, v1, v2, hasNormals, hasUVs, vertexOffset, normalOffset, uvOffset) + AddTriangle (primitive, mesh, v0, v1, v2, hasVertexColors, hasNormals, hasUVs, vertexOffset, vertexColorOffset, normalOffset, uvOffset) { let triangle = new OV.Triangle (vertexOffset + v0, vertexOffset + v1, vertexOffset + v2); + if (hasVertexColors) { + triangle.SetVertexColors ( + vertexColorOffset + v0, + vertexColorOffset + v1, + vertexColorOffset + v2 + ); + } if (hasNormals) { triangle.SetNormals ( normalOffset + v0, diff --git a/source/import/importerply.js b/source/import/importerply.js index 8da4444..f5830aa 100644 --- a/source/import/importerply.js +++ b/source/import/importerply.js @@ -383,6 +383,8 @@ OV.ImporterPly = class extends OV.ImporterBase let triangle = new OV.Triangle (v0, v1, v2); if (faceColor !== null) { triangle.mat = materialHandler.GetMaterialIndexByColor (faceColor); + } else if (this.mesh.VertexColorCount () > 0) { + triangle.SetVertexColors (v0, v1, v2); } this.mesh.AddTriangle (triangle); } diff --git a/source/model/meshbuffer.js b/source/model/meshbuffer.js index 9b10332..5345cc3 100644 --- a/source/model/meshbuffer.js +++ b/source/model/meshbuffer.js @@ -4,6 +4,7 @@ OV.MeshPrimitiveBuffer = class { this.indices = []; this.vertices = []; + this.colors = []; this.normals = []; this.uvs = []; this.material = null; @@ -28,7 +29,7 @@ OV.MeshPrimitiveBuffer = class GetByteLength (indexTypeSize, numberTypeSize) { let indexCount = this.indices.length; - let numberCount = this.vertices.length + this.normals.length + this.uvs.length; + let numberCount = this.vertices.length + this.colors.length + this.normals.length + this.uvs.length; return indexCount * indexTypeSize + numberCount * numberTypeSize; } }; @@ -63,8 +64,19 @@ OV.MeshBuffer = class OV.ConvertMeshToMeshBuffer = function (mesh) { - function AddVertexToPrimitiveBuffer (mesh, vertexIndex, normalIndex, uvIndex, primitiveBuffer, meshToPrimitiveVertices) + function AddVertexToPrimitiveBuffer (mesh, vertexIndex, vertexColorIndex, normalIndex, uvIndex, primitiveBuffer, meshToPrimitiveVertices) { + function GetVertexColorOrDefault (mesh, vertexColorIndex, forceVertexColors) + { + if (vertexColorIndex !== null) { + return mesh.GetVertexColor (vertexColorIndex); + } else if (forceVertexColors) { + return new OV.Color (0, 0, 0); + } else { + return null; + } + } + function GetUVOrDefault (mesh, uvIndex, forceUVs) { if (uvIndex !== null) { @@ -76,58 +88,88 @@ OV.ConvertMeshToMeshBuffer = function (mesh) } } - function AddVertex (mesh, vertexIndex, normalIndex, uvIndex, primitiveBuffer) + function AddVertex (mesh, vertexIndex, vertexColorIndex, normalIndex, uvIndex, primitiveBuffer) { + let forceVertexColors = mesh.VertexColorCount () > 0; let forceUVs = mesh.TextureUVCount () > 0; + let vertex = mesh.GetVertex (vertexIndex); let normal = mesh.GetNormal (normalIndex); + let primitiveVertexIndex = primitiveBuffer.vertices.length / 3; primitiveBuffer.indices.push (primitiveVertexIndex); primitiveBuffer.vertices.push (vertex.x, vertex.y, vertex.z); + + let vertexColor = GetVertexColorOrDefault (mesh, vertexColorIndex, forceVertexColors); + if (vertexColor !== null) { + primitiveBuffer.colors.push (vertexColor.r / 255.0, vertexColor.g / 255.0, vertexColor.b / 255.0); + } + primitiveBuffer.normals.push (normal.x, normal.y, normal.z); + let uv = GetUVOrDefault (mesh, uvIndex, forceUVs); if (uv !== null) { primitiveBuffer.uvs.push (uv.x, uv.y); } + return { index : primitiveVertexIndex, + vertexColor : vertexColor, normal : normal, uv : uv }; } - function FindMatchingPrimitiveVertex (mesh, primitiveVertices, normalIndex, uvIndex) + function FindMatchingPrimitiveVertex (mesh, primitiveVertices, vertexColorIndex, normalIndex, uvIndex) { + function IsEqualVertexColor (mesh, vertexColorIndex, existingVertexColor) + { + if (existingVertexColor === null && vertexColorIndex === null) { + return true; + } + let vertexColor = GetVertexColorOrDefault (mesh, vertexColorIndex, true); + return OV.ColorIsEqual (existingVertexColor, vertexColor); + } + + function IsEqualNormal (mesh, normalIndex, existingNormal) + { + let normal = mesh.GetNormal (normalIndex); + return OV.CoordIsEqual3D (existingNormal, normal); + } + + function IsEqualUV (mesh, uvIndex, existingUv) + { + if (existingUv === null && uvIndex === null) { + return true; + } + let uv = GetUVOrDefault (mesh, uvIndex, true); + return OV.CoordIsEqual2D (existingUv, uv); + } + for (let i = 0; i < primitiveVertices.length; i++) { let primitiveVertex = primitiveVertices[i]; - let normal = mesh.GetNormal (normalIndex); - let equalNormal = OV.CoordIsEqual3D (primitiveVertex.normal, normal); - let equalUv = false; - if (primitiveVertex.uv === null && uvIndex === null) { - equalUv = true; - } else { - let uv = GetUVOrDefault (mesh, uvIndex, true); - equalUv = OV.CoordIsEqual2D (primitiveVertex.uv, uv); - } - if (equalNormal && equalUv) { + let equalVertexColor = IsEqualVertexColor (mesh, vertexColorIndex, primitiveVertex.vertexColor); + let equalNormal = IsEqualNormal (mesh, normalIndex, primitiveVertex.normal); + let equalUv = IsEqualUV (mesh, uvIndex, primitiveVertex.uv); + if (equalVertexColor && equalNormal && equalUv) { return primitiveVertex; } } return null; } - let primitiveVertices = meshToPrimitiveVertices[vertexIndex]; - if (primitiveVertices === undefined) { - let primitiveVertex = AddVertex (mesh, vertexIndex, normalIndex, uvIndex, primitiveBuffer); - meshToPrimitiveVertices[vertexIndex] = [primitiveVertex]; - } else { - let existingPrimitiveVertex = FindMatchingPrimitiveVertex (mesh, primitiveVertices, normalIndex, uvIndex); + if (meshToPrimitiveVertices.has (vertexIndex)) { + let primitiveVertices = meshToPrimitiveVertices.get (vertexIndex); + let existingPrimitiveVertex = FindMatchingPrimitiveVertex (mesh, primitiveVertices, vertexColorIndex, normalIndex, uvIndex); if (existingPrimitiveVertex !== null) { primitiveBuffer.indices.push (existingPrimitiveVertex.index); } else { - let primitiveVertex = AddVertex (mesh, vertexIndex, normalIndex, uvIndex, primitiveBuffer); + let primitiveVertex = AddVertex (mesh, vertexIndex, vertexColorIndex, normalIndex, uvIndex, primitiveBuffer); primitiveVertices.push (primitiveVertex); } + } else { + let primitiveVertex = AddVertex (mesh, vertexIndex, vertexColorIndex, normalIndex, uvIndex, primitiveBuffer); + meshToPrimitiveVertices.set (vertexIndex, [primitiveVertex]); } } @@ -156,12 +198,12 @@ OV.ConvertMeshToMeshBuffer = function (mesh) if (primitiveBuffer === null || primitiveBuffer.material !== triangle.mat) { primitiveBuffer = new OV.MeshPrimitiveBuffer (); primitiveBuffer.material = triangle.mat; - meshToPrimitiveVertices = {}; + meshToPrimitiveVertices = new Map (); meshBuffer.primitives.push (primitiveBuffer); } - AddVertexToPrimitiveBuffer (mesh, triangle.v0, triangle.n0, triangle.u0, primitiveBuffer, meshToPrimitiveVertices); - AddVertexToPrimitiveBuffer (mesh, triangle.v1, triangle.n1, triangle.u1, primitiveBuffer, meshToPrimitiveVertices); - AddVertexToPrimitiveBuffer (mesh, triangle.v2, triangle.n2, triangle.u2, primitiveBuffer, meshToPrimitiveVertices); + AddVertexToPrimitiveBuffer (mesh, triangle.v0, triangle.c0, triangle.n0, triangle.u0, primitiveBuffer, meshToPrimitiveVertices); + AddVertexToPrimitiveBuffer (mesh, triangle.v1, triangle.c1, triangle.n1, triangle.u1, primitiveBuffer, meshToPrimitiveVertices); + AddVertexToPrimitiveBuffer (mesh, triangle.v2, triangle.c2, triangle.n2, triangle.u2, primitiveBuffer, meshToPrimitiveVertices); } return meshBuffer; diff --git a/source/model/modelfinalization.js b/source/model/modelfinalization.js index f56ac99..bbea60f 100644 --- a/source/model/modelfinalization.js +++ b/source/model/modelfinalization.js @@ -96,11 +96,10 @@ OV.FinalizeModel = function (model, getDefaultMaterial) calculateCurveNormals : false }; - let hasVertexColors = (mesh.VertexCount () === mesh.VertexColorCount ()); for (let i = 0; i < mesh.TriangleCount (); i++) { let triangle = mesh.GetTriangle (i); FinalizeTriangle (mesh, triangle, status); - if (hasVertexColors) { + if (triangle.HasVertexColors ()) { let material = model.GetMaterial (triangle.mat); material.vertexColors = true; } diff --git a/source/model/modelutils.js b/source/model/modelutils.js index c0e8055..6ede4b6 100644 --- a/source/model/modelutils.js +++ b/source/model/modelutils.js @@ -35,6 +35,11 @@ OV.TransformMesh = function (mesh, transformation) } }; +OV.MeshHasVertexColors = function (mesh) +{ + return mesh.VertexCount () === mesh.VertexColorCount (); +}; + OV.FlipMeshTrianglesOrientation = function (mesh) { for (let i = 0; i < mesh.TriangleCount (); i++) { @@ -67,6 +72,11 @@ OV.CloneMesh = function (mesh) cloned.AddVertex (vertex.Clone ()); } + for (let i = 0; i < mesh.VertexColorCount (); i++) { + let color = mesh.GetVertexColor (i); + cloned.AddVertexColor (color.Clone ()); + } + for (let i = 0; i < mesh.NormalCount (); i++) { let normal = mesh.GetNormal (i); cloned.AddNormal (normal.Clone ()); diff --git a/source/model/triangle.js b/source/model/triangle.js index 25543c5..a1e31df 100644 --- a/source/model/triangle.js +++ b/source/model/triangle.js @@ -5,15 +5,19 @@ OV.Triangle = class this.v0 = v0; this.v1 = v1; this.v2 = v2; - + + this.c0 = null; + this.c1 = null; + this.c2 = null; + this.n0 = null; this.n1 = null; this.n2 = null; - + this.u0 = null; this.u1 = null; this.u2 = null; - + this.mat = null; this.curve = null; } @@ -23,6 +27,11 @@ OV.Triangle = class return this.v0 !== null && this.v1 !== null && this.v2 !== null; } + HasVertexColors () + { + return this.c0 !== null && this.c1 !== null && this.c2 !== null; + } + HasNormals () { return this.n0 !== null && this.n1 !== null && this.n2 !== null; @@ -31,7 +40,7 @@ OV.Triangle = class HasTextureUVs () { return this.u0 !== null && this.u1 !== null && this.u2 !== null; - } + } SetVertices (v0, v1, v2) { @@ -40,7 +49,15 @@ OV.Triangle = class this.v2 = v2; return this; } - + + SetVertexColors (c0, c1, c2) + { + this.c0 = c0; + this.c1 = c1; + this.c2 = c2; + return this; + } + SetNormals (n0, n1, n2) { this.n0 = n0; @@ -48,7 +65,7 @@ OV.Triangle = class this.n2 = n2; return this; } - + SetTextureUVs (u0, u1, u2) { this.u0 = u0; @@ -62,7 +79,7 @@ OV.Triangle = class this.mat = mat; return this; } - + SetCurve (curve) { this.curve = curve; @@ -72,6 +89,7 @@ OV.Triangle = class Clone () { let cloned = new OV.Triangle (this.v0, this.v1, this.v2); + cloned.SetVertexColors (this.c0, this.c1, this.c2); cloned.SetNormals (this.n0, this.n1, this.n2); cloned.SetTextureUVs (this.u0, this.u1, this.u2); cloned.SetMaterial (this.mat); diff --git a/source/threejs/threeconverter.js b/source/threejs/threeconverter.js index dd79420..8b93815 100644 --- a/source/threejs/threeconverter.js +++ b/source/threejs/threeconverter.js @@ -227,7 +227,7 @@ OV.ConvertModelToThreeObject = function (model, params, output, callbacks) end : -1 }); - let meshHasVertexColors = (mesh.VertexCount () === mesh.VertexColorCount ()); + let meshHasVertexColors = OV.MeshHasVertexColors (mesh); let meshHasUVs = (mesh.TextureUVCount () > 0); for (let i = 0; i < triangleIndices.length; i++) { let triangleIndex = triangleIndices[i]; @@ -238,15 +238,21 @@ OV.ConvertModelToThreeObject = function (model, params, output, callbacks) let v2 = mesh.GetVertex (triangle.v2); vertices.push (v0.x, v0.y, v0.z, v1.x, v1.y, v1.z, v2.x, v2.y, v2.z); - if (meshHasVertexColors) { - let vc0 = OV.ConvertColorToThreeColor (mesh.GetVertexColor (triangle.v0)); - let vc1 = OV.ConvertColorToThreeColor (mesh.GetVertexColor (triangle.v1)); - let vc2 = OV.ConvertColorToThreeColor (mesh.GetVertexColor (triangle.v2)); + if (triangle.HasVertexColors ()) { + let vc0 = OV.ConvertColorToThreeColor (mesh.GetVertexColor (triangle.c0)); + let vc1 = OV.ConvertColorToThreeColor (mesh.GetVertexColor (triangle.c1)); + let vc2 = OV.ConvertColorToThreeColor (mesh.GetVertexColor (triangle.c2)); vertexColors.push ( vc0.r, vc0.g, vc0.b, vc1.r, vc1.g, vc1.b, vc2.r, vc2.g, vc2.b ); + } else if (meshHasVertexColors) { + vertexColors.push ( + 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0 + ); } let n0 = mesh.GetNormal (triangle.n0); diff --git a/source/threejs/threeutils.js b/source/threejs/threeutils.js index dcb85d7..af12295 100644 --- a/source/threejs/threeutils.js +++ b/source/threejs/threeutils.js @@ -156,6 +156,9 @@ OV.ConvertThreeGeometryToMesh = function (threeGeometry, materialIndex) let v1 = indices[i + 1]; let v2 = indices[i + 2]; let triangle = new OV.Triangle (v0, v1, v2); + if (hasVertexColors) { + triangle.SetVertexColors (v0, v1, v2); + } if (hasNormals) { triangle.SetNormals (v0, v1, v2); } diff --git a/test/tests/meshbuffer_test.js b/test/tests/meshbuffer_test.js index e23640e..3783cbe 100644 --- a/test/tests/meshbuffer_test.js +++ b/test/tests/meshbuffer_test.js @@ -30,6 +30,28 @@ describe ('Mesh Buffer', function () { assert.strictEqual (buffer.primitives[1].uvs.length, 0); }); + it ('Mesh To Buffer Different Colors', function () { + var mesh = new OV.Mesh (); + mesh.AddVertex (new OV.Coord3D (0.0, 0.0, 0.0)); + mesh.AddVertex (new OV.Coord3D (1.0, 0.0, 0.0)); + mesh.AddVertex (new OV.Coord3D (1.0, 1.0, 0.0)); + mesh.AddVertex (new OV.Coord3D (0.0, 1.0, 0.0)); + + mesh.AddVertexColor (new OV.Color (0.1, 0.0, 0.0)); + mesh.AddVertexColor (new OV.Color (0.2, 0.0, 0.0)); + + mesh.AddNormal (new OV.Coord3D (0.0, 0.0, 1.0)); + mesh.AddTriangle (new OV.Triangle (0, 1, 2).SetVertexColors (0, 0, 0).SetNormals (0, 0, 0).SetMaterial (0)); + mesh.AddTriangle (new OV.Triangle (0, 2, 3).SetVertexColors (1, 1, 1).SetNormals (0, 0, 0).SetMaterial (0)); + + let buffer = OV.ConvertMeshToMeshBuffer (mesh); + assert.strictEqual (buffer.primitives.length, 1); + assert.strictEqual (buffer.primitives[0].indices.length, 6); + assert.strictEqual (buffer.primitives[0].vertices.length, 6 * 3); + assert.strictEqual (buffer.primitives[0].normals.length, 6 * 3); + assert.strictEqual (buffer.primitives[0].uvs.length, 0); + }); + it ('Mesh To Buffer Different Normals', function () { var mesh = new OV.Mesh (); mesh.AddVertex (new OV.Coord3D (0.0, 0.0, 0.0));