From d32f8427667e3195d72e142ae330d35b65ed4369 Mon Sep 17 00:00:00 2001 From: mkc1370 Date: Fri, 21 Feb 2020 20:29:32 +0900 Subject: [PATCH] Support mesh sharing morph target --- .../glTFMesh.extras.targetNames.cs | 32 +++ .../glTFMesh.extras.targetNames.cs.meta | 3 + Assets/VRM/UniGLTF/Scripts/Format/glTFMesh.cs | 4 +- Assets/VRM/UniGLTF/Scripts/IO/MeshImporter.cs | 182 ++++++++++++++++-- 4 files changed, 209 insertions(+), 12 deletions(-) create mode 100644 Assets/VRM/UniGLTF/Scripts/Format/ExtensionsAndExtras/glTFMesh.extras.targetNames.cs create mode 100644 Assets/VRM/UniGLTF/Scripts/Format/ExtensionsAndExtras/glTFMesh.extras.targetNames.cs.meta diff --git a/Assets/VRM/UniGLTF/Scripts/Format/ExtensionsAndExtras/glTFMesh.extras.targetNames.cs b/Assets/VRM/UniGLTF/Scripts/Format/ExtensionsAndExtras/glTFMesh.extras.targetNames.cs new file mode 100644 index 000000000..49e12de51 --- /dev/null +++ b/Assets/VRM/UniGLTF/Scripts/Format/ExtensionsAndExtras/glTFMesh.extras.targetNames.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using UniJSON; + + +namespace UniGLTF +{ + /// + /// https://github.com/KhronosGroup/glTF/issues/1036 + /// + [Serializable] + public partial class glTFMesh_extras : ExtraBase + { + [JsonSchema(Required = true, MinItems = 1)] + public List targetNames = new List(); + + [JsonSerializeMembers] + void PrimitiveMembers(GLTFJsonFormatter f) + { + if (targetNames.Count > 0) + { + f.Key("targetNames"); + f.BeginList(); + foreach (var x in targetNames) + { + f.Value(x); + } + f.EndList(); + } + } + } +} diff --git a/Assets/VRM/UniGLTF/Scripts/Format/ExtensionsAndExtras/glTFMesh.extras.targetNames.cs.meta b/Assets/VRM/UniGLTF/Scripts/Format/ExtensionsAndExtras/glTFMesh.extras.targetNames.cs.meta new file mode 100644 index 000000000..139962cd6 --- /dev/null +++ b/Assets/VRM/UniGLTF/Scripts/Format/ExtensionsAndExtras/glTFMesh.extras.targetNames.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 97b77d4c1c0d44b594e9187e41b3152d +timeCreated: 1582269878 \ No newline at end of file diff --git a/Assets/VRM/UniGLTF/Scripts/Format/glTFMesh.cs b/Assets/VRM/UniGLTF/Scripts/Format/glTFMesh.cs index 072084d3d..c2d11a466 100644 --- a/Assets/VRM/UniGLTF/Scripts/Format/glTFMesh.cs +++ b/Assets/VRM/UniGLTF/Scripts/Format/glTFMesh.cs @@ -146,9 +146,11 @@ namespace UniGLTF [JsonSchema(MinItems = 1)] public float[] weights; + [JsonSchema(SkipSchemaComparison = true)] + public glTFMesh_extras extras = null; + // empty schemas public object extensions; - public object extras; public glTFMesh() { diff --git a/Assets/VRM/UniGLTF/Scripts/IO/MeshImporter.cs b/Assets/VRM/UniGLTF/Scripts/IO/MeshImporter.cs index d30be935a..e233eeacf 100644 --- a/Assets/VRM/UniGLTF/Scripts/IO/MeshImporter.cs +++ b/Assets/VRM/UniGLTF/Scripts/IO/MeshImporter.cs @@ -12,6 +12,155 @@ namespace UniGLTF const float FRAME_WEIGHT = 100.0f; + // mesh is sharing morph targets. + private static MeshContext _ImportMeshSharingMorphTarget(ImporterContext ctx, glTFMesh gltfMesh) + { + var positions = new List(); + var normals = new List(); + var tangents = new List(); + var uv = new List(); + var colors = new List(); + var blendShapes = new List(); + var meshContext = new MeshContext(); + + // blendshapes + var targetNames = gltfMesh.extras.targetNames; + for (int i = 1; i < gltfMesh.primitives.Count; ++i) + { + if (gltfMesh.primitives[i].targets.Count != targetNames.Count) + { + throw new FormatException(string.Format("different targets length: {0} with targetNames length.", + gltfMesh.primitives[i])); + } + } + for (var i = 0; i < targetNames.Count; i++) + { + var blendShape = new BlendShape(!string.IsNullOrEmpty(targetNames[i]) ? targetNames[i] : i.ToString()); + blendShapes.Add(blendShape); + } + + foreach (var prim in gltfMesh.primitives) + { + var indexOffset = positions.Count; + var indexBuffer = prim.indices; + + var positionCount = positions.Count; + positions.AddRange(ctx.GLTF.GetArrayFromAccessor(prim.attributes.POSITION).Select(x => x.ReverseZ())); + positionCount = positions.Count - positionCount; + + // normal + if (prim.attributes.NORMAL != -1) + { + normals.AddRange(ctx.GLTF.GetArrayFromAccessor(prim.attributes.NORMAL).Select(x => x.ReverseZ())); + } + + if (prim.attributes.TANGENT != -1) + { + tangents.AddRange(ctx.GLTF.GetArrayFromAccessor(prim.attributes.TANGENT).Select(x => x.ReverseZ())); + } + + // uv + if (prim.attributes.TEXCOORD_0 != -1) + { + if (ctx.IsGeneratedUniGLTFAndOlder(1, 16)) + { +#pragma warning disable 0612 + // backward compatibility + uv.AddRange(ctx.GLTF.GetArrayFromAccessor(prim.attributes.TEXCOORD_0).Select(x => x.ReverseY())); +#pragma warning restore 0612 + } + else + { + uv.AddRange(ctx.GLTF.GetArrayFromAccessor(prim.attributes.TEXCOORD_0).Select(x => x.ReverseUV())); + } + } + else + { + // for inconsistent attributes in primitives + uv.AddRange(new Vector2[positionCount]); + } + + // color + if (prim.attributes.COLOR_0 != -1) + { + colors.AddRange(ctx.GLTF.GetArrayFromAccessor(prim.attributes.COLOR_0)); + } + + // skin + if (prim.attributes.JOINTS_0 != -1 && prim.attributes.WEIGHTS_0 != -1) + { + var joints0 = ctx.GLTF.GetArrayFromAccessor(prim.attributes.JOINTS_0); // uint4 + var weights0 = ctx.GLTF.GetArrayFromAccessor(prim.attributes.WEIGHTS_0).Select(x => x.One()).ToArray(); + + for (int j = 0; j < joints0.Length; ++j) + { + var bw = new BoneWeight(); + + bw.boneIndex0 = joints0[j].x; + bw.weight0 = weights0[j].x; + + bw.boneIndex1 = joints0[j].y; + bw.weight1 = weights0[j].y; + + bw.boneIndex2 = joints0[j].z; + bw.weight2 = weights0[j].z; + + bw.boneIndex3 = joints0[j].w; + bw.weight3 = weights0[j].w; + + meshContext.boneWeights.Add(bw); + } + } + + // blendshape + if (prim.targets != null && prim.targets.Count > 0) + { + for (int i = 0; i < prim.targets.Count; ++i) + { + var primTarget = prim.targets[i]; + if (primTarget.POSITION != -1) + { + blendShapes[i].Positions.AddRange( + ctx.GLTF.GetArrayFromAccessor(primTarget.POSITION).Select(x => x.ReverseZ()).ToArray()); + } + if (primTarget.NORMAL != -1) + { + blendShapes[i].Normals.AddRange( + ctx.GLTF.GetArrayFromAccessor(primTarget.NORMAL).Select(x => x.ReverseZ()).ToArray()); + } + if (primTarget.TANGENT != -1) + { + blendShapes[i].Tangents.AddRange( + ctx.GLTF.GetArrayFromAccessor(primTarget.TANGENT).Select(x => x.ReverseZ()).ToArray()); + } + } + } + + var indices = + (indexBuffer >= 0) + ? ctx.GLTF.GetIndices(indexBuffer) + : TriangleUtil.FlipTriangle(Enumerable.Range(0, meshContext.positions.Length)).ToArray() // without index array + ; + for (int i = 0; i < indices.Length; ++i) + { + indices[i] += indexOffset; + } + + meshContext.subMeshes.Add(indices); + + // material + meshContext.materialIndices.Add(prim.material); + } + + meshContext.positions = positions.ToArray(); + meshContext.normals = normals.ToArray(); + meshContext.tangents = tangents.ToArray(); + meshContext.uv = uv.ToArray(); + meshContext.blendShapes = blendShapes; + + return meshContext; + } + // multiple submMesh is not sharing a VertexBuffer. // each subMesh use a independent VertexBuffer. private static MeshContext _ImportMeshIndependentVertexBuffer(ImporterContext ctx, glTFMesh gltfMesh) @@ -352,22 +501,33 @@ namespace UniGLTF public MeshContext ReadMesh(ImporterContext ctx, int meshIndex) { var gltfMesh = ctx.GLTF.meshes[meshIndex]; - glTFAttributes lastAttributes = null; - var sharedAttributes = true; - foreach (var prim in gltfMesh.primitives) + + bool sharedMorphTarget = gltfMesh.extras != null && gltfMesh.extras.targetNames.Count > 0; + MeshContext meshContext; + if (sharedMorphTarget) { - if (lastAttributes != null && !prim.attributes.Equals(lastAttributes)) + meshContext = _ImportMeshSharingMorphTarget(ctx, gltfMesh); + } + else + { + glTFAttributes lastAttributes = null; + var sharedAttributes = true; + foreach (var prim in gltfMesh.primitives) { - sharedAttributes = false; - break; + if (lastAttributes != null && !prim.attributes.Equals(lastAttributes)) + { + sharedAttributes = false; + break; + } + + lastAttributes = prim.attributes; } - lastAttributes = prim.attributes; + + meshContext = sharedAttributes + ? _ImportMeshSharingVertexBuffer(ctx, gltfMesh) + : _ImportMeshIndependentVertexBuffer(ctx, gltfMesh); } - var meshContext = sharedAttributes - ? _ImportMeshSharingVertexBuffer(ctx, gltfMesh) - : _ImportMeshIndependentVertexBuffer(ctx, gltfMesh) - ; meshContext.name = gltfMesh.name; if (string.IsNullOrEmpty(meshContext.name)) {