From 9a479b2337f38b7cd015a53bdaef6dc889dc53e0 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Fri, 9 Apr 2021 20:52:44 +0900 Subject: [PATCH] MeshExporterDivided --- .../Runtime/UniGLTF/IO/MeshExportSettings.cs | 36 ++++ .../UniGLTF/IO/MeshExportSettings.cs.meta | 11 + .../Runtime/UniGLTF/IO/MeshExporter.cs | 181 +--------------- .../Runtime/UniGLTF/IO/MeshExporterDivided.cs | 196 ++++++++++++++++++ .../UniGLTF/IO/MeshExporterDivided.cs.meta | 11 + 5 files changed, 255 insertions(+), 180 deletions(-) create mode 100644 Assets/UniGLTF/Runtime/UniGLTF/IO/MeshExportSettings.cs create mode 100644 Assets/UniGLTF/Runtime/UniGLTF/IO/MeshExportSettings.cs.meta create mode 100644 Assets/UniGLTF/Runtime/UniGLTF/IO/MeshExporterDivided.cs create mode 100644 Assets/UniGLTF/Runtime/UniGLTF/IO/MeshExporterDivided.cs.meta diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshExportSettings.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshExportSettings.cs new file mode 100644 index 000000000..155ee72ef --- /dev/null +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshExportSettings.cs @@ -0,0 +1,36 @@ +using System; + +namespace UniGLTF +{ + [Serializable] + public struct MeshExportSettings + { + // + // https://github.com/vrm-c/UniVRM/issues/800 + // + // VertexBuffer を共有バッファ方式にする + // UniVRM-0.71.0 までの挙動 + // + public bool UseSharingVertexBuffer; + + // MorphTarget に Sparse Accessor を使う + public bool UseSparseAccessorForMorphTarget; + + // MorphTarget を Position だけにする(normal とか捨てる) + public bool ExportOnlyBlendShapePosition; + + // tangent を出力する + public bool ExportTangents; + + public static MeshExportSettings Default => new MeshExportSettings + { + UseSparseAccessorForMorphTarget = false, + ExportOnlyBlendShapePosition = false, + // WIP + UseSharingVertexBuffer = true, +#if GLTF_EXPORT_TANGENTS + ExportTangents = true, +#endif + }; + } +} diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshExportSettings.cs.meta b/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshExportSettings.cs.meta new file mode 100644 index 000000000..78ce31750 --- /dev/null +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshExportSettings.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 26b97430e1698e94e9a27ab322f3eee5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshExporter.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshExporter.cs index 433225582..9b0a72c03 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshExporter.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshExporter.cs @@ -6,187 +6,8 @@ using UnityEngine; namespace UniGLTF { - [Serializable] - public struct MeshExportSettings - { - // - // https://github.com/vrm-c/UniVRM/issues/800 - // - // VertexBuffer を共有バッファ方式にする - // UniVRM-0.71.0 までの挙動 - // - public bool UseSharingVertexBuffer; - - // MorphTarget に Sparse Accessor を使う - public bool UseSparseAccessorForMorphTarget; - - // MorphTarget を Position だけにする(normal とか捨てる) - public bool ExportOnlyBlendShapePosition; - - // tangent を出力する - public bool ExportTangents; - - public static MeshExportSettings Default => new MeshExportSettings - { - UseSparseAccessorForMorphTarget = false, - ExportOnlyBlendShapePosition = false, -#if GLTF_EXPORT_TANGENTS - ExportTangents = true, -#endif - }; - } - - class MorphTarget - { - readonly string m_name; - readonly List m_positions; - readonly List m_normals; - - public MorphTarget(string name, int reserve) - { - m_name = name; - m_positions = new List(reserve); - m_normals = new List(reserve); - } - } - - - class VertexBuffer - { - readonly IAxisInverter m_inverter; - readonly int m_indexCount; - readonly List m_positions; - readonly List m_normals; - readonly List m_uv; - - readonly Func m_getJointIndex; - readonly List m_joints; - readonly List m_weights; - - readonly List m_morphs = new List(); - - - public VertexBuffer(IAxisInverter inverter, int reserve, Func getJointIndex) - { - m_inverter = inverter; - m_indexCount = reserve; - m_positions = new List(reserve); - m_normals = new List(reserve); - m_uv = new List(); - - m_getJointIndex = getJointIndex; - if (m_getJointIndex != null) - { - m_joints = new List(reserve); - m_weights = new List(reserve); - } - } - - public void Push(Vector3 position, Vector3 normal, Vector2 uv) - { - m_positions.Add(m_inverter.InvertVector3(position)); - m_normals.Add(m_inverter.InvertVector3(normal)); - m_uv.Add(uv.ReverseUV()); - } - - public void Push(BoneWeight boneWeight) - { - m_joints.Add(new UShort4((ushort)boneWeight.boneIndex0, (ushort)boneWeight.boneIndex1, (ushort)boneWeight.boneIndex2, (ushort)boneWeight.boneIndex3)); - m_weights.Add(new Vector4(boneWeight.weight0, boneWeight.weight1, boneWeight.weight2, boneWeight.weight3)); - } - - public glTFPrimitives ToGltf(glTF gltf, int bufferIndex, int materialIndex) - { - var indices = new List(m_indexCount); - // flip triangles - for (int i = 0; i < m_indexCount; i += 3) - { - // 2, 1, 0, 5, 4, 3, ... - indices.Add((uint)(i + 2)); - indices.Add((uint)(i + 1)); - indices.Add((uint)(i + 0)); - } - - var indicesAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, indices.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 uvAccessorIndex0 = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, m_uv.ToArray(), glBufferTarget.ARRAY_BUFFER); - var jointsAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, m_joints.ToArray(), glBufferTarget.ARRAY_BUFFER); - var weightAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, m_weights.ToArray(), glBufferTarget.ARRAY_BUFFER); - - var primitive = new glTFPrimitives - { - indices = indicesAccessorIndex, - attributes = new glTFAttributes - { - POSITION = positionAccessorIndex, - NORMAL = normalAccessorIndex, - TEXCOORD_0 = uvAccessorIndex0, - JOINTS_0 = jointsAccessorIndex, - WEIGHTS_0 = weightAccessorIndex, - }, - material = materialIndex, - mode = 4, - targets = null, - }; - return primitive; - } - } - public static class MeshExporter { - static glTFMesh ExportDividedVertexBuffer(glTF gltf, int bufferIndex, - MeshWithRenderer unityMesh, List unityMaterials, - IAxisInverter axisInverter, MeshExportSettings settings) - { - var mesh = unityMesh.Mesh; - var gltfMesh = new glTFMesh(mesh.name); - - if (settings.ExportTangents) - { - // support しない - throw new NotImplementedException(); - } - - var positions = mesh.vertices; - var normals = mesh.normals; - var uv = mesh.uv; - var boneWeights = mesh.boneWeights; - - Func getJointIndex = null; - if (boneWeights != null && boneWeights.Length == positions.Length) - { - getJointIndex = unityMesh.GetJointIndex; - } - - for (int i = 0; i < mesh.subMeshCount; ++i) - { - var indices = mesh.GetIndices(i); - - // index の順に attributes を蓄える - var buffer = new VertexBuffer(axisInverter, indices.Length, getJointIndex); - foreach (var j in indices) - { - buffer.Push(positions[j], normals[j], uv[j]); - if (getJointIndex != null) - { - buffer.Push(boneWeights[j]); - } - } - - var material = unityMesh.Renderer.sharedMaterials[i]; - var materialIndex = -1; - if (material != null) - { - materialIndex = unityMaterials.IndexOf(material); - } - gltfMesh.primitives.Add(buffer.ToGltf(gltf, bufferIndex, materialIndex)); - } - - // morphTarget - - return gltfMesh; - } /// /// primitive 間で vertex を共有する形で Export する。 @@ -520,7 +341,7 @@ namespace UniGLTF } else { - gltfMesh = ExportDividedVertexBuffer(gltf, bufferIndex, unityMesh, unityMaterials, axisInverter, settings); + gltfMesh = MeshExporterDivided.Export(gltf, bufferIndex, unityMesh, unityMaterials, axisInverter, settings); } return (gltfMesh, blendShapeIndexMap); diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshExporterDivided.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshExporterDivided.cs new file mode 100644 index 000000000..34366ae88 --- /dev/null +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshExporterDivided.cs @@ -0,0 +1,196 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; + +namespace UniGLTF +{ + public static class MeshExporterDivided + { + class BlendShapeBuffer + { + readonly List m_positions; + readonly List m_normals; + + public BlendShapeBuffer(int reserve) + { + m_positions = new List(reserve); + m_normals = new List(reserve); + } + + public void Push(Vector3 position, Vector3 normal) + { + m_positions.Add(position); + m_normals.Add(normal); + } + + public gltfMorphTarget ToGltf(glTF gltf, int bufferIndex, bool useNormal) + { + var positionAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, m_positions.ToArray(), glBufferTarget.ARRAY_BUFFER); + var normalAccessorIndex = -1; + if (useNormal) + { + normalAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, m_normals.ToArray(), glBufferTarget.ARRAY_BUFFER); + } + return new gltfMorphTarget + { + POSITION = positionAccessorIndex, + NORMAL = normalAccessorIndex, + }; + } + } + + class VertexBuffer + { + readonly int m_indexCount; + readonly List m_positions; + readonly List m_normals; + readonly List m_uv; + + readonly Func m_getJointIndex; + readonly List m_joints; + readonly List m_weights; + + public VertexBuffer(int reserve, Func getJointIndex) + { + m_indexCount = reserve; + m_positions = new List(reserve); + m_normals = new List(reserve); + m_uv = new List(); + + m_getJointIndex = getJointIndex; + if (m_getJointIndex != null) + { + m_joints = new List(reserve); + m_weights = new List(reserve); + } + } + + public void Push(Vector3 position, Vector3 normal, Vector2 uv) + { + m_positions.Add(position); + m_normals.Add(normal); + m_uv.Add(uv); + } + + public void Push(BoneWeight boneWeight) + { + m_joints.Add(new UShort4((ushort)boneWeight.boneIndex0, (ushort)boneWeight.boneIndex1, (ushort)boneWeight.boneIndex2, (ushort)boneWeight.boneIndex3)); + m_weights.Add(new Vector4(boneWeight.weight0, boneWeight.weight1, boneWeight.weight2, boneWeight.weight3)); + } + + public glTFPrimitives ToGltf(glTF gltf, int bufferIndex, int materialIndex) + { + var indices = new List(m_indexCount); + // flip triangles + for (int i = 0; i < m_indexCount; i += 3) + { + // 2, 1, 0, 5, 4, 3, ... + indices.Add((uint)(i + 2)); + indices.Add((uint)(i + 1)); + indices.Add((uint)(i + 0)); + } + + var indicesAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, indices.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 uvAccessorIndex0 = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, m_uv.ToArray(), glBufferTarget.ARRAY_BUFFER); + var jointsAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, m_joints.ToArray(), glBufferTarget.ARRAY_BUFFER); + var weightAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, m_weights.ToArray(), glBufferTarget.ARRAY_BUFFER); + + var primitive = new glTFPrimitives + { + indices = indicesAccessorIndex, + attributes = new glTFAttributes + { + POSITION = positionAccessorIndex, + NORMAL = normalAccessorIndex, + TEXCOORD_0 = uvAccessorIndex0, + JOINTS_0 = jointsAccessorIndex, + WEIGHTS_0 = weightAccessorIndex, + }, + material = materialIndex, + mode = 4, + }; + return primitive; + } + } + + public static glTFMesh Export(glTF gltf, int bufferIndex, + MeshWithRenderer unityMesh, List unityMaterials, + IAxisInverter axisInverter, MeshExportSettings settings) + { + var mesh = unityMesh.Mesh; + var gltfMesh = new glTFMesh(mesh.name); + + if (settings.ExportTangents) + { + // support しない + throw new NotImplementedException(); + } + + var positions = mesh.vertices; + var normals = mesh.normals; + var uv = mesh.uv; + var boneWeights = mesh.boneWeights; + + Func getJointIndex = null; + if (boneWeights != null && boneWeights.Length == positions.Length) + { + getJointIndex = unityMesh.GetJointIndex; + } + + Vector3[] blendShapePositions = new Vector3[mesh.vertexCount]; + Vector3[] blendShapeNormals = new Vector3[mesh.vertexCount]; + + for (int i = 0; i < mesh.subMeshCount; ++i) + { + var indices = mesh.GetIndices(i); + + // mesh + // index の順に attributes を蓄える + var buffer = new VertexBuffer(indices.Length, getJointIndex); + foreach (var k in indices) + { + buffer.Push(axisInverter.InvertVector3(positions[k]), axisInverter.InvertVector3(normals[k]), uv[k].ReverseUV()); + if (getJointIndex != null) + { + buffer.Push(boneWeights[k]); + } + } + + var material = unityMesh.Renderer.sharedMaterials[i]; + var materialIndex = -1; + if (material != null) + { + materialIndex = unityMaterials.IndexOf(material); + } + var gltfPrimitive = buffer.ToGltf(gltf, bufferIndex, materialIndex); + + // blendShape + for (int j = 0; j < mesh.blendShapeCount; ++j) + { + var blendShape = new BlendShapeBuffer(indices.Length); + + // index の順に attributes を蓄える + mesh.GetBlendShapeFrameVertices(j, 0, blendShapePositions, blendShapeNormals, null); + foreach (var k in indices) + { + blendShape.Push( + axisInverter.InvertVector3(blendShapePositions[k]), + axisInverter.InvertVector3(blendShapeNormals[k])); + } + + gltfPrimitive.targets.Add(blendShape.ToGltf(gltf, bufferIndex, !settings.ExportOnlyBlendShapePosition)); + } + + gltfMesh.primitives.Add(gltfPrimitive); + } + + var targetNames = Enumerable.Range(0, mesh.blendShapeCount).Select(x => mesh.GetBlendShapeName(x)).ToArray(); + gltf_mesh_extras_targetNames.Serialize(gltfMesh, targetNames); + + return gltfMesh; + } + } +} diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshExporterDivided.cs.meta b/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshExporterDivided.cs.meta new file mode 100644 index 000000000..6a31e5d50 --- /dev/null +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshExporterDivided.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 92bc82be5ead84a429346379590f6d7d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: