From 19f8e09752435db2022122602ce62f686242cc3f Mon Sep 17 00:00:00 2001 From: angelswing Date: Fri, 24 Feb 2023 15:59:15 +0545 Subject: [PATCH 1/2] feat: modified meshT file to receive material info --- MeshDecimatorCore/Mesh.cs | 4 +- Obj2Tiles.Library/Geometry/FaceB.cs | 30 +++ Obj2Tiles.Library/Geometry/Mesh.cs | 98 ++++++---- Obj2Tiles.Library/Geometry/MeshT.cs | 240 ++++-------------------- Obj2Tiles.Library/Geometry/MeshUtils.cs | 143 +++++++------- Obj2Tiles.Library/Materials/Material.cs | 7 +- Obj2Tiles/Program.cs | 20 +- Obj2Tiles/Stages/SplitStage.cs | 20 +- 8 files changed, 226 insertions(+), 336 deletions(-) create mode 100644 Obj2Tiles.Library/Geometry/FaceB.cs diff --git a/MeshDecimatorCore/Mesh.cs b/MeshDecimatorCore/Mesh.cs index 58ff063..0743bfb 100644 --- a/MeshDecimatorCore/Mesh.cs +++ b/MeshDecimatorCore/Mesh.cs @@ -371,7 +371,7 @@ public void RecalculateTangents() return; int vertexCount = vertices.Length; - + var tangents = new Vector4[vertexCount]; var tan1 = new Vector3[vertexCount]; var tan2 = new Vector3[vertexCount]; @@ -429,7 +429,7 @@ public void RecalculateTangents() t1 = w1.y - w0.y; t2 = w2.y - w0.y; } - + float x1 = (float)(v1.x - v0.x); float x2 = (float)(v2.x - v0.x); diff --git a/Obj2Tiles.Library/Geometry/FaceB.cs b/Obj2Tiles.Library/Geometry/FaceB.cs new file mode 100644 index 0000000..46a8fd3 --- /dev/null +++ b/Obj2Tiles.Library/Geometry/FaceB.cs @@ -0,0 +1,30 @@ +namespace Obj2Tiles.Library.Geometry; + +public class FaceB +{ + + public int IndexA; + public int IndexB; + public int IndexC; + + public int MaterialIndex; + + public override string ToString() + { + return $"{IndexA} {IndexB} {IndexC} {MaterialIndex}"; + } + + public FaceB(int indexA, int indexB, int indexC, int materialIndex) + { + IndexA = indexA; + IndexB = indexB; + IndexC = indexC; + + MaterialIndex = materialIndex; + } + + public virtual string ToObj() + { + return $"f {IndexA + 1} {IndexB + 1} {IndexC + 1}"; + } +} \ No newline at end of file diff --git a/Obj2Tiles.Library/Geometry/Mesh.cs b/Obj2Tiles.Library/Geometry/Mesh.cs index b7e7def..6cb2cc9 100644 --- a/Obj2Tiles.Library/Geometry/Mesh.cs +++ b/Obj2Tiles.Library/Geometry/Mesh.cs @@ -9,40 +9,46 @@ namespace Obj2Tiles.Library.Geometry; public class Mesh : IMesh { private List _vertices; - private readonly List _faces; + private readonly List _faces; + private List _materials; + public IReadOnlyList Vertices => _vertices; - public IReadOnlyList Faces => _faces; + public IReadOnlyList Faces => _faces; + public IReadOnlyList Materials => _materials; public const string DefaultName = "Mesh"; public string Name { get; set; } = DefaultName; - public Mesh(IEnumerable vertices, IEnumerable faces) + public Mesh(IEnumerable vertices, + IEnumerable faces, IEnumerable materials) { _vertices = new List(vertices); - _faces = new List(faces); + _faces = new List(faces); + _materials = new List(materials); } - + public int Split(IVertexUtils utils, double q, out IMesh left, out IMesh right) { var leftVertices = new Dictionary(_vertices.Count); var rightVertices = new Dictionary(_vertices.Count); - var leftFaces = new List(_faces.Count); - var rightFaces = new List(_faces.Count); + var leftFaces = new List(_faces.Count); + var rightFaces = new List(_faces.Count); var count = 0; for (var index = 0; index < _faces.Count; index++) { var face = _faces[index]; + var faceMaterial = _materials[index]; var vA = _vertices[face.IndexA]; var vB = _vertices[face.IndexB]; var vC = _vertices[face.IndexC]; - + var aSide = utils.GetDimension(vA) < q; var bSide = utils.GetDimension(vB) < q; var cSide = utils.GetDimension(vC) < q; @@ -59,12 +65,12 @@ public int Split(IVertexUtils utils, double q, out IMesh left, var indexBLeft = leftVertices.AddIndex(vB); var indexCLeft = leftVertices.AddIndex(vC); - leftFaces.Add(new Face(indexALeft, indexBLeft, indexCLeft)); + leftFaces.Add(new FaceB(indexALeft, indexBLeft, indexCLeft, face.MaterialIndex)); } else { IntersectRight2D(utils, q, face.IndexC, face.IndexA, face.IndexB, leftVertices, rightVertices, - leftFaces, rightFaces); + leftFaces, rightFaces, face.MaterialIndex); count++; } } @@ -73,13 +79,13 @@ public int Split(IVertexUtils utils, double q, out IMesh left, if (cSide) { IntersectRight2D(utils, q, face.IndexB, face.IndexC, face.IndexA, leftVertices, rightVertices, - leftFaces, rightFaces); + leftFaces, rightFaces, face.MaterialIndex); count++; } else { IntersectLeft2D(utils, q, face.IndexA, face.IndexB, face.IndexC, leftVertices, rightVertices, - leftFaces, rightFaces); + leftFaces, rightFaces, face.MaterialIndex); count++; } } @@ -91,13 +97,13 @@ public int Split(IVertexUtils utils, double q, out IMesh left, if (cSide) { IntersectRight2D(utils, q, face.IndexA, face.IndexB, face.IndexC, leftVertices, rightVertices, - leftFaces, rightFaces); + leftFaces, rightFaces, face.MaterialIndex); count++; } else { IntersectLeft2D(utils, q, face.IndexB, face.IndexC, face.IndexA, leftVertices, rightVertices, - leftFaces, rightFaces); + leftFaces, rightFaces, face.MaterialIndex); count++; } } @@ -106,7 +112,7 @@ public int Split(IVertexUtils utils, double q, out IMesh left, if (cSide) { IntersectLeft2D(utils, q, face.IndexC, face.IndexA, face.IndexB, leftVertices, rightVertices, - leftFaces, rightFaces); + leftFaces, rightFaces, face.MaterialIndex); count++; } else @@ -116,7 +122,7 @@ public int Split(IVertexUtils utils, double q, out IMesh left, var indexARight = rightVertices.AddIndex(vA); var indexBRight = rightVertices.AddIndex(vB); var indexCRight = rightVertices.AddIndex(vC); - rightFaces.Add(new Face(indexARight, indexBRight, indexCRight)); + rightFaces.Add(new FaceB(indexARight, indexBRight, indexCRight, face.MaterialIndex)); } } } @@ -124,24 +130,28 @@ public int Split(IVertexUtils utils, double q, out IMesh left, var orderedLeftVertices = leftVertices.OrderBy(x => x.Value).Select(x => x.Key); var orderedRightVertices = rightVertices.OrderBy(x => x.Value).Select(x => x.Key); + var rightMaterials = _materials.Select(mat => (Material)mat.Clone()); + var leftMaterials = _materials.Select(mat => (Material)mat.Clone()); - left = new Mesh(orderedLeftVertices, leftFaces) + + left = new Mesh(orderedLeftVertices, leftFaces, leftMaterials) { Name = $"{Name}-{utils.Axis}L" }; - right = new Mesh(orderedRightVertices, rightFaces) + right = new Mesh(orderedRightVertices, rightFaces, rightMaterials) { Name = $"{Name}-{utils.Axis}R" }; + return count; } private void IntersectLeft2D(IVertexUtils utils, double q, int indexVL, int indexVR1, int indexVR2, IDictionary leftVertices, - IDictionary rightVertices, ICollection leftFaces, - ICollection rightFaces) + IDictionary rightVertices, ICollection leftFaces, + ICollection rightFaces, int materialIndex) { var vL = _vertices[indexVL]; var vR1 = _vertices[indexVR1]; @@ -157,7 +167,7 @@ private void IntersectLeft2D(IVertexUtils utils, double q, int indexVL, int inde var indexVR1Left = leftVertices.AddIndex(vR1); var indexVR2Left = leftVertices.AddIndex(vR2); - leftFaces.Add(new Face(indexVLLeft, indexVR1Left, indexVR2Left)); + leftFaces.Add(new FaceB(indexVLLeft, indexVR1Left, indexVR2Left, materialIndex)); return; } @@ -176,19 +186,19 @@ private void IntersectLeft2D(IVertexUtils utils, double q, int indexVL, int inde var indexT2Left = leftVertices.AddIndex(t2); var indexT2Right = rightVertices.AddIndex(t2); - var lface = new Face(indexVLLeft, indexT1Left, indexT2Left); + var lface = new FaceB(indexVLLeft, indexT1Left, indexT2Left, materialIndex); leftFaces.Add(lface); - var rface1 = new Face(indexT1Right, indexVR1Right, indexVR2Right); + var rface1 = new FaceB(indexT1Right, indexVR1Right, indexVR2Right, materialIndex); rightFaces.Add(rface1); - var rface2 = new Face(indexT1Right, indexVR2Right, indexT2Right); + var rface2 = new FaceB(indexT1Right, indexVR2Right, indexT2Right, materialIndex); rightFaces.Add(rface2); } private void IntersectRight2D(IVertexUtils utils, double q, int indexVR, int indexVL1, int indexVL2, IDictionary leftVertices, IDictionary rightVertices, - ICollection leftFaces, ICollection rightFaces) + ICollection leftFaces, ICollection rightFaces, int materialIndex) { var vR = _vertices[indexVR]; var vL1 = _vertices[indexVL1]; @@ -203,7 +213,7 @@ private void IntersectRight2D(IVertexUtils utils, double q, int indexVR, int ind var indexVL1Right = rightVertices.AddIndex(vL1); var indexVL2Right = rightVertices.AddIndex(vL2); - rightFaces.Add(new Face(indexVRRight, indexVL1Right, indexVL2Right)); + rightFaces.Add(new FaceB(indexVRRight, indexVL1Right, indexVL2Right, materialIndex)); return; } @@ -223,13 +233,13 @@ private void IntersectRight2D(IVertexUtils utils, double q, int indexVR, int ind var indexT2Left = leftVertices.AddIndex(t2); var indexT2Right = rightVertices.AddIndex(t2); - var rface = new Face(indexVRRight, indexT1Right, indexT2Right); + var rface = new FaceB(indexVRRight, indexT1Right, indexT2Right, materialIndex); rightFaces.Add(rface); - var lface1 = new Face(indexT2Left, indexVL1Left, indexVL2Left); + var lface1 = new FaceB(indexT2Left, indexVL1Left, indexVL2Left, materialIndex); leftFaces.Add(lface1); - var lface2 = new Face(indexT2Left, indexT1Left, indexVL1Left); + var lface2 = new FaceB(indexT2Left, indexT1Left, indexVL1Left, materialIndex); leftFaces.Add(lface2); } @@ -286,11 +296,10 @@ public Vertex3 GetVertexBaricenter() public void WriteObj(string path, bool removeUnused = true) { - if (removeUnused) RemoveUnusedVertices(); - + using var writer = new FormattingStreamWriter(path, CultureInfo.InvariantCulture); - + writer.Write("o "); writer.WriteLine(string.IsNullOrWhiteSpace(Name) ? DefaultName : Name); @@ -305,10 +314,17 @@ public void WriteObj(string path, bool removeUnused = true) writer.WriteLine(vertex.Z); } - for (var index = 0; index < _faces.Count; index++) + var materialFaces = from face in _faces + group face by face.MaterialIndex + into g + select g; + + foreach (var grp in materialFaces.OrderBy(item => item.Key)) { - var face = _faces[index]; - writer.WriteLine(face.ToObj()); + writer.WriteLine($"usemtl {_materials[grp.Key].Name}"); + + foreach (var face in grp) + writer.WriteLine(face.ToObj()); } } @@ -327,19 +343,19 @@ private void RemoveUnusedVertices() if (!newVertexes.TryGetValue(vA, out var newVA)) newVA = newVertexes.AddIndex(vA); - + face.IndexA = newVA; - + if (!newVertexes.TryGetValue(vB, out var newVB)) newVB = newVertexes.AddIndex(vB); - + face.IndexB = newVB; - + if (!newVertexes.TryGetValue(vC, out var newVC)) newVC = newVertexes.AddIndex(vC); - + face.IndexC = newVC; - + } _vertices = newVertexes.Keys.ToList(); diff --git a/Obj2Tiles.Library/Geometry/MeshT.cs b/Obj2Tiles.Library/Geometry/MeshT.cs index 65182e6..f2890b0 100644 --- a/Obj2Tiles.Library/Geometry/MeshT.cs +++ b/Obj2Tiles.Library/Geometry/MeshT.cs @@ -13,13 +13,11 @@ namespace Obj2Tiles.Library.Geometry; public class MeshT : IMesh { private List _vertices; - private List _textureVertices; - private readonly List _faces; + private readonly List _faces; private List _materials; public IReadOnlyList Vertices => _vertices; - public IReadOnlyList TextureVertices => _textureVertices; - public IReadOnlyList Faces => _faces; + public IReadOnlyList Faces => _faces; public IReadOnlyList Materials => _materials; public const string DefaultName = "Mesh"; @@ -28,12 +26,11 @@ public class MeshT : IMesh public TexturesStrategy TexturesStrategy { get; set; } - public MeshT(IEnumerable vertices, IEnumerable textureVertices, - IEnumerable faces, IEnumerable materials) + public MeshT(IEnumerable vertices, + IEnumerable faces, IEnumerable materials) { _vertices = new List(vertices); - _textureVertices = new List(textureVertices); - _faces = new List(faces); + _faces = new List(faces); _materials = new List(materials); } @@ -43,11 +40,9 @@ public int Split(IVertexUtils utils, double q, out IMesh left, var leftVertices = new Dictionary(_vertices.Count); var rightVertices = new Dictionary(_vertices.Count); - var leftFaces = new List(_faces.Count); - var rightFaces = new List(_faces.Count); + var leftFaces = new List(_faces.Count); + var rightFaces = new List(_faces.Count); - var leftTextureVertices = new Dictionary(_textureVertices.Count); - var rightTextureVertices = new Dictionary(_textureVertices.Count); var count = 0; @@ -59,10 +54,6 @@ public int Split(IVertexUtils utils, double q, out IMesh left, var vB = _vertices[face.IndexB]; var vC = _vertices[face.IndexC]; - var vtA = _textureVertices[face.TextureIndexA]; - var vtB = _textureVertices[face.TextureIndexB]; - var vtC = _textureVertices[face.TextureIndexC]; - var aSide = utils.GetDimension(vA) < q; var bSide = utils.GetDimension(vB) < q; var cSide = utils.GetDimension(vC) < q; @@ -79,12 +70,8 @@ public int Split(IVertexUtils utils, double q, out IMesh left, var indexBLeft = leftVertices.AddIndex(vB); var indexCLeft = leftVertices.AddIndex(vC); - var indexATextureLeft = leftTextureVertices!.AddIndex(vtA); - var indexBTextureLeft = leftTextureVertices!.AddIndex(vtB); - var indexCTextureLeft = leftTextureVertices!.AddIndex(vtC); - leftFaces.Add(new FaceT(indexALeft, indexBLeft, indexCLeft, - indexATextureLeft, indexBTextureLeft, indexCTextureLeft, + leftFaces.Add(new FaceB(indexALeft, indexBLeft, indexCLeft, face.MaterialIndex)); } else @@ -92,8 +79,7 @@ public int Split(IVertexUtils utils, double q, out IMesh left, IntersectRight2DWithTexture(utils, q, face.IndexC, face.IndexA, face.IndexB, leftVertices, rightVertices, - face.TextureIndexC, face.TextureIndexA, face.TextureIndexB, - leftTextureVertices, rightTextureVertices, face.MaterialIndex, leftFaces, rightFaces + face.MaterialIndex, leftFaces, rightFaces ); count++; } @@ -105,8 +91,7 @@ public int Split(IVertexUtils utils, double q, out IMesh left, IntersectRight2DWithTexture(utils, q, face.IndexB, face.IndexC, face.IndexA, leftVertices, rightVertices, - face.TextureIndexB, face.TextureIndexC, face.TextureIndexA, - leftTextureVertices, rightTextureVertices, face.MaterialIndex, leftFaces, + face.MaterialIndex, leftFaces, rightFaces); count++; } @@ -115,8 +100,7 @@ public int Split(IVertexUtils utils, double q, out IMesh left, IntersectLeft2DWithTexture(utils, q, face.IndexA, face.IndexB, face.IndexC, leftVertices, rightVertices, - face.TextureIndexA, face.TextureIndexB, face.TextureIndexC, - leftTextureVertices, rightTextureVertices, face.MaterialIndex, leftFaces, + face.MaterialIndex, leftFaces, rightFaces); count++; } @@ -131,8 +115,7 @@ public int Split(IVertexUtils utils, double q, out IMesh left, IntersectRight2DWithTexture(utils, q, face.IndexA, face.IndexB, face.IndexC, leftVertices, rightVertices, - face.TextureIndexA, face.TextureIndexB, face.TextureIndexC, - leftTextureVertices, rightTextureVertices, face.MaterialIndex, leftFaces, + face.MaterialIndex, leftFaces, rightFaces); count++; } @@ -141,8 +124,7 @@ public int Split(IVertexUtils utils, double q, out IMesh left, IntersectLeft2DWithTexture(utils, q, face.IndexB, face.IndexC, face.IndexA, leftVertices, rightVertices, - face.TextureIndexB, face.TextureIndexC, face.TextureIndexA, - leftTextureVertices, rightTextureVertices, face.MaterialIndex, leftFaces, + face.MaterialIndex, leftFaces, rightFaces); count++; } @@ -154,8 +136,7 @@ public int Split(IVertexUtils utils, double q, out IMesh left, IntersectLeft2DWithTexture(utils, q, face.IndexC, face.IndexA, face.IndexB, leftVertices, rightVertices, - face.TextureIndexC, face.TextureIndexA, face.TextureIndexB, - leftTextureVertices, rightTextureVertices, face.MaterialIndex, leftFaces, + face.MaterialIndex, leftFaces, rightFaces); count++; } @@ -167,12 +148,8 @@ public int Split(IVertexUtils utils, double q, out IMesh left, var indexBRight = rightVertices.AddIndex(vB); var indexCRight = rightVertices.AddIndex(vC); - var indexATextureRight = rightTextureVertices!.AddIndex(vtA); - var indexBTextureRight = rightTextureVertices!.AddIndex(vtB); - var indexCTextureRight = rightTextureVertices!.AddIndex(vtC); - rightFaces.Add(new FaceT(indexARight, indexBRight, indexCRight, - indexATextureRight, indexBTextureRight, indexCTextureRight, + rightFaces.Add(new FaceB(indexARight, indexBRight, indexCRight, face.MaterialIndex)); } } @@ -183,15 +160,13 @@ public int Split(IVertexUtils utils, double q, out IMesh left, var orderedRightVertices = rightVertices.OrderBy(x => x.Value).Select(x => x.Key); var rightMaterials = _materials.Select(mat => (Material)mat.Clone()); - var orderedLeftTextureVertices = leftTextureVertices.OrderBy(x => x.Value).Select(x => x.Key); - var orderedRightTextureVertices = rightTextureVertices.OrderBy(x => x.Value).Select(x => x.Key); var leftMaterials = _materials.Select(mat => (Material)mat.Clone()); - left = new MeshT(orderedLeftVertices, orderedLeftTextureVertices, leftFaces, leftMaterials) + left = new MeshT(orderedLeftVertices, leftFaces, leftMaterials) { Name = $"{Name}-{utils.Axis}L" }; - right = new MeshT(orderedRightVertices, orderedRightTextureVertices, rightFaces, rightMaterials) + right = new MeshT(orderedRightVertices, rightFaces, rightMaterials) { Name = $"{Name}-{utils.Axis}R" }; @@ -202,20 +177,13 @@ public int Split(IVertexUtils utils, double q, out IMesh left, private void IntersectLeft2DWithTexture(IVertexUtils utils, double q, int indexVL, int indexVR1, int indexVR2, IDictionary leftVertices, IDictionary rightVertices, - int indexTextureVL, int indexTextureVR1, int indexTextureVR2, - IDictionary leftTextureVertices, IDictionary rightTextureVertices, - int materialIndex, ICollection leftFaces, ICollection rightFaces) + int materialIndex, ICollection leftFaces, ICollection rightFaces) { var vL = _vertices[indexVL]; var vR1 = _vertices[indexVR1]; var vR2 = _vertices[indexVR2]; - var tVL = _textureVertices[indexTextureVL]; - var tVR1 = _textureVertices[indexTextureVR1]; - var tVR2 = _textureVertices[indexTextureVR2]; - var indexVLLeft = leftVertices.AddIndex(vL); - var indexTextureVLLeft = leftTextureVertices.AddIndex(tVL); if (Math.Abs(utils.GetDimension(vR1) - q) < Common.Epsilon && Math.Abs(utils.GetDimension(vR2) - q) < Common.Epsilon) @@ -225,11 +193,8 @@ private void IntersectLeft2DWithTexture(IVertexUtils utils, double q, int indexV var indexVR1Left = leftVertices.AddIndex(vR1); var indexVR2Left = leftVertices.AddIndex(vR2); - var indexTextureVR1Left = leftTextureVertices.AddIndex(tVR1); - var indexTextureVR2Left = leftTextureVertices.AddIndex(tVR2); - leftFaces.Add(new FaceT(indexVLLeft, indexVR1Left, indexVR2Left, - indexTextureVLLeft, indexTextureVR1Left, indexTextureVR2Left, materialIndex)); + leftFaces.Add(new FaceB(indexVLLeft, indexVR1Left, indexVR2Left, materialIndex)); return; } @@ -249,54 +214,35 @@ private void IntersectLeft2DWithTexture(IVertexUtils utils, double q, int indexV var indexT2Left = leftVertices.AddIndex(t2); var indexT2Right = rightVertices.AddIndex(t2); - // Split texture - var indexTextureVR1Right = rightTextureVertices.AddIndex(tVR1); - var indexTextureVR2Right = rightTextureVertices.AddIndex(tVR2); var perc1 = Common.GetIntersectionPerc(vL, vR1, t1); - // Prima intersezione texture - var t1t = tVL.CutEdgePerc(tVR1, perc1); - var indexTextureT1Left = leftTextureVertices.AddIndex(t1t); - var indexTextureT1Right = rightTextureVertices.AddIndex(t1t); var perc2 = Common.GetIntersectionPerc(vL, vR2, t2); - // Seconda intersezione texture - var t2t = tVL.CutEdgePerc(tVR2, perc2); - var indexTextureT2Left = leftTextureVertices.AddIndex(t2t); - var indexTextureT2Right = rightTextureVertices.AddIndex(t2t); - var lface = new FaceT(indexVLLeft, indexT1Left, indexT2Left, - indexTextureVLLeft, indexTextureT1Left, indexTextureT2Left, materialIndex); + + var lface = new FaceB(indexVLLeft, indexT1Left, indexT2Left, materialIndex); leftFaces.Add(lface); - var rface1 = new FaceT(indexT1Right, indexVR1Right, indexVR2Right, - indexTextureT1Right, indexTextureVR1Right, indexTextureVR2Right, materialIndex); + var rface1 = new FaceB(indexT1Right, indexVR1Right, indexVR2Right, materialIndex); rightFaces.Add(rface1); - var rface2 = new FaceT(indexT1Right, indexVR2Right, indexT2Right, - indexTextureT1Right, indexTextureVR2Right, indexTextureT2Right, materialIndex); + var rface2 = new FaceB(indexT1Right, indexVR2Right, indexT2Right, materialIndex); rightFaces.Add(rface2); } private void IntersectRight2DWithTexture(IVertexUtils utils, double q, int indexVR, int indexVL1, int indexVL2, IDictionary leftVertices, IDictionary rightVertices, - int indexTextureVR, int indexTextureVL1, int indexTextureVL2, - IDictionary leftTextureVertices, IDictionary rightTextureVertices, - int materialIndex, ICollection leftFaces, ICollection rightFaces) + int materialIndex, ICollection leftFaces, ICollection rightFaces) { var vR = _vertices[indexVR]; var vL1 = _vertices[indexVL1]; var vL2 = _vertices[indexVL2]; - var tVR = _textureVertices[indexTextureVR]; - var tVL1 = _textureVertices[indexTextureVL1]; - var tVL2 = _textureVertices[indexTextureVL2]; var indexVRRight = rightVertices.AddIndex(vR); - var indexTextureVRRight = rightTextureVertices.AddIndex(tVR); if (Math.Abs(utils.GetDimension(vL1) - q) < Common.Epsilon && Math.Abs(utils.GetDimension(vL2) - q) < Common.Epsilon) @@ -306,11 +252,8 @@ private void IntersectRight2DWithTexture(IVertexUtils utils, double q, int index var indexVL1Right = rightVertices.AddIndex(vL1); var indexVL2Right = rightVertices.AddIndex(vL2); - var indexTextureVL1Right = rightTextureVertices.AddIndex(tVL1); - var indexTextureVL2Right = rightTextureVertices.AddIndex(tVL2); - rightFaces.Add(new FaceT(indexVRRight, indexVL1Right, indexVL2Right, - indexTextureVRRight, indexTextureVL1Right, indexTextureVL2Right, materialIndex)); + rightFaces.Add(new FaceB(indexVRRight, indexVL1Right, indexVL2Right, materialIndex)); return; } @@ -330,34 +273,22 @@ private void IntersectRight2DWithTexture(IVertexUtils utils, double q, int index var indexT2Left = leftVertices.AddIndex(t2); var indexT2Right = rightVertices.AddIndex(t2); - // Split texture - var indexTextureVL1Left = leftTextureVertices.AddIndex(tVL1); - var indexTextureVL2Left = leftTextureVertices.AddIndex(tVL2); var perc1 = Common.GetIntersectionPerc(vR, vL1, t1); - // Prima intersezione texture - var t1t = tVR.CutEdgePerc(tVL1, perc1); - var indexTextureT1Left = leftTextureVertices.AddIndex(t1t); - var indexTextureT1Right = rightTextureVertices.AddIndex(t1t); + var perc2 = Common.GetIntersectionPerc(vR, vL2, t2); - // Seconda intersezione texture - var t2t = tVR.CutEdgePerc(tVL2, perc2); - var indexTextureT2Left = leftTextureVertices.AddIndex(t2t); - var indexTextureT2Right = rightTextureVertices.AddIndex(t2t); - var rface = new FaceT(indexVRRight, indexT1Right, indexT2Right, - indexTextureVRRight, indexTextureT1Right, indexTextureT2Right, materialIndex); + + var rface = new FaceB(indexVRRight, indexT1Right, indexT2Right, materialIndex); rightFaces.Add(rface); - var lface1 = new FaceT(indexT2Left, indexVL1Left, indexVL2Left, - indexTextureT2Left, indexTextureVL1Left, indexTextureVL2Left, materialIndex); + var lface1 = new FaceB(indexT2Left, indexVL1Left, indexVL2Left, materialIndex); leftFaces.Add(lface1); - var lface2 = new FaceT(indexT2Left, indexT1Left, indexVL1Left, - indexTextureT2Left, indexTextureT1Left, indexTextureVL1Left, materialIndex); + var lface2 = new FaceB(indexT2Left, indexT1Left, indexVL1Left, materialIndex); leftFaces.Add(lface2); } @@ -371,7 +302,6 @@ private void TrimTextures(string targetFolder) var facesByMaterial = GetFacesByMaterial(); - var newTextureVertices = new Dictionary(_textureVertices.Count); var sw = new Stopwatch(); @@ -414,14 +344,11 @@ private void TrimTextures(string targetFolder) Debug.WriteLine($"Material {material.Name} has {clusters.Count} clusters"); Debug.WriteLine("Bin packing clusters"); - BinPackTextures(targetFolder, m, clusters, newTextureVertices, tasks); + // BinPackTextures(targetFolder, m, clusters, tasks); Debug.WriteLine("Done in " + sw.ElapsedMilliseconds + "ms"); } - Debug.WriteLine("Sorting new texture vertices"); - sw.Restart(); - _textureVertices = newTextureVertices.OrderBy(item => item.Value).Select(item => item.Key).ToList(); - Debug.WriteLine("Done in " + sw.ElapsedMilliseconds + "ms"); + Debug.WriteLine("Waiting for save tasks to finish"); sw.Restart(); @@ -440,8 +367,7 @@ private void LoadTexturesCache() private static readonly JpegEncoder encoder = new JpegEncoder { Quality = 75 }; - private void BinPackTextures(string targetFolder, int materialIndex, IReadOnlyList> clusters, - IDictionary newTextureVertices, ICollection tasks) + private void BinPackTextures(string targetFolder, int materialIndex, IReadOnlyList> clusters, ICollection tasks) { var material = _materials[materialIndex]; @@ -548,39 +474,13 @@ private void BinPackTextures(string targetFolder, int materialIndex, IReadOnlyLi var faceIndex = cluster[index]; var face = _faces[faceIndex]; - var vtA = _textureVertices[face.TextureIndexA]; - var vtB = _textureVertices[face.TextureIndexB]; - var vtC = _textureVertices[face.TextureIndexC]; - // Traslation relative to the cluster (percentage) - var vtAdx = Math.Max(0, vtA.X - clusterBoundary.X) * textureScaleX; - var vtAdy = Math.Max(0, vtA.Y - clusterBoundary.Y) * textureScaleY; - - var vtBdx = Math.Max(0, vtB.X - clusterBoundary.X) * textureScaleX; - var vtBdy = Math.Max(0, vtB.Y - clusterBoundary.Y) * textureScaleY; - - var vtCdx = Math.Max(0, vtC.X - clusterBoundary.X) * textureScaleX; - var vtCdy = Math.Max(0, vtC.Y - clusterBoundary.Y) * textureScaleY; // Cluster relative positions (percentage) var relativeClusterX = newTextureClusterRect.X / (double)edgeLength; var relativeClusterY = newTextureClusterRect.Y / (double)edgeLength; - // New vertex coordinates - var newVtA = new Vertex2(Math.Clamp(relativeClusterX + vtAdx, 0, 1), - Math.Clamp(relativeClusterY + vtAdy, 0, 1)); - var newVtB = new Vertex2(Math.Clamp(relativeClusterX + vtBdx, 0, 1), - Math.Clamp(relativeClusterY + vtBdy, 0, 1)); - var newVtC = new Vertex2(Math.Clamp(relativeClusterX + vtCdx, 0, 1), - Math.Clamp(relativeClusterY + vtCdy, 0, 1)); - - var newIndexVtA = newTextureVertices.AddIndex(newVtA); - var newIndexVtB = newTextureVertices.AddIndex(newVtB); - var newIndexVtC = newTextureVertices.AddIndex(newVtC); - - face.TextureIndexA = newIndexVtA; - face.TextureIndexB = newIndexVtB; - face.TextureIndexC = newIndexVtC; + face.MaterialIndex = materialIndex; } } @@ -664,15 +564,6 @@ private RectangleF GetClusterRect(IReadOnlyList cluster) { var face = _faces[cluster[n]]; - var vtA = _textureVertices[face.TextureIndexA]; - var vtB = _textureVertices[face.TextureIndexB]; - var vtC = _textureVertices[face.TextureIndexC]; - - maxX = Math.Max(Math.Max(Math.Max(maxX, vtC.X), vtB.X), vtA.X); - maxY = Math.Max(Math.Max(Math.Max(maxY, vtC.Y), vtB.Y), vtA.Y); - - minX = Math.Min(Math.Min(Math.Min(minX, vtC.X), vtB.X), vtA.X); - minY = Math.Min(Math.Min(Math.Min(minY, vtC.Y), vtB.Y), vtA.Y); } return new RectangleF((float)minX, (float)minY, (float)(maxX - minX), (float)(maxY - minY)); @@ -685,12 +576,6 @@ private double GetTextureArea(IReadOnlyList facesIndexes) for (var index = 0; index < facesIndexes.Count; index++) { var faceIndex = facesIndexes[index]; - - var vtA = _textureVertices[_faces[faceIndex].TextureIndexA]; - var vtB = _textureVertices[_faces[faceIndex].TextureIndexB]; - var vtC = _textureVertices[_faces[faceIndex].TextureIndexC]; - - area += Common.Area(vtA, vtB, vtC); } return area; @@ -781,23 +666,6 @@ private Dictionary> GetEdgesMapper(IReadOnlyList facesIndex { var faceIndex = facesIndexes[idx]; var f = _faces[faceIndex]; - - var e1 = new Edge(f.TextureIndexA, f.TextureIndexB); - var e2 = new Edge(f.TextureIndexB, f.TextureIndexC); - var e3 = new Edge(f.TextureIndexA, f.TextureIndexC); - - if (!edgesMapper.ContainsKey(e1)) - edgesMapper.Add(e1, new List()); - - if (!edgesMapper.ContainsKey(e2)) - edgesMapper.Add(e2, new List()); - - if (!edgesMapper.ContainsKey(e3)) - edgesMapper.Add(e3, new List()); - - edgesMapper[e1].Add(faceIndex); - edgesMapper[e2].Add(faceIndex); - edgesMapper[e3].Add(faceIndex); } return edgesMapper; @@ -902,7 +770,7 @@ public Vertex3 GetVertexBaricenter() public void WriteObj(string path, bool removeUnused = true) { - if (!_materials.Any() || !_textureVertices.Any()) + if (!_materials.Any()) _WriteObjWithoutTexture(path, removeUnused); else _WriteObjWithTexture(path, removeUnused); @@ -942,7 +810,6 @@ private void RemoveUnusedVertices() private void RemoveUnusedVerticesAndUvs() { var newVertexes = new Dictionary(_vertices.Count); - var newUvs = new Dictionary(_textureVertices.Count); var newMaterials = new Dictionary(_materials.Count); for (var f = 0; f < _faces.Count; f++) @@ -970,27 +837,6 @@ private void RemoveUnusedVerticesAndUvs() face.IndexC = newVC; - // Texture vertices - - var uvA = _textureVertices[face.TextureIndexA]; - var uvB = _textureVertices[face.TextureIndexB]; - var uvC = _textureVertices[face.TextureIndexC]; - - if (!newUvs.TryGetValue(uvA, out var newUvA)) - newUvA = newUvs.AddIndex(uvA); - - face.TextureIndexA = newUvA; - - if (!newUvs.TryGetValue(uvB, out var newUvB)) - newUvB = newUvs.AddIndex(uvB); - - face.TextureIndexB = newUvB; - - if (!newUvs.TryGetValue(uvC, out var newUvC)) - newUvC = newUvs.AddIndex(uvC); - - face.TextureIndexC = newUvC; - // Materials var material = _materials[face.MaterialIndex]; @@ -1002,7 +848,6 @@ private void RemoveUnusedVerticesAndUvs() } _vertices = newVertexes.Keys.ToList(); - _textureVertices = newUvs.Keys.ToList(); _materials = newMaterials.Keys.ToList(); } @@ -1014,8 +859,8 @@ private void _WriteObjWithTexture(string path, bool removeUnused = true) var materialsPath = Path.ChangeExtension(path, "mtl"); - if (TexturesStrategy == TexturesStrategy.Repack || TexturesStrategy == TexturesStrategy.RepackCompressed) - TrimTextures(Path.GetDirectoryName(path)); + // if (TexturesStrategy == TexturesStrategy.Repack || TexturesStrategy == TexturesStrategy.RepackCompressed) + // TrimTextures(Path.GetDirectoryName(path)); using (var writer = new FormattingStreamWriter(path, CultureInfo.InvariantCulture)) { @@ -1034,18 +879,11 @@ private void _WriteObjWithTexture(string path, bool removeUnused = true) writer.WriteLine(vertex.Z); } - foreach (var textureVertex in _textureVertices) - { - writer.Write("vt "); - writer.Write(textureVertex.X); - writer.Write(" "); - writer.WriteLine(textureVertex.Y); - } var materialFaces = from face in _faces - group face by face.MaterialIndex + group face by face.MaterialIndex into g - select g; + select g; // NOTE: If there are groups of faces without materials, they must be placed at the beginning foreach (var grp in materialFaces.OrderBy(item => item.Key)) diff --git a/Obj2Tiles.Library/Geometry/MeshUtils.cs b/Obj2Tiles.Library/Geometry/MeshUtils.cs index b697fc8..d3b850e 100644 --- a/Obj2Tiles.Library/Geometry/MeshUtils.cs +++ b/Obj2Tiles.Library/Geometry/MeshUtils.cs @@ -11,7 +11,7 @@ public static IMesh LoadMesh(string fileName) { return LoadMesh(fileName, out _); } - + public static IMesh LoadMesh(string fileName, out string[] dependencies) { using var reader = new StreamReader(fileName); @@ -20,6 +20,7 @@ public static IMesh LoadMesh(string fileName, out string[] dependencies) var textureVertices = new List(); var facesT = new List(); var faces = new List(); + var facesB = new List(); var materials = new List(); var materialsDict = new Dictionary(); var currentMaterial = string.Empty; @@ -49,86 +50,86 @@ public static IMesh LoadMesh(string fileName, out string[] dependencies) var vtx = new Vertex2( double.Parse(segs[1], CultureInfo.InvariantCulture), double.Parse(segs[2], CultureInfo.InvariantCulture)); - + if (vtx.X < 0 || vtx.Y < 0 || vtx.X > 1 || vtx.Y > 1) throw new Exception("Invalid texture coordinates: " + vtx); - + textureVertices.Add(vtx); break; case "vn" when segs.Length == 3: // Skipping normals break; case "usemtl" when segs.Length == 2: - { - if (!materialsDict.ContainsKey(segs[1])) - throw new Exception($"Material {segs[1]} not found"); - - currentMaterial = segs[1]; - break; - } - case "f" when segs.Length == 4: - { - var first = segs[1].Split('/'); - var second = segs[2].Split('/'); - var third = segs[3].Split('/'); - - var hasTexture = first.Length > 1 && first[1].Length > 0 && second.Length > 1 && - second[1].Length > 0 && third.Length > 1 && third[1].Length > 0; - - // We ignore this - // var hasNormals = vertexIndices[0][2] != null && vertexIndices[1][2] != null && vertexIndices[2][2] != null; - - var v1 = int.Parse(first[0]); - var v2 = int.Parse(second[0]); - var v3 = int.Parse(third[0]); - - if (hasTexture) { - var vt1 = int.Parse(first[1]); - var vt2 = int.Parse(second[1]); - var vt3 = int.Parse(third[1]); - - var faceT = new FaceT( - v1 - 1, - v2 - 1, - v3 - 1, - vt1 - 1, - vt2 - 1, - vt3 - 1, - materialsDict[currentMaterial]); - - facesT.Add(faceT); + if (!materialsDict.ContainsKey(segs[1])) + throw new Exception($"Material {segs[1]} not found"); + currentMaterial = segs[1]; + break; } - else + case "f" when segs.Length == 4: { - var face = new Face( - v1 - 1, - v2 - 1, - v3 - 1); - - faces.Add(face); + var first = segs[1].Split('/'); + var second = segs[2].Split('/'); + var third = segs[3].Split('/'); + + var hasTexture = first.Length > 1 && first[1].Length > 0 && second.Length > 1 && + second[1].Length > 0 && third.Length > 1 && third[1].Length > 0; + + // We ignore this + // var hasNormals = vertexIndices[0][2] != null && vertexIndices[1][2] != null && vertexIndices[2][2] != null; + + var v1 = int.Parse(first[0]); + var v2 = int.Parse(second[0]); + var v3 = int.Parse(third[0]); + + if (hasTexture) + { + + var vt1 = int.Parse(first[1]); + var vt2 = int.Parse(second[1]); + var vt3 = int.Parse(third[1]); + var faceT = new FaceT( + v1 - 1, + v2 - 1, + v3 - 1, + vt1 - 1, + vt2 - 1, + vt3 - 1, + materialsDict[currentMaterial]); + + facesT.Add(faceT); + } + else + { + var faceT = new FaceB( + v1 - 1, + v2 - 1, + v3 - 1, + materialsDict[currentMaterial]); + + facesB.Add(faceT); + } + + break; } - - break; - } case "mtllib" when segs.Length == 2: - { - var mtlFileName = segs[1]; - var mtlFilePath = Path.Combine(Path.GetDirectoryName(fileName) ?? string.Empty, mtlFileName); - - var mats = Material.ReadMtl(mtlFilePath, out var mtlDeps); - - deps.AddRange(mtlDeps); - deps.Add(mtlFilePath); - - foreach (var mat in mats) { - materials.Add(mat); - materialsDict.Add(mat.Name, materials.Count - 1); - } + var mtlFileName = segs[1]; + var mtlFilePath = Path.Combine(Path.GetDirectoryName(fileName) ?? string.Empty, mtlFileName); - break; - } + var mats = Material.ReadMtl(mtlFilePath, out var mtlDeps); + + deps.AddRange(mtlDeps); + deps.Add(mtlFilePath); + + foreach (var mat in mats) + { + materials.Add(mat); + materialsDict.Add(mat.Name, materials.Count - 1); + } + + break; + } case "l" or "cstype" or "deg" or "bmat" or "step" or "curv" or "curv2" or "surf" or "parm" or "trim" or "end" or "hole" or "scrv" or "sp" or "con": @@ -137,10 +138,12 @@ public static IMesh LoadMesh(string fileName, out string[] dependencies) } dependencies = deps.ToArray(); - - return textureVertices.Any() - ? new MeshT(vertices, textureVertices, facesT, materials) - : new Mesh(vertices, faces); + Console.WriteLine($" -> facesB-------------------------\"{facesB}\""); + // return new Mesh(vertices, facesB, materials); + return new MeshT(vertices, facesB, materials); + // return textureVertices.Any() + // ? new MeshT(vertices, textureVertices, facesT, materials) + // : new Mesh(vertices, facesB, materials); } #region Splitters diff --git a/Obj2Tiles.Library/Materials/Material.cs b/Obj2Tiles.Library/Materials/Material.cs index 64d5286..8e20427 100644 --- a/Obj2Tiles.Library/Materials/Material.cs +++ b/Obj2Tiles.Library/Materials/Material.cs @@ -68,6 +68,7 @@ public static Material[] ReadMtl(string path, out string[] dependencies) continue; var parts = line.Split(' '); + // Console.WriteLine("Parts", parts[0]); switch (parts[0]) { case "newmtl": @@ -83,9 +84,9 @@ public static Material[] ReadMtl(string path, out string[] dependencies) texture = Path.IsPathRooted(parts[1]) ? parts[1] : Path.GetFullPath(Path.Combine(Path.GetDirectoryName(path)!, parts[1])); - + deps.Add(texture); - + break; case "Ka": ambientColor = new RGB( @@ -127,7 +128,7 @@ public static Material[] ReadMtl(string path, out string[] dependencies) illuminationModel)); dependencies = deps.ToArray(); - + return materials.ToArray(); } diff --git a/Obj2Tiles/Program.cs b/Obj2Tiles/Program.cs index 57a51dc..123c563 100644 --- a/Obj2Tiles/Program.cs +++ b/Obj2Tiles/Program.cs @@ -34,13 +34,13 @@ private static async Task Run(Options opts) opts.Output = Path.GetFullPath(opts.Output); opts.Input = Path.GetFullPath(opts.Input); - + Directory.CreateDirectory(opts.Output); var pipelineId = Guid.NewGuid().ToString(); var sw = new Stopwatch(); var swg = Stopwatch.StartNew(); - + Func createTempFolder = opts.UseSystemTempFolder ? s => CreateTempFolder(s, Path.GetTempPath()) : s => CreateTempFolder(s, Path.Combine(opts.Output, ".temp")); @@ -50,7 +50,7 @@ private static async Task Run(Options opts) try { - + destFolderDecimation = opts.StopAt == Stage.Decimation ? opts.Output : createTempFolder($"{pipelineId}-obj2tiles-decimation"); @@ -109,7 +109,7 @@ private static async Task Run(Options opts) { Console.WriteLine( $" ?> Skipping cleanup, intermediate files are in '{tmpFolder}' with pipeline id '{pipelineId}'"); - + Console.WriteLine(" ?> You should delete this folder manually, it is only for debugging purposes"); } else @@ -132,38 +132,38 @@ private static async Task Run(Options opts) } private static bool CheckOptions(Options opts) - { + { if (string.IsNullOrWhiteSpace(opts.Input)) { Console.WriteLine(" !> Input file is required"); return false; } - + if (!File.Exists(opts.Input)) { Console.WriteLine(" !> Input file does not exist"); return false; } - + if (string.IsNullOrWhiteSpace(opts.Output)) { Console.WriteLine(" !> Output folder is required"); return false; } - + if (opts.LODs < 1) { Console.WriteLine(" !> LODs must be at least 1"); return false; } - + if (opts.Divisions < 0) { Console.WriteLine(" !> Divisions must be non-negative"); return false; } - + return true; } diff --git a/Obj2Tiles/Stages/SplitStage.cs b/Obj2Tiles/Stages/SplitStage.cs index 2fa97fa..405da1a 100644 --- a/Obj2Tiles/Stages/SplitStage.cs +++ b/Obj2Tiles/Stages/SplitStage.cs @@ -3,6 +3,7 @@ using System.Text.Json; using Obj2Tiles.Library.Geometry; + namespace Obj2Tiles.Stages; public static partial class StagesFacade @@ -10,14 +11,14 @@ public static partial class StagesFacade public static async Task[]> Split(string[] sourceFiles, string destFolder, int divisions, bool zsplit, Box3 bounds, bool keepOriginalTextures = false) { - + var tasks = new List>>(); for (var index = 0; index < sourceFiles.Length; index++) { var file = sourceFiles[index]; var dest = Path.Combine(destFolder, "LOD-" + index); - + // We compress textures except the first one (the original one) var textureStrategy = keepOriginalTextures ? TexturesStrategy.KeepOriginal : index == 0 ? TexturesStrategy.Repack : TexturesStrategy.RepackCompressed; @@ -42,7 +43,7 @@ public static async Task> Split(string sourcePath, stri var tilesBounds = new Dictionary(); Directory.CreateDirectory(destPath); - + Console.WriteLine($" -> Loading OBJ file \"{sourcePath}\""); sw.Start(); @@ -57,13 +58,13 @@ public static async Task> Split(string sourcePath, stri if (mesh is MeshT t) t.TexturesStrategy = TexturesStrategy.Compress; - + mesh.WriteObj(Path.Combine(destPath, $"{mesh.Name}.obj")); - + return new Dictionary { { mesh.Name, mesh.Bounds } }; - + } - + Console.WriteLine( $" -> Splitting with a depth of {divisions}{(zSplit ? " with z-split" : "")}"); @@ -73,6 +74,7 @@ public static async Task> Split(string sourcePath, stri int count; + Console.WriteLine($"bounds===================={bounds}"); if (bounds != null) { count = zSplit @@ -95,8 +97,8 @@ public static async Task> Split(string sourcePath, stri sw.Stop(); - Console.WriteLine( - $" ?> Done {count} edge splits in {sw.ElapsedMilliseconds}ms ({(double)count / sw.ElapsedMilliseconds:F2} split/ms)"); + // Console.WriteLine( + // $" ?> Done {count} edge splits in {sw.ElapsedMilliseconds}ms ({(double)count / sw.ElapsedMilliseconds:F2} split/ms)"); Console.WriteLine(" -> Writing tiles"); From ac0fb2804554959aa42b896ca005b23459834573 Mon Sep 17 00:00:00 2001 From: angelswing Date: Mon, 27 Feb 2023 08:29:48 +0545 Subject: [PATCH 2/2] feat: updated mtl file path --- Obj2Tiles.Library.Test/Mesh3Tests.cs | 44 +-- Obj2Tiles.Library/Geometry/Mesh.cs | 80 ++--- Obj2Tiles.Library/Geometry/MeshT.cs | 397 ------------------------ Obj2Tiles.Library/Geometry/MeshUtils.cs | 56 ++-- Obj2Tiles.Library/Materials/Material.cs | 1 - Obj2Tiles/Program.cs | 2 +- Obj2Tiles/Stages/SplitStage.cs | 8 +- 7 files changed, 94 insertions(+), 494 deletions(-) diff --git a/Obj2Tiles.Library.Test/Mesh3Tests.cs b/Obj2Tiles.Library.Test/Mesh3Tests.cs index 06a67ff..de052ed 100644 --- a/Obj2Tiles.Library.Test/Mesh3Tests.cs +++ b/Obj2Tiles.Library.Test/Mesh3Tests.cs @@ -44,17 +44,17 @@ public void WriteObj_Square_RemoveUnused() { var testPath = GetTestOutputPath(nameof(WriteObj_Square_RemoveUnused)); - var mesh = MeshUtils.LoadMesh(Path.Combine(TestDataPath, "square-unused.obj")); - + var mesh = MeshUtils.LoadMesh(Path.Combine(TestDataPath, "square-unused.obj"), ""); + mesh.WriteObj(Path.Combine(testPath, "square.obj")); } - + [Test] public void WriteObj_Cube2_Repacking() { var testPath = GetTestOutputPath(nameof(WriteObj_Cube2_Repacking)); - var mesh = (MeshT)MeshUtils.LoadMesh(Path.Combine(TestDataPath, "cube2/cube.obj")); + var mesh = (MeshT)MeshUtils.LoadMesh(Path.Combine(TestDataPath, "cube2/cube.obj"), ""); mesh.TexturesStrategy = TexturesStrategy.Repack; @@ -66,7 +66,7 @@ public void WriteObj_Cube2_PreserveOriginalTextures() { var testPath = GetTestOutputPath(nameof(WriteObj_Cube2_PreserveOriginalTextures)); - var mesh = (MeshT)MeshUtils.LoadMesh(Path.Combine(TestDataPath, "cube2/cube.obj")); + var mesh = (MeshT)MeshUtils.LoadMesh(Path.Combine(TestDataPath, "cube2/cube.obj"), ""); mesh.TexturesStrategy = TexturesStrategy.KeepOriginal; mesh.WriteObj(Path.Combine(testPath, "mesh.obj")); @@ -77,7 +77,7 @@ public void WriteObj_Cube_Repacking() { var testPath = GetTestOutputPath(nameof(WriteObj_Cube_Repacking)); - var mesh = (MeshT)MeshUtils.LoadMesh(Path.Combine(TestDataPath, "cube/cube.obj")); + var mesh = (MeshT)MeshUtils.LoadMesh(Path.Combine(TestDataPath, "cube/cube.obj"), ""); mesh.TexturesStrategy = TexturesStrategy.Repack; @@ -89,7 +89,7 @@ public void WriteObj_Cube_PreserveOriginalTextures() { var testPath = GetTestOutputPath(nameof(WriteObj_Cube_PreserveOriginalTextures)); - var mesh = (MeshT)MeshUtils.LoadMesh(Path.Combine(TestDataPath, "cube/cube.obj")); + var mesh = (MeshT)MeshUtils.LoadMesh(Path.Combine(TestDataPath, "cube/cube.obj"), ""); mesh.TexturesStrategy = TexturesStrategy.KeepOriginal; mesh.WriteObj(Path.Combine(testPath, "mesh.obj")); @@ -100,7 +100,7 @@ public void WriteObj_Brighton_Repacking() { using var fs = new TestFS(BrightonTexturingTestUrl, nameof(Mesh3Tests)); - var mesh = (MeshT)MeshUtils.LoadMesh(Path.Combine(fs.TestFolder, "odm_textured_model_geo.obj")); + var mesh = (MeshT)MeshUtils.LoadMesh(Path.Combine(fs.TestFolder, "odm_textured_model_geo.obj"), ""); mesh.TexturesStrategy = TexturesStrategy.Repack; var outputPath = Path.Combine(fs.TestFolder, "output"); @@ -116,7 +116,7 @@ public void WriteObj_Canyon_Repacking() { var testPath = GetTestOutputPath(nameof(WriteObj_Canyon_Repacking)); - var mesh = (MeshT)MeshUtils.LoadMesh(@"C:\datasets\canyon\odm_texturing\odm_textured_model_geo.obj"); + var mesh = (MeshT)MeshUtils.LoadMesh(@"C:\datasets\canyon\odm_texturing\odm_textured_model_geo.obj", ""); mesh.TexturesStrategy = TexturesStrategy.Repack; @@ -128,7 +128,7 @@ public void WriteObj_Splitted_Cube_PreserveOriginalTextures() { var testPath = GetTestOutputPath(nameof(WriteObj_Splitted_Cube_PreserveOriginalTextures)); - var mesh = MeshUtils.LoadMesh(Path.Combine(TestDataPath, "cube/cube.obj")); + var mesh = MeshUtils.LoadMesh(Path.Combine(TestDataPath, "cube/cube.obj"), ""); var center = mesh.GetVertexBaricenter(); @@ -146,7 +146,7 @@ public void WriteObj_SplittedX_Cube_Repacking() { var testPath = GetTestOutputPath(nameof(WriteObj_SplittedX_Cube_Repacking)); - var mesh = MeshUtils.LoadMesh(Path.Combine(TestDataPath, "cube/cube.obj")); + var mesh = MeshUtils.LoadMesh(Path.Combine(TestDataPath, "cube/cube.obj"), ""); var center = mesh.GetVertexBaricenter(); @@ -164,7 +164,7 @@ public void WriteObj_SplittedX_Cube_PreserveOriginalTextures() { var testPath = GetTestOutputPath(nameof(WriteObj_SplittedX_Cube_PreserveOriginalTextures)); - var mesh = MeshUtils.LoadMesh(Path.Combine(TestDataPath, "cube/cube.obj")); + var mesh = MeshUtils.LoadMesh(Path.Combine(TestDataPath, "cube/cube.obj"), ""); var center = mesh.GetVertexBaricenter(); @@ -182,7 +182,7 @@ public void WriteObj_Splitted_Cube2_PreserveOriginalTextures() { var testPath = GetTestOutputPath(nameof(WriteObj_Splitted_Cube2_PreserveOriginalTextures)); - var mesh = MeshUtils.LoadMesh(Path.Combine(TestDataPath, "cube2/cube.obj")); + var mesh = MeshUtils.LoadMesh(Path.Combine(TestDataPath, "cube2/cube.obj"), ""); var center = mesh.GetVertexBaricenter(); @@ -200,7 +200,7 @@ public void WriteObj_Splitted_Cube2_Repacking() { var testPath = GetTestOutputPath(nameof(WriteObj_Splitted_Cube2_Repacking)); - var mesh = MeshUtils.LoadMesh(Path.Combine(TestDataPath, "cube2/cube.obj")); + var mesh = MeshUtils.LoadMesh(Path.Combine(TestDataPath, "cube2/cube.obj"), ""); var center = mesh.GetVertexBaricenter(); @@ -259,22 +259,22 @@ public void Orientation_TestOk() var v1 = new Vertex3(0, 0, 0); var v2 = new Vertex3(1, 0, 0); var v3 = new Vertex3(0, 1, 0); - + var o = Common.Orientation(v1, v2, v3); o.Z.Should().Be(1); o.X.Should().Be(0); o.Y.Should().Be(0); } - - + + [Test] public void Orientation_TestZero() { var v1 = new Vertex3(0, 0, 0); var v2 = new Vertex3(0, 0, 0); var v3 = new Vertex3(0, 0, 0); - + var o = Common.Orientation(v1, v2, v3); o.Z.Should().Be(0); @@ -285,7 +285,7 @@ public void Orientation_TestZero() [Test] public void Orientation_TestCubeMesh() { - var mesh = (MeshT)MeshUtils.LoadMesh(Path.Combine(TestDataPath, "cube2/cube.obj")); + var mesh = (MeshT)MeshUtils.LoadMesh(Path.Combine(TestDataPath, "cube2/cube.obj"), ""); var orientation = mesh.GetAverageOrientation(); @@ -293,14 +293,14 @@ public void Orientation_TestCubeMesh() orientation.Y.Should().Be(0); orientation.Z.Should().Be(0); } - + [Test] public void Orientation_TestBrighton() { - + using var fs = new TestFS(BrightonTexturingTestUrl, nameof(Mesh3Tests)); - var mesh = (MeshT)MeshUtils.LoadMesh(Path.Combine(fs.TestFolder, "odm_textured_model_geo.obj")); + var mesh = (MeshT)MeshUtils.LoadMesh(Path.Combine(fs.TestFolder, "odm_textured_model_geo.obj"), ""); var orientation = mesh.GetAverageOrientation(); diff --git a/Obj2Tiles.Library/Geometry/Mesh.cs b/Obj2Tiles.Library/Geometry/Mesh.cs index 6cb2cc9..c178901 100644 --- a/Obj2Tiles.Library/Geometry/Mesh.cs +++ b/Obj2Tiles.Library/Geometry/Mesh.cs @@ -9,24 +9,19 @@ namespace Obj2Tiles.Library.Geometry; public class Mesh : IMesh { private List _vertices; - private readonly List _faces; - private List _materials; - + private readonly List _faces; public IReadOnlyList Vertices => _vertices; - public IReadOnlyList Faces => _faces; - public IReadOnlyList Materials => _materials; + public IReadOnlyList Faces => _faces; public const string DefaultName = "Mesh"; public string Name { get; set; } = DefaultName; - public Mesh(IEnumerable vertices, - IEnumerable faces, IEnumerable materials) + public Mesh(IEnumerable vertices, IEnumerable faces) { _vertices = new List(vertices); - _faces = new List(faces); - _materials = new List(materials); + _faces = new List(faces); } public int Split(IVertexUtils utils, double q, out IMesh left, @@ -35,15 +30,14 @@ public int Split(IVertexUtils utils, double q, out IMesh left, var leftVertices = new Dictionary(_vertices.Count); var rightVertices = new Dictionary(_vertices.Count); - var leftFaces = new List(_faces.Count); - var rightFaces = new List(_faces.Count); + var leftFaces = new List(_faces.Count); + var rightFaces = new List(_faces.Count); var count = 0; for (var index = 0; index < _faces.Count; index++) { var face = _faces[index]; - var faceMaterial = _materials[index]; var vA = _vertices[face.IndexA]; var vB = _vertices[face.IndexB]; @@ -65,12 +59,12 @@ public int Split(IVertexUtils utils, double q, out IMesh left, var indexBLeft = leftVertices.AddIndex(vB); var indexCLeft = leftVertices.AddIndex(vC); - leftFaces.Add(new FaceB(indexALeft, indexBLeft, indexCLeft, face.MaterialIndex)); + leftFaces.Add(new Face(indexALeft, indexBLeft, indexCLeft)); } else { IntersectRight2D(utils, q, face.IndexC, face.IndexA, face.IndexB, leftVertices, rightVertices, - leftFaces, rightFaces, face.MaterialIndex); + leftFaces, rightFaces); count++; } } @@ -79,13 +73,13 @@ public int Split(IVertexUtils utils, double q, out IMesh left, if (cSide) { IntersectRight2D(utils, q, face.IndexB, face.IndexC, face.IndexA, leftVertices, rightVertices, - leftFaces, rightFaces, face.MaterialIndex); + leftFaces, rightFaces); count++; } else { IntersectLeft2D(utils, q, face.IndexA, face.IndexB, face.IndexC, leftVertices, rightVertices, - leftFaces, rightFaces, face.MaterialIndex); + leftFaces, rightFaces); count++; } } @@ -97,13 +91,13 @@ public int Split(IVertexUtils utils, double q, out IMesh left, if (cSide) { IntersectRight2D(utils, q, face.IndexA, face.IndexB, face.IndexC, leftVertices, rightVertices, - leftFaces, rightFaces, face.MaterialIndex); + leftFaces, rightFaces); count++; } else { IntersectLeft2D(utils, q, face.IndexB, face.IndexC, face.IndexA, leftVertices, rightVertices, - leftFaces, rightFaces, face.MaterialIndex); + leftFaces, rightFaces); count++; } } @@ -112,7 +106,7 @@ public int Split(IVertexUtils utils, double q, out IMesh left, if (cSide) { IntersectLeft2D(utils, q, face.IndexC, face.IndexA, face.IndexB, leftVertices, rightVertices, - leftFaces, rightFaces, face.MaterialIndex); + leftFaces, rightFaces); count++; } else @@ -122,7 +116,7 @@ public int Split(IVertexUtils utils, double q, out IMesh left, var indexARight = rightVertices.AddIndex(vA); var indexBRight = rightVertices.AddIndex(vB); var indexCRight = rightVertices.AddIndex(vC); - rightFaces.Add(new FaceB(indexARight, indexBRight, indexCRight, face.MaterialIndex)); + rightFaces.Add(new Face(indexARight, indexBRight, indexCRight)); } } } @@ -130,28 +124,24 @@ public int Split(IVertexUtils utils, double q, out IMesh left, var orderedLeftVertices = leftVertices.OrderBy(x => x.Value).Select(x => x.Key); var orderedRightVertices = rightVertices.OrderBy(x => x.Value).Select(x => x.Key); - var rightMaterials = _materials.Select(mat => (Material)mat.Clone()); - var leftMaterials = _materials.Select(mat => (Material)mat.Clone()); - - left = new Mesh(orderedLeftVertices, leftFaces, leftMaterials) + left = new Mesh(orderedLeftVertices, leftFaces) { Name = $"{Name}-{utils.Axis}L" }; - right = new Mesh(orderedRightVertices, rightFaces, rightMaterials) + right = new Mesh(orderedRightVertices, rightFaces) { Name = $"{Name}-{utils.Axis}R" }; - return count; } private void IntersectLeft2D(IVertexUtils utils, double q, int indexVL, int indexVR1, int indexVR2, IDictionary leftVertices, - IDictionary rightVertices, ICollection leftFaces, - ICollection rightFaces, int materialIndex) + IDictionary rightVertices, ICollection leftFaces, + ICollection rightFaces) { var vL = _vertices[indexVL]; var vR1 = _vertices[indexVR1]; @@ -167,7 +157,7 @@ private void IntersectLeft2D(IVertexUtils utils, double q, int indexVL, int inde var indexVR1Left = leftVertices.AddIndex(vR1); var indexVR2Left = leftVertices.AddIndex(vR2); - leftFaces.Add(new FaceB(indexVLLeft, indexVR1Left, indexVR2Left, materialIndex)); + leftFaces.Add(new Face(indexVLLeft, indexVR1Left, indexVR2Left)); return; } @@ -186,19 +176,19 @@ private void IntersectLeft2D(IVertexUtils utils, double q, int indexVL, int inde var indexT2Left = leftVertices.AddIndex(t2); var indexT2Right = rightVertices.AddIndex(t2); - var lface = new FaceB(indexVLLeft, indexT1Left, indexT2Left, materialIndex); + var lface = new Face(indexVLLeft, indexT1Left, indexT2Left); leftFaces.Add(lface); - var rface1 = new FaceB(indexT1Right, indexVR1Right, indexVR2Right, materialIndex); + var rface1 = new Face(indexT1Right, indexVR1Right, indexVR2Right); rightFaces.Add(rface1); - var rface2 = new FaceB(indexT1Right, indexVR2Right, indexT2Right, materialIndex); + var rface2 = new Face(indexT1Right, indexVR2Right, indexT2Right); rightFaces.Add(rface2); } private void IntersectRight2D(IVertexUtils utils, double q, int indexVR, int indexVL1, int indexVL2, IDictionary leftVertices, IDictionary rightVertices, - ICollection leftFaces, ICollection rightFaces, int materialIndex) + ICollection leftFaces, ICollection rightFaces) { var vR = _vertices[indexVR]; var vL1 = _vertices[indexVL1]; @@ -213,7 +203,7 @@ private void IntersectRight2D(IVertexUtils utils, double q, int indexVR, int ind var indexVL1Right = rightVertices.AddIndex(vL1); var indexVL2Right = rightVertices.AddIndex(vL2); - rightFaces.Add(new FaceB(indexVRRight, indexVL1Right, indexVL2Right, materialIndex)); + rightFaces.Add(new Face(indexVRRight, indexVL1Right, indexVL2Right)); return; } @@ -233,13 +223,13 @@ private void IntersectRight2D(IVertexUtils utils, double q, int indexVR, int ind var indexT2Left = leftVertices.AddIndex(t2); var indexT2Right = rightVertices.AddIndex(t2); - var rface = new FaceB(indexVRRight, indexT1Right, indexT2Right, materialIndex); + var rface = new Face(indexVRRight, indexT1Right, indexT2Right); rightFaces.Add(rface); - var lface1 = new FaceB(indexT2Left, indexVL1Left, indexVL2Left, materialIndex); + var lface1 = new Face(indexT2Left, indexVL1Left, indexVL2Left); leftFaces.Add(lface1); - var lface2 = new FaceB(indexT2Left, indexT1Left, indexVL1Left, materialIndex); + var lface2 = new Face(indexT2Left, indexT1Left, indexVL1Left); leftFaces.Add(lface2); } @@ -296,6 +286,7 @@ public Vertex3 GetVertexBaricenter() public void WriteObj(string path, bool removeUnused = true) { + if (removeUnused) RemoveUnusedVertices(); using var writer = new FormattingStreamWriter(path, CultureInfo.InvariantCulture); @@ -314,17 +305,10 @@ public void WriteObj(string path, bool removeUnused = true) writer.WriteLine(vertex.Z); } - var materialFaces = from face in _faces - group face by face.MaterialIndex - into g - select g; - - foreach (var grp in materialFaces.OrderBy(item => item.Key)) + for (var index = 0; index < _faces.Count; index++) { - writer.WriteLine($"usemtl {_materials[grp.Key].Name}"); - - foreach (var face in grp) - writer.WriteLine(face.ToObj()); + var face = _faces[index]; + writer.WriteLine(face.ToObj()); } } @@ -368,4 +352,4 @@ private void RemoveUnusedVertices() #endregion -} +} \ No newline at end of file diff --git a/Obj2Tiles.Library/Geometry/MeshT.cs b/Obj2Tiles.Library/Geometry/MeshT.cs index f2890b0..fcad43e 100644 --- a/Obj2Tiles.Library/Geometry/MeshT.cs +++ b/Obj2Tiles.Library/Geometry/MeshT.cs @@ -292,398 +292,6 @@ private void IntersectRight2DWithTexture(IVertexUtils utils, double q, int index leftFaces.Add(lface2); } - private void TrimTextures(string targetFolder) - { - Debug.WriteLine("Trimming textures of " + Name); - - var tasks = new List(); - - LoadTexturesCache(); - - var facesByMaterial = GetFacesByMaterial(); - - - var sw = new Stopwatch(); - - for (var m = 0; m < facesByMaterial.Count; m++) - { - var material = _materials[m]; - var facesIndexes = facesByMaterial[m]; - Debug.WriteLine($"Working on material {m} -> {material.Name}"); - - if (facesIndexes.Count == 0) - { - Debug.WriteLine("No faces with this material"); - continue; - } - - sw.Restart(); - - Debug.WriteLine("Creating edges mapper"); - var edgesMapper = GetEdgesMapper(facesIndexes); - Debug.WriteLine("Done in " + sw.ElapsedMilliseconds + "ms"); - sw.Restart(); - - Debug.WriteLine("Creating faces mapper"); - var facesMapper = GetFacesMapper(edgesMapper); - Debug.WriteLine("Done in " + sw.ElapsedMilliseconds + "ms"); - sw.Restart(); - - Debug.WriteLine("Assembling faces clusters"); - var clusters = GetFacesClusters(facesIndexes, facesMapper); - Debug.WriteLine("Done in " + sw.ElapsedMilliseconds + "ms"); - sw.Restart(); - - Debug.WriteLine("Sorting clusters"); - - // Sort clusters by count (improves packing density, could be removed if we notice a bottleneck) - clusters.Sort((a, b) => b.Count.CompareTo(a.Count)); - Debug.WriteLine("Done in " + sw.ElapsedMilliseconds + "ms"); - sw.Restart(); - - Debug.WriteLine($"Material {material.Name} has {clusters.Count} clusters"); - - Debug.WriteLine("Bin packing clusters"); - // BinPackTextures(targetFolder, m, clusters, tasks); - Debug.WriteLine("Done in " + sw.ElapsedMilliseconds + "ms"); - } - - - - Debug.WriteLine("Waiting for save tasks to finish"); - sw.Restart(); - Task.WaitAll(tasks.ToArray()); - Debug.WriteLine("Done in " + sw.ElapsedMilliseconds + "ms"); - } - - private void LoadTexturesCache() - { - Parallel.ForEach(_materials, material => - { - if (!string.IsNullOrEmpty(material.Texture)) - TexturesCache.GetTexture(material.Texture); - }); - } - - private static readonly JpegEncoder encoder = new JpegEncoder { Quality = 75 }; - - private void BinPackTextures(string targetFolder, int materialIndex, IReadOnlyList> clusters, ICollection tasks) - { - var material = _materials[materialIndex]; - - if (material.Texture == null) - return; - - var texture = TexturesCache.GetTexture(material.Texture); - - var textureWidth = texture.Width; - var textureHeight = texture.Height; - var clustersRects = clusters.Select(GetClusterRect).ToArray(); - - CalculateMaxMinAreaRect(clustersRects, textureWidth, textureHeight, out var maxWidth, out var maxHeight, - out var textureArea); - - Debug.WriteLine("Texture area: " + textureArea); - - var edgeLength = Math.Max(Common.NextPowerOfTwo((int)Math.Sqrt(textureArea)), 32); - - if (edgeLength < maxWidth) - edgeLength = Common.NextPowerOfTwo((int)maxWidth); - - if (edgeLength < maxHeight) - edgeLength = Common.NextPowerOfTwo((int)maxHeight); - - Debug.WriteLine("Edge length: " + edgeLength); - - // NOTE: We could enable rotations but it would be a bit more complex - var binPack = new MaxRectanglesBinPack(edgeLength, edgeLength, false); - - var newTexture = new Image(edgeLength, edgeLength); - - string? textureFileName, newPath; - var count = 0; - - for (var i = 0; i < clusters.Count; i++) - { - var cluster = clusters[i]; - Debug.WriteLine("Processing cluster with " + cluster.Count + " faces"); - - var clusterBoundary = clustersRects[i]; - - Debug.WriteLine("Cluster boundary (percentage): " + clusterBoundary); - - var clusterX = (int)Math.Floor(clusterBoundary.Left * textureWidth); - var clusterY = (int)Math.Floor(clusterBoundary.Top * textureHeight); - var clusterWidth = (int)Math.Max(Math.Ceiling(clusterBoundary.Width * textureWidth), 1); - var clusterHeight = (int)Math.Max(Math.Ceiling(clusterBoundary.Height * textureHeight), 1); - - Debug.WriteLine( - $"Cluster boundary (pixel): ({clusterX},{clusterY}) size {clusterWidth}x{clusterHeight}"); - - var newTextureClusterRect = binPack.Insert(clusterWidth, clusterHeight, - FreeRectangleChoiceHeuristic.RectangleBestAreaFit); - - if (newTextureClusterRect.Width == 0) - { - Debug.WriteLine("Somehow we could not pack everything in the texture, splitting it in two"); - - textureFileName = $"{Name}-texture-{material.Name}{Path.GetExtension(material.Texture)}"; - newPath = Path.Combine(targetFolder, textureFileName); - newTexture.Save(newPath); - newTexture.Dispose(); - - newTexture = new Image(edgeLength, edgeLength); - binPack = new MaxRectanglesBinPack(edgeLength, edgeLength, false); - material.Texture = textureFileName; - - // Avoid texture name collision - count++; - - material = new Material(material.Name + "-" + count, textureFileName, material.AmbientColor, - material.DiffuseColor, - material.SpecularColor, material.SpecularExponent, material.Dissolve, material.IlluminationModel); - - _materials.Add(material); - materialIndex = _materials.Count - 1; - - // This is the second time we are here - newTextureClusterRect = binPack.Insert(clusterWidth, clusterHeight, - FreeRectangleChoiceHeuristic.RectangleBestAreaFit); - - if (newTextureClusterRect.Width == 0) - throw new Exception( - $"Find room for cluster in a newly created texture, this is not supposed to happen. {clusterWidth}x{clusterHeight} in {edgeLength}x{edgeLength} with occupancy {binPack.Occupancy()}"); - } - - Debug.WriteLine("Found place for cluster at " + newTextureClusterRect); - - // Too long to explain this here, but it works - var adjustedSourceY = Math.Max(texture.Height - (clusterY + clusterHeight), 0); - var adjustedDestY = Math.Max(edgeLength - (newTextureClusterRect.Y + clusterHeight), 0); - - Common.CopyImage(texture, newTexture, clusterX, adjustedSourceY, clusterWidth, clusterHeight, - newTextureClusterRect.X, adjustedDestY); - - var textureScaleX = (double)textureWidth / edgeLength; - var textureScaleY = (double)textureHeight / edgeLength; - - Debug.WriteLine("Texture copied, now updating texture vertex coordinates"); - - for (var index = 0; index < cluster.Count; index++) - { - var faceIndex = cluster[index]; - var face = _faces[faceIndex]; - - - - // Cluster relative positions (percentage) - var relativeClusterX = newTextureClusterRect.X / (double)edgeLength; - var relativeClusterY = newTextureClusterRect.Y / (double)edgeLength; - - - face.MaterialIndex = materialIndex; - } - } - - textureFileName = TexturesStrategy == TexturesStrategy.Repack - ? $"{Name}-texture-{material.Name}{Path.GetExtension(material.Texture)}" - : $"{Name}-texture-{material.Name}.jpg"; - - newPath = Path.Combine(targetFolder, textureFileName); - - var saveTask = new Task(t => - { - var tx = t as Image; - - switch (TexturesStrategy) - { - case TexturesStrategy.RepackCompressed: - tx.SaveAsJpeg(newPath, encoder); - break; - case TexturesStrategy.Repack: - tx.Save(newPath); - break; - case TexturesStrategy.Compress: - case TexturesStrategy.KeepOriginal: - throw new InvalidOperationException( - "KeepOriginal or Compress are meaningless here, we are repacking!"); - default: - throw new ArgumentOutOfRangeException(); - } - - Debug.WriteLine("Saved texture to " + newPath); - tx.Dispose(); - }, newTexture, TaskCreationOptions.LongRunning); - - tasks.Add(saveTask); - saveTask.Start(); - - material.Texture = textureFileName; - } - - private void CalculateMaxMinAreaRect(RectangleF[] clustersRects, int textureWidth, int textureHeight, - out double maxWidth, out double maxHeight, out double textureArea) - { - maxWidth = 0; - maxHeight = 0; - textureArea = 0; - - for (var index = 0; index < clustersRects.Length; index++) - { - var rect = clustersRects[index]; - - textureArea += Math.Max(Math.Ceiling(rect.Width * textureWidth), 1) * - Math.Max(Math.Ceiling(rect.Height * textureHeight), 1); - - if (rect.Width > maxWidth) - { - maxWidth = rect.Width; - } - - if (rect.Height > maxHeight) - { - maxHeight = rect.Height; - } - } - - maxWidth = Math.Ceiling(maxWidth * textureWidth); - maxHeight = Math.Ceiling(maxHeight * textureHeight); - } - - /// - /// Calculates the bounding box of a set of points. - /// - /// - /// - private RectangleF GetClusterRect(IReadOnlyList cluster) - { - double maxX = double.MinValue, maxY = double.MinValue; - double minX = double.MaxValue, minY = double.MaxValue; - - for (var n = 0; n < cluster.Count; n++) - { - var face = _faces[cluster[n]]; - - } - - return new RectangleF((float)minX, (float)minY, (float)(maxX - minX), (float)(maxY - minY)); - } - - private double GetTextureArea(IReadOnlyList facesIndexes) - { - double area = 0; - - for (var index = 0; index < facesIndexes.Count; index++) - { - var faceIndex = facesIndexes[index]; - } - - return area; - } - - private static List> GetFacesClusters(IEnumerable facesIndexes, - IReadOnlyDictionary> facesMapper) - { - Debug.Assert(facesIndexes.Any(), "No faces in this cluster"); - - var clusters = new List>(); - var remainingFacesIndexes = new List(facesIndexes); - - var currentCluster = new List { remainingFacesIndexes.First() }; - remainingFacesIndexes.RemoveAt(0); - - while (remainingFacesIndexes.Count > 0) - { - var cnt = currentCluster.Count; - - for (var index = 0; index < currentCluster.Count; index++) - { - var faceIndex = currentCluster[index]; - - if (!facesMapper.TryGetValue(faceIndex, out var connectedFaces)) - continue; - - for (var i = 0; i < connectedFaces.Count; i++) - { - var connectedFace = connectedFaces[i]; - if (currentCluster.Contains(connectedFace)) continue; - - currentCluster.Add(connectedFace); - remainingFacesIndexes.Remove(connectedFace); - } - } - - // No new face was added - if (cnt == currentCluster.Count) - { - // Add the cluster - clusters.Add(currentCluster); - - // If no more faces, exit - if (remainingFacesIndexes.Count == 0) break; - - // Let's continue with the next cluster - currentCluster = new List { remainingFacesIndexes.First() }; - remainingFacesIndexes.RemoveAt(0); - } - } - - // Add the cluster - clusters.Add(currentCluster); - return clusters; - } - - private static Dictionary> GetFacesMapper(Dictionary> edgesMapper) - { - var facesMapper = new Dictionary>(); - - foreach (var edge in edgesMapper) - { - for (var i = 0; i < edge.Value.Count; i++) - { - var faceIndex = edge.Value[i]; - if (!facesMapper.ContainsKey(faceIndex)) - facesMapper.Add(faceIndex, new List()); - - for (var index = 0; index < edge.Value.Count; index++) - { - var f = edge.Value[index]; - if (f != faceIndex) - facesMapper[faceIndex].Add(f); - } - } - } - - return facesMapper; - } - - private Dictionary> GetEdgesMapper(IReadOnlyList facesIndexes) - { - var edgesMapper = new Dictionary>(); - edgesMapper.EnsureCapacity(facesIndexes.Count * 3); - - for (var idx = 0; idx < facesIndexes.Count; idx++) - { - var faceIndex = facesIndexes[idx]; - var f = _faces[faceIndex]; - } - - return edgesMapper; - } - - private List> GetFacesByMaterial() - { - var res = _materials.Select(_ => new List()).ToList(); - - for (var i = 0; i < _faces.Count; i++) - { - var f = _faces[i]; - - res[f.MaterialIndex].Add(i); - } - - return res; - } #region Utils @@ -936,11 +544,6 @@ into g Console.WriteLine($" -> Compressing texture '{material.Texture}'"); - using (var image = Image.Load(material.Texture)) - { - image.SaveAsJpeg(newTexturePath, encoder); - } - material.Texture = textureFileName; } } diff --git a/Obj2Tiles.Library/Geometry/MeshUtils.cs b/Obj2Tiles.Library/Geometry/MeshUtils.cs index d3b850e..1991331 100644 --- a/Obj2Tiles.Library/Geometry/MeshUtils.cs +++ b/Obj2Tiles.Library/Geometry/MeshUtils.cs @@ -7,12 +7,12 @@ namespace Obj2Tiles.Library.Geometry; public class MeshUtils { - public static IMesh LoadMesh(string fileName) + public static IMesh LoadMesh(string fileName, string objFilePath) { - return LoadMesh(fileName, out _); + return LoadMesh(fileName, objFilePath, out _); } - public static IMesh LoadMesh(string fileName, out string[] dependencies) + public static IMesh LoadMesh(string fileName, string objFilePath, out string[] dependencies) { using var reader = new StreamReader(fileName); @@ -26,6 +26,20 @@ public static IMesh LoadMesh(string fileName, out string[] dependencies) var currentMaterial = string.Empty; var deps = new List(); + var mtlFileName = objFilePath.Replace(".obj", ".mtl"); + var mtlFilePath = Path.Combine(Path.GetDirectoryName(fileName) ?? string.Empty, mtlFileName); + + var mats = Material.ReadMtl(mtlFilePath, out var mtlDeps); + + deps.AddRange(mtlDeps); + deps.Add(mtlFilePath); + + foreach (var mat in mats) + { + materials.Add(mat); + materialsDict.Add(mat.Name, materials.Count - 1); + } + while (true) { var line = reader.ReadLine(); @@ -101,35 +115,35 @@ public static IMesh LoadMesh(string fileName, out string[] dependencies) } else { - var faceT = new FaceB( + var face = new FaceB( v1 - 1, v2 - 1, v3 - 1, materialsDict[currentMaterial]); - facesB.Add(faceT); + facesB.Add(face); } break; } - case "mtllib" when segs.Length == 2: - { - var mtlFileName = segs[1]; - var mtlFilePath = Path.Combine(Path.GetDirectoryName(fileName) ?? string.Empty, mtlFileName); + // case "mtllib" when segs.Length == 2: + // { + // var mtlFileName = segs[1]; + // var mtlFilePath = Path.Combine(Path.GetDirectoryName(fileName) ?? string.Empty, mtlFileName); - var mats = Material.ReadMtl(mtlFilePath, out var mtlDeps); + // var mats = Material.ReadMtl(mtlFilePath, out var mtlDeps); - deps.AddRange(mtlDeps); - deps.Add(mtlFilePath); + // deps.AddRange(mtlDeps); + // deps.Add(mtlFilePath); - foreach (var mat in mats) - { - materials.Add(mat); - materialsDict.Add(mat.Name, materials.Count - 1); - } + // foreach (var mat in mats) + // { + // materials.Add(mat); + // materialsDict.Add(mat.Name, materials.Count - 1); + // } - break; - } + // break; + // } case "l" or "cstype" or "deg" or "bmat" or "step" or "curv" or "curv2" or "surf" or "parm" or "trim" or "end" or "hole" or "scrv" or "sp" or "con": @@ -138,9 +152,9 @@ public static IMesh LoadMesh(string fileName, out string[] dependencies) } dependencies = deps.ToArray(); - Console.WriteLine($" -> facesB-------------------------\"{facesB}\""); // return new Mesh(vertices, facesB, materials); - return new MeshT(vertices, facesB, materials); + return materials.Any() ? new MeshT(vertices, facesB, materials) : new Mesh(vertices, faces); + // return new MeshT(vertices, facesB, materials); // return textureVertices.Any() // ? new MeshT(vertices, textureVertices, facesT, materials) // : new Mesh(vertices, facesB, materials); diff --git a/Obj2Tiles.Library/Materials/Material.cs b/Obj2Tiles.Library/Materials/Material.cs index 8e20427..8dafe95 100644 --- a/Obj2Tiles.Library/Materials/Material.cs +++ b/Obj2Tiles.Library/Materials/Material.cs @@ -68,7 +68,6 @@ public static Material[] ReadMtl(string path, out string[] dependencies) continue; var parts = line.Split(' '); - // Console.WriteLine("Parts", parts[0]); switch (parts[0]) { case "newmtl": diff --git a/Obj2Tiles/Program.cs b/Obj2Tiles/Program.cs index 123c563..6b4e508 100644 --- a/Obj2Tiles/Program.cs +++ b/Obj2Tiles/Program.cs @@ -74,7 +74,7 @@ private static async Task Run(Options opts) : createTempFolder($"{pipelineId}-obj2tiles-split"); var boundsMapper = await StagesFacade.Split(decimateRes.DestFiles, destFolderSplit, opts.Divisions, - opts.ZSplit, decimateRes.Bounds, opts.KeepOriginalTextures); + opts.ZSplit, decimateRes.Bounds, opts.Input, opts.KeepOriginalTextures); Console.WriteLine(" ?> Splitting stage done in {0}", sw.Elapsed); diff --git a/Obj2Tiles/Stages/SplitStage.cs b/Obj2Tiles/Stages/SplitStage.cs index 405da1a..1cee683 100644 --- a/Obj2Tiles/Stages/SplitStage.cs +++ b/Obj2Tiles/Stages/SplitStage.cs @@ -9,7 +9,7 @@ namespace Obj2Tiles.Stages; public static partial class StagesFacade { public static async Task[]> Split(string[] sourceFiles, string destFolder, int divisions, - bool zsplit, Box3 bounds, bool keepOriginalTextures = false) + bool zsplit, Box3 bounds, string objFilePath, bool keepOriginalTextures = false) { var tasks = new List>>(); @@ -23,7 +23,7 @@ public static async Task[]> Split(string[] sourceFiles, var textureStrategy = keepOriginalTextures ? TexturesStrategy.KeepOriginal : index == 0 ? TexturesStrategy.Repack : TexturesStrategy.RepackCompressed; - var splitTask = Split(file, dest, divisions, zsplit, bounds, textureStrategy); + var splitTask = Split(file, dest, divisions, objFilePath, zsplit, bounds, textureStrategy); tasks.Add(splitTask); } @@ -34,6 +34,7 @@ public static async Task[]> Split(string[] sourceFiles, } public static async Task> Split(string sourcePath, string destPath, int divisions, + string objFilePath, bool zSplit = false, Box3? bounds = null, TexturesStrategy textureStrategy = TexturesStrategy.Repack, @@ -47,7 +48,7 @@ public static async Task> Split(string sourcePath, stri Console.WriteLine($" -> Loading OBJ file \"{sourcePath}\""); sw.Start(); - var mesh = MeshUtils.LoadMesh(sourcePath, out var deps); + var mesh = MeshUtils.LoadMesh(sourcePath, objFilePath, out var deps); Console.WriteLine( $" ?> Loaded {mesh.VertexCount} vertices, {mesh.FacesCount} faces in {sw.ElapsedMilliseconds}ms"); @@ -74,7 +75,6 @@ public static async Task> Split(string sourcePath, stri int count; - Console.WriteLine($"bounds===================={bounds}"); if (bounds != null) { count = zSplit