From e5e731359f55864b3d960bbf080cc12d4937b38d Mon Sep 17 00:00:00 2001 From: Christian Petry Date: Tue, 3 Dec 2024 12:44:06 +0100 Subject: [PATCH 1/4] Fixed #2519 - progress being used when given --- Assets/UniGLTF/Runtime/UniGLTF/IO/gltfExporter.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/gltfExporter.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/gltfExporter.cs index db93b8017..2f51dd7db 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/gltfExporter.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/gltfExporter.cs @@ -89,6 +89,8 @@ namespace UniGLTF m_settings = new GltfExportSettings(); } + if (progress != null) + m_progress = progress; m_animationExporter = animationExporter; m_materialExporter = materialExporter ?? MaterialExporterUtility.GetValidGltfMaterialExporter(); m_textureSerializer = textureSerializer ?? new RuntimeTextureSerializer(); From 66f37ba2cea03690ef8aac807bb6e91c214e842e Mon Sep 17 00:00:00 2001 From: Christian Petry Date: Tue, 3 Dec 2024 15:15:12 +0100 Subject: [PATCH 2/4] Refs #2521 - Improved exporting performance drastically by increasing allocated buffer more than needed to be able to skip extending chunk by chunk. No difference in export quality --- .../Runtime/UniGLTF/IO/ArrayByteBuffer.cs | 18 +++++++----------- .../Runtime/UniGLTF/IO/NativeArrayManager.cs | 4 ++-- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/ArrayByteBuffer.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/ArrayByteBuffer.cs index 722c1f8c2..11d1e8216 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/ArrayByteBuffer.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/ArrayByteBuffer.cs @@ -43,22 +43,18 @@ namespace UniGLTF public glTFBufferView Extend(IntPtr p, int bytesLength, int stride, glBufferTarget target) { - var tmp = m_bytes; // alignment var padding = m_used % stride == 0 ? 0 : stride - m_used % stride; + var requiredLength = m_used + padding + bytesLength; - if (m_bytes == null || m_used + padding + bytesLength > m_bytes.Length) + if (m_bytes == null || requiredLength > m_bytes.Length) { // recreate buffer - m_bytes = new Byte[m_used + padding + bytesLength]; + var newLength = Math.Max(requiredLength, m_bytes?.Length * 2 ?? 256); + var newBuffer = new Byte[newLength]; if (m_used > 0) - { - Buffer.BlockCopy(tmp, 0, m_bytes, 0, m_used); - } - } - if (m_used + padding + bytesLength > m_bytes.Length) - { - throw new ArgumentOutOfRangeException(); + Buffer.BlockCopy(m_bytes, 0, newBuffer, 0, m_used); + m_bytes = newBuffer; } Marshal.Copy(p, m_bytes, m_used + padding, bytesLength); @@ -70,7 +66,7 @@ namespace UniGLTF byteStride = stride, target = target, }; - m_used = m_used + padding + bytesLength; + m_used = requiredLength; return result; } diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/NativeArrayManager.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/NativeArrayManager.cs index fc8f4c05d..b02250bbb 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/NativeArrayManager.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/NativeArrayManager.cs @@ -69,8 +69,8 @@ namespace UniGLTF public NativeArray CreateNativeArray(ArraySegment data) where T : struct { var array = CreateNativeArray(data.Count); - // TODO: remove ToArray - array.CopyFrom(data.ToArray()); + for (int i = 0; i < data.Count; i++) + array[i] = data.Array[data.Offset + i]; return array; } From cc6acafcf33e3e22a5598a0d16d3e77c684ff586 Mon Sep 17 00:00:00 2001 From: Christian Petry Date: Tue, 3 Dec 2024 15:21:03 +0100 Subject: [PATCH 3/4] cleaned up PR --- Assets/UniGLTF/Runtime/UniGLTF/IO/gltfExporter.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/gltfExporter.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/gltfExporter.cs index 2f51dd7db..db93b8017 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/gltfExporter.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/gltfExporter.cs @@ -89,8 +89,6 @@ namespace UniGLTF m_settings = new GltfExportSettings(); } - if (progress != null) - m_progress = progress; m_animationExporter = animationExporter; m_materialExporter = materialExporter ?? MaterialExporterUtility.GetValidGltfMaterialExporter(); m_textureSerializer = textureSerializer ?? new RuntimeTextureSerializer(); From 5d978f9c887d5c75e6c80132075f40d9ac0251dd Mon Sep 17 00:00:00 2001 From: Christian Petry Date: Wed, 4 Dec 2024 12:51:32 +0100 Subject: [PATCH 4/4] Refs #2525 - Using mesh topology to also process quads. Quads are being split into two triangles. --- .../InputPorts/FastSpringBoneBuffer.cs | 7 + .../Runtime/UniGLTF/Format/glTFMesh.cs | 11 ++ .../MeshIO/MeshExporter_SharedVertexBuffer.cs | 160 +++++++++++++----- 3 files changed, 132 insertions(+), 46 deletions(-) diff --git a/Assets/UniGLTF/Runtime/SpringBoneJobs/InputPorts/FastSpringBoneBuffer.cs b/Assets/UniGLTF/Runtime/SpringBoneJobs/InputPorts/FastSpringBoneBuffer.cs index 455e17dd6..f420ed10e 100644 --- a/Assets/UniGLTF/Runtime/SpringBoneJobs/InputPorts/FastSpringBoneBuffer.cs +++ b/Assets/UniGLTF/Runtime/SpringBoneJobs/InputPorts/FastSpringBoneBuffer.cs @@ -172,7 +172,14 @@ namespace UniGLTF.SpringBoneJobs.InputPorts for (int i = offset; i < end; ++i) { // mark velocity zero +#if UNITY_2022_2_OR_NEWER currentTails.GetSubArray(offset, Logics.Length).AsSpan().Fill(new Vector3(float.NaN, float.NaN, float.NaN)); +#else + var subArray = currentTails.GetSubArray(offset, Logics.Length); + var value = new Vector3(float.NaN, float.NaN, float.NaN); + for (int a = 0; a < subArray.Length; ++a) + subArray[a] = value; +#endif } } } diff --git a/Assets/UniGLTF/Runtime/UniGLTF/Format/glTFMesh.cs b/Assets/UniGLTF/Runtime/UniGLTF/Format/glTFMesh.cs index bc65a325c..9ed27634b 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/Format/glTFMesh.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/Format/glTFMesh.cs @@ -75,6 +75,17 @@ namespace UniGLTF [Serializable] public class glTFPrimitives { + public enum Mode + { + POINTS = 0, + LINES = 1, + LINE_LOOP = 2, + LINE_STRIP = 3, + TRIANGLES = 4, + TRIANGLE_STRIP = 5, + TRIANGLE_FAN = 6, + } + [JsonSchema(EnumValues = new object[] { 0, 1, 2, 3, 4, 5, 6 })] public int mode; diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshExporter_SharedVertexBuffer.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshExporter_SharedVertexBuffer.cs index 17d798e43..95bcd7cc8 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshExporter_SharedVertexBuffer.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshExporter_SharedVertexBuffer.cs @@ -114,52 +114,7 @@ namespace UniGLTF attributes.JOINTS_0 = jointsAccessorIndex; } - var gltfMesh = new glTFMesh(mesh.name); - var indices = new List(); - for (int j = 0; j < mesh.subMeshCount; ++j) - { - indices.Clear(); - - var triangles = mesh.GetIndices(j); - if (triangles.Length == 0) - { - // https://github.com/vrm-c/UniVRM/issues/664 - continue; - } - - for (int i = 0; i < triangles.Length; i += 3) - { - var i0 = triangles[i]; - var i1 = triangles[i + 1]; - var i2 = triangles[i + 2]; - - // flip triangle - indices.Add((uint)i2); - indices.Add((uint)i1); - indices.Add((uint)i0); - } - - var indicesAccessorIndex = data.ExtendBufferAndGetAccessorIndex(indices.ToArray(), glBufferTarget.ELEMENT_ARRAY_BUFFER); - if (indicesAccessorIndex < 0) - { - // https://github.com/vrm-c/UniVRM/issues/664 - throw new Exception(); - } - - if (j >= materials.Length) - { - Debug.LogWarningFormat("{0}.materials is not enough", unityMesh.Mesh.name); - break; - } - - gltfMesh.primitives.Add(new glTFPrimitives - { - attributes = attributes, - indices = indicesAccessorIndex, - mode = 4, // triangles ? - material = unityMaterials.IndexOf(materials[j]) - }); - } + var gltfMesh = CreateGLTFMesh(attributes, data, unityMesh, unityMaterials); var blendShapeIndexMap = new Dictionary(); { @@ -201,6 +156,119 @@ namespace UniGLTF return (gltfMesh, blendShapeIndexMap); } + private static glTFMesh CreateGLTFMesh(glTFAttributes attributes, ExportingGltfData data, MeshExportInfo unityMesh, List unityMaterials) + { + var mesh = unityMesh.Mesh; + var materials = unityMesh.Materials; + var gltfMesh = new glTFMesh(mesh.name); + + var indices = new List(); + for (int j = 0; j < mesh.subMeshCount; ++j) + { + indices.Clear(); + if (j >= materials.Length) + { + Debug.LogWarningFormat("{0}.materials is not enough", mesh.name); + continue; + } + + var subMesh = mesh.GetSubMesh(j); + var topologyType = subMesh.topology; + var materialIndex = unityMaterials.IndexOf(materials[j]); + + var submeshIndices = mesh.GetIndices(j); + if (submeshIndices.Length == 0) + { + // https://github.com/vrm-c/UniVRM/issues/664 + break; + } + else if (submeshIndices.Length < 3) + { + Debug.LogWarningFormat("Invalid primitive of type {0} found", topologyType); + continue; + } + + // Add indices considering the topology type + switch (topologyType) + { + case MeshTopology.Triangles: + if (submeshIndices.Length % 3 != 0) + Debug.LogWarningFormat("triangle indices is not multiple of 3"); + GetTriangleIndices(indices, submeshIndices); + break; + case MeshTopology.Quads: + if (submeshIndices.Length % 4 != 0) + Debug.LogWarningFormat("quad indices is not multiple of 4"); + GetQuadIndices(indices, submeshIndices); + break; + default: + case MeshTopology.Lines: + case MeshTopology.LineStrip: + case MeshTopology.Points: + Debug.LogWarningFormat("Mesh {0} has unsupported topology type {1}.", mesh.name, topologyType); + continue; + } + + var primitive = CreatePrimitives(attributes, data, indices, materialIndex); + gltfMesh.primitives.Add(primitive); + } + + return gltfMesh; + } + + private static glTFPrimitives CreatePrimitives(glTFAttributes attributes, ExportingGltfData data, List indices, int materialIndex) + { + var indicesAccessorIndex = data.ExtendBufferAndGetAccessorIndex(indices.ToArray(), glBufferTarget.ELEMENT_ARRAY_BUFFER); + if (indicesAccessorIndex < 0) + { + // https://github.com/vrm-c/UniVRM/issues/664 + throw new Exception(); + } + var primitive = new glTFPrimitives + { + attributes = attributes, + indices = indicesAccessorIndex, + mode = (int)glTFPrimitives.Mode.TRIANGLES, // triangles ? + material = materialIndex + }; + return primitive; + } + + private static void GetQuadIndices(List indices, int[] quadIndices) + { + for (int i = 0; i < quadIndices.Length - 3; i += 4) + { + var i0 = quadIndices[i]; + var i1 = quadIndices[i + 1]; + var i2 = quadIndices[i + 2]; + var i3 = quadIndices[i + 3]; + + // flip triangles + indices.Add((uint)i2); + indices.Add((uint)i1); + indices.Add((uint)i0); + + indices.Add((uint)i3); + indices.Add((uint)i2); + indices.Add((uint)i0); + } + } + + private static void GetTriangleIndices(List indices, int[] triangleIndices) + { + for (int i = 0; i < triangleIndices.Length - 2; i += 3) + { + var i0 = triangleIndices[i]; + var i1 = triangleIndices[i + 1]; + var i2 = triangleIndices[i + 2]; + + // flip triangle + indices.Add((uint)i2); + indices.Add((uint)i1); + indices.Add((uint)i0); + } + } + static bool UseSparse( bool usePosition, Vector3 position, bool useNormal, Vector3 normal,