From 7e42a8bd128f66af8e7783df9dfc5283409897b4 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Fri, 4 Jun 2021 13:39:28 +0900 Subject: [PATCH 1/5] =?UTF-8?q?BlendShapeExporter=20=E3=82=92=E6=BA=96?= =?UTF-8?q?=E5=82=99=E4=B8=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../UniGLTF/IO/MeshIO/BlendShapeExporter.cs | 50 +++++++++++++++++++ .../IO/MeshIO/BlendShapeExporter.cs.meta | 11 ++++ .../UniGLTF/IO/MeshIO/MeshExportUtil.cs | 43 +++++++--------- .../MeshExporter_DividedVertexBuffer.cs | 31 ++++++++---- .../MeshIO/MeshExporter_SharedVertexBuffer.cs | 18 ++++--- Assets/VRM10/Runtime/IO/Model/MeshWriter.cs | 7 +-- 6 files changed, 113 insertions(+), 47 deletions(-) create mode 100644 Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/BlendShapeExporter.cs create mode 100644 Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/BlendShapeExporter.cs.meta diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/BlendShapeExporter.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/BlendShapeExporter.cs new file mode 100644 index 000000000..fd7eae6c1 --- /dev/null +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/BlendShapeExporter.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; + +namespace UniGLTF +{ + public struct SparseBase + { + public readonly Vector3[] Positions; + public readonly Vector3[] Normals; + + public SparseBase(Vector3[] positions, Vector3[] normals) + { + Positions = positions; + Normals = normals; + } + } + + public static class BlendShapeExporter + { + public static gltfMorphTarget Export(glTF gltf, int gltfBuffer, Vector3[] positions, Vector3[] normals, SparseBase? sparseBase) + { + if (sparseBase.HasValue) + { + throw new NotImplementedException(); + } + else + { + // position + var positionAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(gltfBuffer, positions, glBufferTarget.ARRAY_BUFFER); + gltf.accessors[positionAccessorIndex].min = positions.Aggregate(positions[0], (a, b) => new Vector3(Mathf.Min(a.x, b.x), Math.Min(a.y, b.y), Mathf.Min(a.z, b.z))).ToArray(); + + // normal + var normalAccessorIndex = -1; + if (normals != null) + { + normalAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(gltfBuffer, normals, glBufferTarget.ARRAY_BUFFER); + } + gltf.accessors[positionAccessorIndex].max = positions.Aggregate(positions[0], (a, b) => new Vector3(Mathf.Max(a.x, b.x), Math.Max(a.y, b.y), Mathf.Max(a.z, b.z))).ToArray(); + + return new gltfMorphTarget + { + POSITION = positionAccessorIndex, + NORMAL = normalAccessorIndex, + }; + } + } + } +} diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/BlendShapeExporter.cs.meta b/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/BlendShapeExporter.cs.meta new file mode 100644 index 000000000..b407c6d75 --- /dev/null +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/BlendShapeExporter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 49e5f06c3492116409bc0c0745b5edf7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshExportUtil.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshExportUtil.cs index 19bd410da..a3870cb25 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshExportUtil.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshExportUtil.cs @@ -15,37 +15,27 @@ namespace UniGLTF { public class BlendShapeBuffer { - readonly List m_positions; - readonly List m_normals; + readonly Vector3[] m_positions; + readonly Vector3[] m_normals; public BlendShapeBuffer(int reserve) { - m_positions = new List(reserve); - m_normals = new List(reserve); + m_positions = new Vector3[reserve]; + m_normals = new Vector3[reserve]; } - public void Push(Vector3 position, Vector3 normal) + public void Set(int index, Vector3 position, Vector3 normal) { - m_positions.Add(position); - m_normals.Add(normal); + m_positions[index] = position; + m_normals[index] = normal; } - public gltfMorphTarget ToGltf(glTF gltf, int bufferIndex, bool useNormal) + public gltfMorphTarget ToGltf(glTF gltf, int gltfBuffer, bool useNormal, SparseBase? sparseBase) { - var positionAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, m_positions.ToArray(), glBufferTarget.ARRAY_BUFFER); - gltf.accessors[positionAccessorIndex].min = m_positions.Aggregate(m_positions[0], (a, b) => new Vector3(Mathf.Min(a.x, b.x), Math.Min(a.y, b.y), Mathf.Min(a.z, b.z))).ToArray(); - gltf.accessors[positionAccessorIndex].max = m_positions.Aggregate(m_positions[0], (a, b) => new Vector3(Mathf.Max(a.x, b.x), Math.Max(a.y, b.y), Mathf.Max(a.z, b.z))).ToArray(); - - var normalAccessorIndex = -1; - if (useNormal) - { - normalAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, m_normals.ToArray(), glBufferTarget.ARRAY_BUFFER); - } - return new gltfMorphTarget - { - POSITION = positionAccessorIndex, - NORMAL = normalAccessorIndex, - }; + return BlendShapeExporter.Export(gltf, gltfBuffer, + m_positions, + useNormal ? m_normals : null, + sparseBase); } } @@ -113,11 +103,12 @@ namespace UniGLTF m_weights.Add(new Vector4(boneWeight.weight0, boneWeight.weight1, boneWeight.weight2, boneWeight.weight3)); } - public glTFPrimitives ToGltfPrimitive(glTF gltf, int bufferIndex, int materialIndex, IEnumerable indices) + public (glTFPrimitives, SparseBase) ToGltfPrimitive(glTF gltf, int bufferIndex, int materialIndex, IEnumerable indices) { + var sparseBase = new SparseBase(m_positions.ToArray(), m_normals.ToArray()); var indicesAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, indices.Select(x => (uint)m_vertexIndexMap[x]).ToArray(), glBufferTarget.ELEMENT_ARRAY_BUFFER); - var positionAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, m_positions.ToArray(), glBufferTarget.ARRAY_BUFFER); - var normalAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, m_normals.ToArray(), glBufferTarget.ARRAY_BUFFER); + var positionAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, sparseBase.Positions, glBufferTarget.ARRAY_BUFFER); + var normalAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, sparseBase.Normals, glBufferTarget.ARRAY_BUFFER); var uvAccessorIndex0 = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, m_uv.ToArray(), glBufferTarget.ARRAY_BUFFER); int? jointsAccessorIndex = default; @@ -146,7 +137,7 @@ namespace UniGLTF mode = 4, }; - return primitive; + return (primitive, sparseBase); } } } diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshExporter_DividedVertexBuffer.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshExporter_DividedVertexBuffer.cs index f0a8159cf..e6445a131 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshExporter_DividedVertexBuffer.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshExporter_DividedVertexBuffer.cs @@ -7,7 +7,17 @@ namespace UniGLTF { public static class MeshExporter_DividedVertexBuffer { - public static (glTFMesh, Dictionary) Export(glTF gltf, int bufferIndex, + /// + /// Divide vertex buffer(Position, Normal, UV, VertexColor, Skinning and BlendShapes) by submesh usage, then export + /// + /// + /// + /// + /// + /// + /// + /// + public static (glTFMesh, Dictionary) Export(glTF gltf, int gltfBuffer, MeshExportInfo unityMesh, List unityMaterials, IAxisInverter axisInverter, MeshExportSettings settings) { @@ -16,7 +26,7 @@ namespace UniGLTF if (settings.ExportTangents) { - // support しない + // no support throw new NotImplementedException(); } @@ -40,15 +50,14 @@ namespace UniGLTF var indices = mesh.GetIndices(i); var hash = new HashSet(indices); - // mesh - // index の順に attributes を蓄える + // aggrigate vertex attributes var buffer = new MeshExportUtil.VertexBuffer(indices.Length, getJointIndex); usedIndices.Clear(); for (int k = 0; k < positions.Length; ++k) { if (hash.Contains(k)) { - // indices から参照される頂点だけを蓄える + // aggrigate indices usedIndices.Add(k); buffer.Push(k, axisInverter.InvertVector3(positions[k]), axisInverter.InvertVector3(normals[k]), uv[k].ReverseUV()); if (getJointIndex != null) @@ -75,23 +84,25 @@ namespace UniGLTF flipped.Add(t1); flipped.Add(t0); } - var gltfPrimitive = buffer.ToGltfPrimitive(gltf, bufferIndex, materialIndex, flipped); + var (gltfPrimitive, sparseBase) = buffer.ToGltfPrimitive(gltf, gltfBuffer, materialIndex, flipped); - // blendShape + // blendShape(morph target) for (int j = 0; j < mesh.blendShapeCount; ++j) { var blendShape = new MeshExportUtil.BlendShapeBuffer(indices.Length); - // index の順に attributes を蓄える + // aggriage morph target mesh.GetBlendShapeFrameVertices(j, 0, blendShapePositions, blendShapeNormals, null); + int l = 0; foreach (var k in usedIndices) { - blendShape.Push( + blendShape.Set(l++, axisInverter.InvertVector3(blendShapePositions[k]), axisInverter.InvertVector3(blendShapeNormals[k])); } - gltfPrimitive.targets.Add(blendShape.ToGltf(gltf, bufferIndex, !settings.ExportOnlyBlendShapePosition)); + gltfPrimitive.targets.Add(blendShape.ToGltf(gltf, gltfBuffer, !settings.ExportOnlyBlendShapePosition, + settings.UseSparseAccessorForMorphTarget ? sparseBase : default)); } gltfMesh.primitives.Add(gltfPrimitive); diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshExporter_SharedVertexBuffer.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshExporter_SharedVertexBuffer.cs index 23aefbca8..b600835ef 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshExporter_SharedVertexBuffer.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshExporter_SharedVertexBuffer.cs @@ -10,11 +10,12 @@ namespace UniGLTF { /// /// primitive 間で vertex を共有する形で Export する。 + /// UniVRM-0.71.0 以降は、MeshExporterDivided.Export もある。 /// - /// UniVRM-0.71.0 までの挙動 + /// * GLB/GLTF は shared(default) と divided を選択可能 + /// * VRM0 は shared 仕様 + /// * VRM1 は divided 仕様 /// - /// UniVRM-0.71.0 以降は、MeshExporterDivided.Export もある - /// /// /// /// /// @@ -159,12 +160,13 @@ namespace UniGLTF unityMesh.Mesh, j, settings.UseSparseAccessorForMorphTarget, settings.ExportOnlyBlendShapePosition, axisInverter); - if (morphTarget.POSITION < 0 && morphTarget.NORMAL < 0 && morphTarget.TANGENT < 0) + if (morphTarget.POSITION < 0) { + // Skip empty blendShape. + // Shift blendShape's index. continue; } - // maybe skip var blendShapeName = unityMesh.Mesh.GetBlendShapeName(j); blendShapeIndexMap.Add(j, exportBlendShapes++); targetNames.Add(blendShapeName); @@ -199,7 +201,7 @@ namespace UniGLTF } static gltfMorphTarget ExportMorphTarget(glTF gltf, int bufferIndex, - Mesh mesh, int j, + Mesh mesh, int blendShapeIndex, bool useSparseAccessorForMorphTarget, bool exportOnlyBlendShapePosition, IAxisInverter axisInverter) @@ -215,8 +217,8 @@ namespace UniGLTF //var useTangent = usePosition && blendShapeTangents != null && blendShapeTangents.Length == blendShapeVertices.Length; var useTangent = false; - var frameCount = mesh.GetBlendShapeFrameCount(j); - mesh.GetBlendShapeFrameVertices(j, frameCount - 1, blendShapeVertices, blendShapeNormals, null); + var frameCount = mesh.GetBlendShapeFrameCount(blendShapeIndex); + mesh.GetBlendShapeFrameVertices(blendShapeIndex, frameCount - 1, blendShapeVertices, blendShapeNormals, null); var blendShapePositionAccessorIndex = -1; var blendShapeNormalAccessorIndex = -1; diff --git a/Assets/VRM10/Runtime/IO/Model/MeshWriter.cs b/Assets/VRM10/Runtime/IO/Model/MeshWriter.cs index 7baaaa8f1..e0751036e 100644 --- a/Assets/VRM10/Runtime/IO/Model/MeshWriter.cs +++ b/Assets/VRM10/Runtime/IO/Model/MeshWriter.cs @@ -121,7 +121,7 @@ namespace UniVRM10 } } var materialIndex = submesh.Material; - var gltfPrimitive = buffer.ToGltfPrimitive(storage.Gltf, bufferIndex, materialIndex, indices); + var (gltfPrimitive, sparseBase) = buffer.ToGltfPrimitive(storage.Gltf, bufferIndex, materialIndex, indices); // blendShape for (int j = 0; j < mesh.MorphTargets.Count; ++j) @@ -136,15 +136,16 @@ namespace UniVRM10 { blendShapeNormals = morph.VertexBuffer.Normals.GetSpan(); } + int l = 0; foreach (var k in usedIndices) { - blendShape.Push( + blendShape.Set(l++, blendShapePositions[k], blendShapeNormals.HasValue ? blendShapeNormals.Value[k] : UnityEngine.Vector3.zero ); } - gltfPrimitive.targets.Add(blendShape.ToGltf(storage.Gltf, bufferIndex, !option.removeMorphNormal)); + gltfPrimitive.targets.Add(blendShape.ToGltf(storage.Gltf, bufferIndex, !option.removeMorphNormal, option.sparse ? sparseBase : default)); } yield return gltfPrimitive; From 80abc5d7cee94e1de49624777e619b38c252dfef Mon Sep 17 00:00:00 2001 From: ousttrue Date: Fri, 4 Jun 2021 15:40:44 +0900 Subject: [PATCH 2/5] implement BlendShapeExporter.Export --- .../UniGLTF/IO/MeshIO/BlendShapeExporter.cs | 46 ++++++- .../MeshIO/MeshExporter_SharedVertexBuffer.cs | 114 ++++-------------- .../Runtime/IO/Model/MeshImporterDivided.cs | 10 +- Assets/VRM10/Runtime/IO/Model/MeshWriter.cs | 2 +- 4 files changed, 77 insertions(+), 95 deletions(-) diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/BlendShapeExporter.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/BlendShapeExporter.cs index fd7eae6c1..f19f6723c 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/BlendShapeExporter.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/BlendShapeExporter.cs @@ -21,15 +21,58 @@ namespace UniGLTF { public static gltfMorphTarget Export(glTF gltf, int gltfBuffer, Vector3[] positions, Vector3[] normals, SparseBase? sparseBase) { + var accessorCount = positions.Length; + if (normals != null && positions.Length != normals.Length) + { + throw new Exception(); + } + + bool useSparse = sparseBase.HasValue; if (sparseBase.HasValue) { - throw new NotImplementedException(); + var sparseIndices = Enumerable.Range(0, positions.Length).Where(x => positions[x] != Vector3.zero).ToArray(); + if (sparseIndices.Length == 0) + { + useSparse = false; + } + } + + if (useSparse) + { + // positions + var positionAccessorIndex = -1; + var sparseIndices = Enumerable.Range(0, positions.Length).Where(x => positions[x] != Vector3.zero).ToArray(); + if (sparseIndices.Length > 0) + { + Debug.LogFormat("Sparse {0}/{1}", sparseIndices.Length, positions.Length); + var sparseIndicesViewIndex = gltf.ExtendBufferAndGetViewIndex(gltfBuffer, sparseIndices); + positionAccessorIndex = gltf.ExtendSparseBufferAndGetAccessorIndex(gltfBuffer, accessorCount, positions, sparseIndices, sparseIndicesViewIndex, glBufferTarget.NONE); + } + + // normals + var normalAccessorIndex = -1; + if (normals != null) + { + var sparseNormalIndices = Enumerable.Range(0, positions.Length).Where(x => normals[x] != Vector3.zero).ToArray(); + if (sparseNormalIndices.Length > 0) + { + var sparseNormalIndicesViewIndex = gltf.ExtendBufferAndGetViewIndex(gltfBuffer, sparseNormalIndices); + normalAccessorIndex = gltf.ExtendSparseBufferAndGetAccessorIndex(gltfBuffer, accessorCount, normals, sparseNormalIndices, sparseNormalIndicesViewIndex, glBufferTarget.NONE); + } + } + + return new gltfMorphTarget + { + POSITION = positionAccessorIndex, + NORMAL = normalAccessorIndex, + }; } else { // position var positionAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(gltfBuffer, positions, glBufferTarget.ARRAY_BUFFER); gltf.accessors[positionAccessorIndex].min = positions.Aggregate(positions[0], (a, b) => new Vector3(Mathf.Min(a.x, b.x), Math.Min(a.y, b.y), Mathf.Min(a.z, b.z))).ToArray(); + gltf.accessors[positionAccessorIndex].max = positions.Aggregate(positions[0], (a, b) => new Vector3(Mathf.Max(a.x, b.x), Math.Max(a.y, b.y), Mathf.Max(a.z, b.z))).ToArray(); // normal var normalAccessorIndex = -1; @@ -37,7 +80,6 @@ namespace UniGLTF { normalAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(gltfBuffer, normals, glBufferTarget.ARRAY_BUFFER); } - gltf.accessors[positionAccessorIndex].max = positions.Aggregate(positions[0], (a, b) => new Vector3(Mathf.Max(a.x, b.x), Math.Max(a.y, b.y), Mathf.Max(a.z, b.z))).ToArray(); return new gltfMorphTarget { diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshExporter_SharedVertexBuffer.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshExporter_SharedVertexBuffer.cs index b600835ef..97127a86c 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshExporter_SharedVertexBuffer.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshExporter_SharedVertexBuffer.cs @@ -213,106 +213,38 @@ namespace UniGLTF var useNormal = usePosition && blendShapeNormals != null && blendShapeNormals.Length == blendShapeVertices.Length; // var useNormal = usePosition && blendShapeNormals != null && blendShapeNormals.Length == blendShapeVertices.Length && !exportOnlyBlendShapePosition; - var blendShapeTangents = mesh.tangents.Select(y => (Vector3)y).ToArray(); - //var useTangent = usePosition && blendShapeTangents != null && blendShapeTangents.Length == blendShapeVertices.Length; - var useTangent = false; + // var blendShapeTangents = mesh.tangents.Select(y => (Vector3)y).ToArray(); + // //var useTangent = usePosition && blendShapeTangents != null && blendShapeTangents.Length == blendShapeVertices.Length; + // var useTangent = false; var frameCount = mesh.GetBlendShapeFrameCount(blendShapeIndex); mesh.GetBlendShapeFrameVertices(blendShapeIndex, frameCount - 1, blendShapeVertices, blendShapeNormals, null); - var blendShapePositionAccessorIndex = -1; - var blendShapeNormalAccessorIndex = -1; - var blendShapeTangentAccessorIndex = -1; - if (useSparseAccessorForMorphTarget) + // + // invert axis + // + for (int i = 0; i < blendShapeVertices.Length; ++i) { - var accessorCount = blendShapeVertices.Length; - var sparseIndices = Enumerable.Range(0, blendShapeVertices.Length) - .Where(x => UseSparse( - usePosition, blendShapeVertices[x], - useNormal, blendShapeNormals[x], - useTangent, blendShapeTangents[x])) - .ToArray() - ; - - if (sparseIndices.Length == 0) - { - usePosition = false; - useNormal = false; - useTangent = false; - } - else - { - Debug.LogFormat("Sparse {0}/{1}", sparseIndices.Length, mesh.vertexCount); - } - - var sparseIndicesViewIndex = -1; - if (usePosition) - { - sparseIndicesViewIndex = gltf.ExtendBufferAndGetViewIndex(bufferIndex, sparseIndices); - - blendShapeVertices = sparseIndices.Select(x => axisInverter.InvertVector3(blendShapeVertices[x])).ToArray(); - blendShapePositionAccessorIndex = gltf.ExtendSparseBufferAndGetAccessorIndex(bufferIndex, accessorCount, - blendShapeVertices, - sparseIndices, sparseIndicesViewIndex, - glBufferTarget.NONE); - } - - if (useNormal) - { - blendShapeNormals = sparseIndices.Select(x => axisInverter.InvertVector3(blendShapeNormals[x])).ToArray(); - blendShapeNormalAccessorIndex = gltf.ExtendSparseBufferAndGetAccessorIndex(bufferIndex, accessorCount, - blendShapeNormals, - sparseIndices, sparseIndicesViewIndex, - glBufferTarget.NONE); - } - - if (useTangent) - { - blendShapeTangents = sparseIndices.Select(x => axisInverter.InvertVector3(blendShapeTangents[x])).ToArray(); - blendShapeTangentAccessorIndex = gltf.ExtendSparseBufferAndGetAccessorIndex(bufferIndex, accessorCount, - blendShapeTangents, sparseIndices, sparseIndicesViewIndex, - glBufferTarget.NONE); - } + blendShapeVertices[i] = axisInverter.InvertVector3(blendShapeVertices[i]); } - else + for (int i = 0; i < blendShapeNormals.Length; ++i) { - for (int i = 0; i < blendShapeVertices.Length; ++i) blendShapeVertices[i] = axisInverter.InvertVector3(blendShapeVertices[i]); - if (usePosition) - { - blendShapePositionAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, - blendShapeVertices, - glBufferTarget.ARRAY_BUFFER); - } - - if (useNormal) - { - for (int i = 0; i < blendShapeNormals.Length; ++i) blendShapeNormals[i] = axisInverter.InvertVector3(blendShapeNormals[i]); - blendShapeNormalAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, - blendShapeNormals, - glBufferTarget.ARRAY_BUFFER); - } - - if (useTangent) - { - for (int i = 0; i < blendShapeTangents.Length; ++i) blendShapeTangents[i] = axisInverter.InvertVector3(blendShapeTangents[i]); - blendShapeTangentAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, - blendShapeTangents, - glBufferTarget.ARRAY_BUFFER); - } + blendShapeNormals[i] = axisInverter.InvertVector3(blendShapeNormals[i]); + } + var sparseBase = new SparseBase(mesh.vertices, mesh.normals); + for (int i = 0; i < sparseBase.Positions.Length; ++i) + { + sparseBase.Positions[i] = axisInverter.InvertVector3(sparseBase.Positions[i]); + } + for (int i = 0; i < sparseBase.Normals.Length; ++i) + { + sparseBase.Normals[i] = axisInverter.InvertVector3(sparseBase.Normals[i]); } - if (blendShapePositionAccessorIndex != -1) - { - gltf.accessors[blendShapePositionAccessorIndex].min = blendShapeVertices.Aggregate(blendShapeVertices[0], (a, b) => new Vector3(Mathf.Min(a.x, b.x), Math.Min(a.y, b.y), Mathf.Min(a.z, b.z))).ToArray(); - gltf.accessors[blendShapePositionAccessorIndex].max = blendShapeVertices.Aggregate(blendShapeVertices[0], (a, b) => new Vector3(Mathf.Max(a.x, b.x), Math.Max(a.y, b.y), Mathf.Max(a.z, b.z))).ToArray(); - } - - return new gltfMorphTarget - { - POSITION = blendShapePositionAccessorIndex, - NORMAL = blendShapeNormalAccessorIndex, - TANGENT = blendShapeTangentAccessorIndex, - }; + return BlendShapeExporter.Export(gltf, bufferIndex, + blendShapeVertices, + exportOnlyBlendShapePosition && useNormal ? null : blendShapeNormals, + useSparseAccessorForMorphTarget ? sparseBase : default); } } } diff --git a/Assets/VRM10/Runtime/IO/Model/MeshImporterDivided.cs b/Assets/VRM10/Runtime/IO/Model/MeshImporterDivided.cs index 64c646c71..8153fae45 100644 --- a/Assets/VRM10/Runtime/IO/Model/MeshImporterDivided.cs +++ b/Assets/VRM10/Runtime/IO/Model/MeshImporterDivided.cs @@ -93,7 +93,15 @@ namespace UniVRM10 { var morphTarget = src.Meshes[meshIndex].MorphTargets[i]; positions.AddRange(morphTarget.VertexBuffer.Positions.GetSpan()); - normals.AddRange(morphTarget.VertexBuffer.Normals.GetSpan()); + if (morphTarget.VertexBuffer.Normals != null) + { + normals.AddRange(morphTarget.VertexBuffer.Normals.GetSpan()); + } + else + { + // fill zero + normals.AddRange(Enumerable.Range(0, morphTarget.VertexBuffer.Count).Select(x => Vector3.zero)); + } } dst.AddBlendShapeFrame(name, 100.0f, positions.ToArray(), normals.ToArray(), null); } diff --git a/Assets/VRM10/Runtime/IO/Model/MeshWriter.cs b/Assets/VRM10/Runtime/IO/Model/MeshWriter.cs index e0751036e..8faf2c350 100644 --- a/Assets/VRM10/Runtime/IO/Model/MeshWriter.cs +++ b/Assets/VRM10/Runtime/IO/Model/MeshWriter.cs @@ -126,7 +126,7 @@ namespace UniVRM10 // blendShape for (int j = 0; j < mesh.MorphTargets.Count; ++j) { - var blendShape = new MeshExportUtil.BlendShapeBuffer(indices.Length); + var blendShape = new MeshExportUtil.BlendShapeBuffer(usedIndices.Count); // index の順に attributes を蓄える var morph = mesh.MorphTargets[j]; From a557fd6eae0e413530625cd72352128684fc06ff Mon Sep 17 00:00:00 2001 From: ousttrue Date: Fri, 4 Jun 2021 16:27:25 +0900 Subject: [PATCH 3/5] show migration error --- .../VRM10/Editor/ScriptedImporter/VrmScriptedImporterImpl.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Assets/VRM10/Editor/ScriptedImporter/VrmScriptedImporterImpl.cs b/Assets/VRM10/Editor/ScriptedImporter/VrmScriptedImporterImpl.cs index 6c41ec630..09ac8dda3 100644 --- a/Assets/VRM10/Editor/ScriptedImporter/VrmScriptedImporterImpl.cs +++ b/Assets/VRM10/Editor/ScriptedImporter/VrmScriptedImporterImpl.cs @@ -62,9 +62,9 @@ namespace UniVRM10 return "cannot migrate"; } } - catch (Exception) + catch (Exception ex) { - return "migration error"; + return $"migration error: {ex}"; } parser = new GltfParser(); From 40be812e2522a54c7809b808e3a70464b1828cf2 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Fri, 4 Jun 2021 16:34:26 +0900 Subject: [PATCH 4/5] fix -1 index in migration --- Assets/VRM10/Runtime/Migration/RotateY180.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Assets/VRM10/Runtime/Migration/RotateY180.cs b/Assets/VRM10/Runtime/Migration/RotateY180.cs index f4878cb63..327bc11dc 100644 --- a/Assets/VRM10/Runtime/Migration/RotateY180.cs +++ b/Assets/VRM10/Runtime/Migration/RotateY180.cs @@ -49,6 +49,11 @@ namespace UniVRM10 static void ReverseVector3Array(glTF gltf, int accessorIndex, HashSet used) { + if (accessorIndex == -1) + { + return; + } + if (!used.Add(accessorIndex)) { return; From ada991eb71af7d3065601ddc658e519819139c65 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Mon, 7 Jun 2021 19:13:10 +0900 Subject: [PATCH 5/5] =?UTF-8?q?=E3=82=B3=E3=83=BC=E3=83=89=E8=A6=8B?= =?UTF-8?q?=E7=9B=B4=E3=81=97=E3=80=82SparseBase=E3=80=80=E4=BD=BF?= =?UTF-8?q?=E3=81=A3=E3=81=A6=E3=81=AA=E3=81=8B=E3=81=A3=E3=81=9F=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../UniGLTF/IO/MeshIO/BlendShapeExporter.cs | 34 +++++++++---------- .../UniGLTF/IO/MeshIO/MeshExportUtil.cs | 15 ++++---- .../MeshExporter_DividedVertexBuffer.cs | 4 +-- .../MeshIO/MeshExporter_SharedVertexBuffer.cs | 15 ++++---- Assets/VRM10/Runtime/IO/Model/MeshWriter.cs | 4 +-- 5 files changed, 38 insertions(+), 34 deletions(-) diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/BlendShapeExporter.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/BlendShapeExporter.cs index f19f6723c..563b9d2e4 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/BlendShapeExporter.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/BlendShapeExporter.cs @@ -5,21 +5,9 @@ using UnityEngine; namespace UniGLTF { - public struct SparseBase - { - public readonly Vector3[] Positions; - public readonly Vector3[] Normals; - - public SparseBase(Vector3[] positions, Vector3[] normals) - { - Positions = positions; - Normals = normals; - } - } - public static class BlendShapeExporter { - public static gltfMorphTarget Export(glTF gltf, int gltfBuffer, Vector3[] positions, Vector3[] normals, SparseBase? sparseBase) + public static gltfMorphTarget Export(glTF gltf, int gltfBuffer, Vector3[] positions, Vector3[] normals, bool useSparse) { var accessorCount = positions.Length; if (normals != null && positions.Length != normals.Length) @@ -27,21 +15,33 @@ namespace UniGLTF throw new Exception(); } - bool useSparse = sparseBase.HasValue; - if (sparseBase.HasValue) + int[] sparseIndices = default; + if (useSparse) { - var sparseIndices = Enumerable.Range(0, positions.Length).Where(x => positions[x] != Vector3.zero).ToArray(); + sparseIndices = Enumerable.Range(0, positions.Length).Where(x => positions[x] != Vector3.zero).ToArray(); if (sparseIndices.Length == 0) { + // sparse 対象がすべて [0, 0, 0] の場合 + // new glTFSparse + // { + // count = 0, + // } + // のようになる。 + // たぶん、仕様的にはあり。 + // 解釈できない場合あり。 useSparse = false; } } if (useSparse) { + if (sparseIndices == null) + { + throw new Exception(); + } + // positions var positionAccessorIndex = -1; - var sparseIndices = Enumerable.Range(0, positions.Length).Where(x => positions[x] != Vector3.zero).ToArray(); if (sparseIndices.Length > 0) { Debug.LogFormat("Sparse {0}/{1}", sparseIndices.Length, positions.Length); diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshExportUtil.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshExportUtil.cs index a3870cb25..9d3a7eac1 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshExportUtil.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshExportUtil.cs @@ -30,12 +30,12 @@ namespace UniGLTF m_normals[index] = normal; } - public gltfMorphTarget ToGltf(glTF gltf, int gltfBuffer, bool useNormal, SparseBase? sparseBase) + public gltfMorphTarget ToGltf(glTF gltf, int gltfBuffer, bool useNormal, bool useSparse) { return BlendShapeExporter.Export(gltf, gltfBuffer, m_positions, useNormal ? m_normals : null, - sparseBase); + useSparse); } } @@ -103,12 +103,13 @@ namespace UniGLTF m_weights.Add(new Vector4(boneWeight.weight0, boneWeight.weight1, boneWeight.weight2, boneWeight.weight3)); } - public (glTFPrimitives, SparseBase) ToGltfPrimitive(glTF gltf, int bufferIndex, int materialIndex, IEnumerable indices) + public glTFPrimitives ToGltfPrimitive(glTF gltf, int bufferIndex, int materialIndex, IEnumerable indices) { - var sparseBase = new SparseBase(m_positions.ToArray(), m_normals.ToArray()); var indicesAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, indices.Select(x => (uint)m_vertexIndexMap[x]).ToArray(), glBufferTarget.ELEMENT_ARRAY_BUFFER); - var positionAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, sparseBase.Positions, glBufferTarget.ARRAY_BUFFER); - var normalAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, sparseBase.Normals, glBufferTarget.ARRAY_BUFFER); + var positions = m_positions.ToArray(); + var positionAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, positions, glBufferTarget.ARRAY_BUFFER); + var normals = m_normals.ToArray(); + var normalAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, normals, glBufferTarget.ARRAY_BUFFER); var uvAccessorIndex0 = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, m_uv.ToArray(), glBufferTarget.ARRAY_BUFFER); int? jointsAccessorIndex = default; @@ -137,7 +138,7 @@ namespace UniGLTF mode = 4, }; - return (primitive, sparseBase); + return primitive; } } } diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshExporter_DividedVertexBuffer.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshExporter_DividedVertexBuffer.cs index e6445a131..bd7796073 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshExporter_DividedVertexBuffer.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshExporter_DividedVertexBuffer.cs @@ -84,7 +84,7 @@ namespace UniGLTF flipped.Add(t1); flipped.Add(t0); } - var (gltfPrimitive, sparseBase) = buffer.ToGltfPrimitive(gltf, gltfBuffer, materialIndex, flipped); + var gltfPrimitive = buffer.ToGltfPrimitive(gltf, gltfBuffer, materialIndex, flipped); // blendShape(morph target) for (int j = 0; j < mesh.blendShapeCount; ++j) @@ -102,7 +102,7 @@ namespace UniGLTF } gltfPrimitive.targets.Add(blendShape.ToGltf(gltf, gltfBuffer, !settings.ExportOnlyBlendShapePosition, - settings.UseSparseAccessorForMorphTarget ? sparseBase : default)); + settings.UseSparseAccessorForMorphTarget)); } gltfMesh.primitives.Add(gltfPrimitive); diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshExporter_SharedVertexBuffer.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshExporter_SharedVertexBuffer.cs index 97127a86c..f80edb35b 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshExporter_SharedVertexBuffer.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshExporter_SharedVertexBuffer.cs @@ -231,20 +231,23 @@ namespace UniGLTF { blendShapeNormals[i] = axisInverter.InvertVector3(blendShapeNormals[i]); } - var sparseBase = new SparseBase(mesh.vertices, mesh.normals); - for (int i = 0; i < sparseBase.Positions.Length; ++i) + + var positions = mesh.vertices; + for (int i = 0; i < positions.Length; ++i) { - sparseBase.Positions[i] = axisInverter.InvertVector3(sparseBase.Positions[i]); + positions[i] = axisInverter.InvertVector3(positions[i]); } - for (int i = 0; i < sparseBase.Normals.Length; ++i) + + var normals = mesh.normals; + for (int i = 0; i < normals.Length; ++i) { - sparseBase.Normals[i] = axisInverter.InvertVector3(sparseBase.Normals[i]); + normals[i] = axisInverter.InvertVector3(normals[i]); } return BlendShapeExporter.Export(gltf, bufferIndex, blendShapeVertices, exportOnlyBlendShapePosition && useNormal ? null : blendShapeNormals, - useSparseAccessorForMorphTarget ? sparseBase : default); + useSparseAccessorForMorphTarget); } } } diff --git a/Assets/VRM10/Runtime/IO/Model/MeshWriter.cs b/Assets/VRM10/Runtime/IO/Model/MeshWriter.cs index 8faf2c350..7f2565ad5 100644 --- a/Assets/VRM10/Runtime/IO/Model/MeshWriter.cs +++ b/Assets/VRM10/Runtime/IO/Model/MeshWriter.cs @@ -121,7 +121,7 @@ namespace UniVRM10 } } var materialIndex = submesh.Material; - var (gltfPrimitive, sparseBase) = buffer.ToGltfPrimitive(storage.Gltf, bufferIndex, materialIndex, indices); + var gltfPrimitive = buffer.ToGltfPrimitive(storage.Gltf, bufferIndex, materialIndex, indices); // blendShape for (int j = 0; j < mesh.MorphTargets.Count; ++j) @@ -145,7 +145,7 @@ namespace UniVRM10 ); } - gltfPrimitive.targets.Add(blendShape.ToGltf(storage.Gltf, bufferIndex, !option.removeMorphNormal, option.sparse ? sparseBase : default)); + gltfPrimitive.targets.Add(blendShape.ToGltf(storage.Gltf, bufferIndex, !option.removeMorphNormal, option.sparse)); } yield return gltfPrimitive;