Reuse indices in mesh parsing, remove trailing nulls in mesh writing

This commit is contained in:
Bálint Hodossy
2024-01-20 19:06:15 +00:00
parent 2feefbc5d2
commit 042e3c9c4c
+49 -24
View File
@@ -12,11 +12,11 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using UnityEngine; using UnityEngine;
using UnityEngine.Rendering;
namespace Mujoco { namespace Mujoco {
@@ -27,6 +27,17 @@ public static class BinaryReaderExtensions {
var z = reader.ReadSingle(); var z = reader.ReadSingle();
return new Vector3(x, y, z); return new Vector3(x, y, z);
} }
public static int GetOrCreateVertexIndex(Dictionary<Vector3, int> vertexIndexMap, List<Vector3> vertices, List<Vector3>normals, Vector3 vertex, Vector3 normal) {
if (vertexIndexMap.TryGetValue(vertex, out int existingIndex)) {
return existingIndex;
}
int newIndex = vertexIndexMap.Count;
vertexIndexMap.Add(vertex, newIndex);
vertices.Add(vertex);
normals.Add(normal);
return newIndex;
}
} }
public static class BinaryWriterExtensions { public static class BinaryWriterExtensions {
@@ -50,7 +61,7 @@ public class StlMeshParser {
// The binary STL format is described here: https://en.wikipedia.org/wiki/STL_(file_format) // The binary STL format is described here: https://en.wikipedia.org/wiki/STL_(file_format)
public static Mesh ParseBinary(byte[] stlFileContents, Vector3 scale) { public static Mesh ParseBinary(byte[] stlFileContents, Vector3 scale) {
var fileTypeId = System.Text.Encoding.UTF8.GetString( var fileTypeId = System.Text.Encoding.UTF8.GetString(
stlFileContents.Take(_asciiFileTypeId.Length).ToArray()); stlFileContents.Take(_asciiFileTypeId.Length).ToArray());
if (fileTypeId == _asciiFileTypeId) { if (fileTypeId == _asciiFileTypeId) {
throw new IOException("Ascii STL file format is not supported."); throw new IOException("Ascii STL file format is not supported.");
} }
@@ -59,27 +70,39 @@ public class StlMeshParser {
using (var reader = new BinaryReader(stream)) { using (var reader = new BinaryReader(stream)) {
reader.ReadBytes(_headerLength); reader.ReadBytes(_headerLength);
var numTriangles = reader.ReadUInt32(); var numTriangles = reader.ReadUInt32();
var numVertices = numTriangles * _verticesPerTriangle; var maxNumVertices = numTriangles * _verticesPerTriangle;
if (numVertices > _unityLimitNumVerticesPerMesh) {
throw new IndexOutOfRangeException( Dictionary<Vector3, int> vertexIndexMap = new Dictionary<Vector3, int>();
"The mesh exceeds the number of vertices per mesh allowed by Unity. " + var triangleIndices = new int[(int)numTriangles * _verticesPerTriangle];
$"({numVertices} > {_unityLimitNumVerticesPerMesh})"); var vertices = new List<Vector3>(capacity: (int)maxNumVertices);
} var normals = new List<Vector3>(capacity: (int)maxNumVertices);
var triangleIndices = new List<int>(capacity: (int)numVertices); for (var i = 0; i < numTriangles; i++) {
var vertices = new List<Vector3>(capacity: (int)numVertices);
var normals = new List<Vector3>(capacity: (int)numVertices);
for (var i = 0; i < numVertices; i += _verticesPerTriangle) {
var triangleNormal = ToXZY(reader.ReadVector3()); var triangleNormal = ToXZY(reader.ReadVector3());
normals.AddRange(new[] { triangleNormal, triangleNormal, triangleNormal }); var verts = new[]
vertices.AddRange(new[] { {
ToXZY(reader.ReadVector3()), ToXZY(reader.ReadVector3()),
ToXZY(reader.ReadVector3()), ToXZY(reader.ReadVector3()),
ToXZY(reader.ReadVector3()) }); ToXZY(reader.ReadVector3())
triangleIndices.AddRange(new[] {i, i + 2, i + 1}); };
reader.ReadInt16(); // Read the unused attribute indices field. var indices = new[] { verts[0], verts[2], verts[1] }.Select(v =>
BinaryReaderExtensions.GetOrCreateVertexIndex(vertexIndexMap,
vertices,
normals,
v,
triangleNormal)).ToArray();
for (int j = 0; j < 3; j++) {
triangleIndices[i * 3 + j] = indices[j];
}
reader.ReadInt16(); // Read the unused attribute indices field.
} }
var mesh = new Mesh(); var mesh = new Mesh();
var numVertices = vertexIndexMap.Count;
if (numVertices > _unityLimitNumVerticesPerMesh) {
mesh.indexFormat = IndexFormat.UInt32;
}
mesh.vertices = vertices.ToArray(); mesh.vertices = vertices.ToArray();
mesh.normals = normals.ToArray(); mesh.normals = normals.ToArray();
mesh.triangles = triangleIndices.ToArray(); mesh.triangles = triangleIndices.ToArray();
@@ -88,6 +111,7 @@ public class StlMeshParser {
mesh.RecalculateNormals(); mesh.RecalculateNormals();
mesh.RecalculateTangents(); mesh.RecalculateTangents();
mesh.RecalculateBounds(); mesh.RecalculateBounds();
return mesh; return mesh;
} }
} }
@@ -118,15 +142,16 @@ public class StlMeshParser {
var i2 = triangles[i + 1]; var i2 = triangles[i + 1];
var i3 = triangles[i + 2]; var i3 = triangles[i + 2];
var faceNormal = (normals[i1] + normals[i2] + normals[i3]).normalized; var faceNormal = (normals[i1] + normals[i2] + normals[i3]).normalized;
writer.Write(ToXZY(faceNormal)); writer.Write(faceNormal);
writer.Write(ToXZY(vertices[i1])); writer.Write(vertices[i1]);
writer.Write(ToXZY(vertices[i3])); writer.Write(vertices[i2]);
writer.Write(ToXZY(vertices[i2])); writer.Write(vertices[i3]);
writer.Write((short)0); writer.Write((short)0);
} }
return stream.GetBuffer();
return stream.ToArray();
} }
} }
} }