From 9551f08cb073bc4b7c0921a114bd8e677bf2ac9c Mon Sep 17 00:00:00 2001 From: ousttrue Date: Fri, 13 Nov 2020 18:25:00 +0900 Subject: [PATCH 1/4] =?UTF-8?q?uv2=E3=81=AE=E4=BB=A3=E5=85=A5=E6=BC=8F?= =?UTF-8?q?=E3=82=8C=E3=80=81=E7=84=A1=E3=81=8B=E3=81=A3=E3=81=9F=E6=99=82?= =?UTF-8?q?=E3=81=AB0=E3=81=A7=E8=A9=B0=E3=82=81=E3=82=8B=E3=81=AA?= =?UTF-8?q?=E3=81=A9=E3=81=AE=E5=95=8F=E9=A1=8C=E3=80=82=E6=9B=B8=E3=81=8D?= =?UTF-8?q?=E7=9B=B4=E3=81=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Assets/VRM/UniGLTF/Scripts/IO/MeshImporter.cs | 979 +++++++++--------- 1 file changed, 479 insertions(+), 500 deletions(-) diff --git a/Assets/VRM/UniGLTF/Scripts/IO/MeshImporter.cs b/Assets/VRM/UniGLTF/Scripts/IO/MeshImporter.cs index bd92613b7..f2467caa8 100644 --- a/Assets/VRM/UniGLTF/Scripts/IO/MeshImporter.cs +++ b/Assets/VRM/UniGLTF/Scripts/IO/MeshImporter.cs @@ -12,538 +12,518 @@ namespace UniGLTF { const float FRAME_WEIGHT = 100.0f; - - // mesh is sharing morph targets. - private static MeshContext _ImportMeshSharingMorphTarget(ImporterContext ctx, glTFMesh gltfMesh) + public class MeshContext { - var positions = new List(); - var normals = new List(); - var tangents = new List(); - var uv = new List(); - var uv2 = 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) + [Serializable, StructLayout(LayoutKind.Sequential, Pack = 1)] + struct Float4 { - if (gltfMesh.primitives[i].targets.Count != targetNames.Count) + public float x; + public float y; + public float z; + public float w; + + public Float4 One() { - 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)) + var sum = x + y + z + w; + var f = 1.0f / sum; + return new Float4 { -#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]); - } - - // uv1 - if (prim.attributes.TEXCOORD_1 != -1) - { - uv2.AddRange(ctx.GLTF.GetArrayFromAccessor(prim.attributes.TEXCOORD_1).Select(x => x.ReverseUV())); - } - else - { - // for inconsistent attributes in primitives - uv2.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) - { - //Debug.LogWarning("_ImportMeshIndependentVertexBuffer"); - - var targets = gltfMesh.primitives[0].targets; - for (int i = 1; i < gltfMesh.primitives.Count; ++i) - { - if (!gltfMesh.primitives[i].targets.SequenceEqual(targets)) - { - throw new NotImplementedException(string.Format("different targets: {0} with {1}", - gltfMesh.primitives[i], - targets)); + x = x * f, + y = y * f, + z = z * f, + w = w * f, + }; } } - var positions = new List(); - var normals = new List(); - var tangents = new List(); - var uv = new List(); - var uv2 = new List(); - var colors = new List(); - var meshContext = new MeshContext(); - foreach (var prim in gltfMesh.primitives) + string m_name; + public string name => m_name; + + public readonly List positions = new List(); + public readonly List normals = new List(); + + [Obsolete] + public readonly List tangents = new List(); + + public readonly List uv = new List(); + public readonly List uv2 = new List(); + public readonly List colors = new List(); + public readonly List boneWeights = new List(); + public readonly List subMeshes = new List(); + public readonly List materialIndices = new List(); + public readonly List blendShapes = new List(); + + public MeshContext(string name, int meshIndex) { - 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) + if (string.IsNullOrEmpty(name)) { - normals.AddRange(ctx.GLTF.GetArrayFromAccessor(prim.attributes.NORMAL).Select(x => x.ReverseZ())); + name = string.Format("UniGLTF import#{0}", meshIndex); } - - 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]); - } - - // uv2 - if (prim.attributes.TEXCOORD_1 != -1) - { - uv2.AddRange(ctx.GLTF.GetArrayFromAccessor(prim.attributes.TEXCOORD_1).Select(x => x.ReverseUV())); - } - else - { - // for inconsistent attributes in primitives - uv2.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 name = string.Format("target{0}", i++); - var primTarget = prim.targets[i]; - var blendShape = new BlendShape(!string.IsNullOrEmpty(prim.extras.targetNames[i]) - ? prim.extras.targetNames[i] - : i.ToString()) - ; - if (primTarget.POSITION != -1) - { - blendShape.Positions.AddRange( - ctx.GLTF.GetArrayFromAccessor(primTarget.POSITION).Select(x => x.ReverseZ()).ToArray()); - } - if (primTarget.NORMAL != -1) - { - blendShape.Normals.AddRange( - ctx.GLTF.GetArrayFromAccessor(primTarget.NORMAL).Select(x => x.ReverseZ()).ToArray()); - } - if (primTarget.TANGENT != -1) - { - blendShape.Tangents.AddRange( - ctx.GLTF.GetArrayFromAccessor(primTarget.TANGENT).Select(x => x.ReverseZ()).ToArray()); - } - meshContext.blendShapes.Add(blendShape); - } - } - - 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); + m_name = name; } - meshContext.positions = positions.ToArray(); - meshContext.normals = normals.ToArray(); - meshContext.tangents = tangents.ToArray(); - meshContext.uv = uv.ToArray(); - - return meshContext; - } - - - // multiple submesh sharing same VertexBuffer - private static MeshContext _ImportMeshSharingVertexBuffer(ImporterContext ctx, glTFMesh gltfMesh) - { - var context = new MeshContext(); - + /// + /// mesh.extras.targetNames が存在する => UniVRMでエクスポートしたものであると仮定 + /// + /// * 各primitiveが同じ attribute を共有している + /// * 各primitiveが同じ targets を共有している + /// * 各primitiveは indices が異なる(submesh) + /// + /// を仮定して Mesh をロードする。 + /// + /// + /// + /// + public void ImportMeshSharingMorphTarget(ImporterContext ctx, glTFMesh gltfMesh) { - var prim = gltfMesh.primitives.First(); - context.positions = ctx.GLTF.GetArrayFromAccessor(prim.attributes.POSITION).SelectInplace(x => x.ReverseZ()); - - // normal - if (prim.attributes.NORMAL != -1) + // blendshapes + var targetNames = gltfMesh.extras.targetNames; + for (int i = 1; i < gltfMesh.primitives.Count; ++i) { - context.normals = ctx.GLTF.GetArrayFromAccessor(prim.attributes.NORMAL).SelectInplace(x => x.ReverseZ()); + 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 false // tangent if (prim.attributes.TANGENT != -1) { - context.tangents = ctx.GLTF.GetArrayFromAccessor(prim.attributes.TANGENT).SelectInplace(x => x.ReverseZ()); + tangents.AddRange(ctx.GLTF.GetArrayFromAccessor(prim.attributes.TANGENT).Select(x => x.ReverseZ())); } +#endif - // uv - if (prim.attributes.TEXCOORD_0 != -1) - { - if (ctx.IsGeneratedUniGLTFAndOlder(1, 16)) + // uv + if (prim.attributes.TEXCOORD_0 != -1) { + if (ctx.IsGeneratedUniGLTFAndOlder(1, 16)) + { #pragma warning disable 0612 - // backward compatibility - context.uv = ctx.GLTF.GetArrayFromAccessor(prim.attributes.TEXCOORD_0).SelectInplace(x => x.ReverseY()); + // 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 { - context.uv = ctx.GLTF.GetArrayFromAccessor(prim.attributes.TEXCOORD_0).SelectInplace(x => x.ReverseUV()); + // for inconsistent attributes in primitives + uv.AddRange(new Vector2[positionCount]); } - } - else - { - // for inconsistent attributes in primitives - context.uv = new Vector2[context.positions.Length]; - } - // uv2 - if (prim.attributes.TEXCOORD_1 != -1) - { - context.uv2 = ctx.GLTF.GetArrayFromAccessor(prim.attributes.TEXCOORD_1).SelectInplace(x => x.ReverseUV()); - } - else - { - // for inconsistent attributes in primitives - context.uv2 = new Vector2[context.positions.Length]; - } - - // color - if (prim.attributes.COLOR_0 != -1) - { - if (ctx.GLTF.accessors[prim.attributes.COLOR_0].TypeCount == 3) + // uv1 + if (prim.attributes.TEXCOORD_1 != -1) { - var vec3Color = ctx.GLTF.GetArrayFromAccessor(prim.attributes.COLOR_0); - context.colors = new Color[vec3Color.Length]; + uv2.AddRange(ctx.GLTF.GetArrayFromAccessor(prim.attributes.TEXCOORD_1).Select(x => x.ReverseUV())); + } - for (int i = 0; i < vec3Color.Length; i++) + // 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) { - Vector3 color = vec3Color[i]; - context.colors[i] = new Color(color.x, color.y, color.z); + 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; + + boneWeights.Add(bw); } } - else if (ctx.GLTF.accessors[prim.attributes.COLOR_0].TypeCount == 4) + + // blendshape + if (prim.targets != null && prim.targets.Count > 0) { - context.colors = ctx.GLTF.GetArrayFromAccessor(prim.attributes.COLOR_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, positions.Count)).ToArray() // without index array + ; + for (int i = 0; i < indices.Length; ++i) + { + indices[i] += indexOffset; + } + + subMeshes.Add(indices); + + // material + materialIndices.Add(prim.material); + } + } + + /// + /// 各 primitive の attribute の要素が同じでない。=> uv が有るものと無いものが混在するなど + /// glTF 的にはありうる。 + /// + /// primitive を独立した(Independent) Mesh として扱いこれを連結する。 + /// + /// + /// + /// + public void ImportMeshIndependentVertexBuffer(ImporterContext ctx, glTFMesh gltfMesh) + { + var targets = gltfMesh.primitives[0].targets; + for (int i = 1; i < gltfMesh.primitives.Count; ++i) + { + if (!gltfMesh.primitives[i].targets.SequenceEqual(targets)) + { + // + // 各 primitive の morphTarget の内容が違うことは許容しない + // + throw new NotImplementedException(string.Format("different targets: {0} with {1}", + gltfMesh.primitives[i], + targets)); + } + } + + 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 false + if (prim.attributes.TANGENT != -1) + { + tangents.AddRange(ctx.GLTF.GetArrayFromAccessor(prim.attributes.TANGENT).Select(x => x.ReverseZ())); + } +#endif + + // 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 { - throw new NotImplementedException(string.Format("unknown color type {0}", ctx.GLTF.accessors[prim.attributes.COLOR_0].type)); - } - } - - // 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); - for (int i = 0; i < weights0.Length; ++i) - { - weights0[i] = weights0[i].One(); + // for inconsistent attributes in primitives + uv.AddRange(new Vector2[positionCount]); } - for (int j = 0; j < joints0.Length; ++j) + // uv2 + if (prim.attributes.TEXCOORD_1 != -1) { - 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; - - context.boneWeights.Add(bw); + uv2.AddRange(ctx.GLTF.GetArrayFromAccessor(prim.attributes.TEXCOORD_1).Select(x => x.ReverseUV())); } - } - // blendshape - if (prim.targets != null && prim.targets.Count > 0) - { - context.blendShapes.AddRange(prim.targets.Select((x, i) => new BlendShape( - i < prim.extras.targetNames.Count && !string.IsNullOrEmpty(prim.extras.targetNames[i]) - ? prim.extras.targetNames[i] - : i.ToString()))); - for (int i = 0; i < prim.targets.Count; ++i) + // color + if (prim.attributes.COLOR_0 != -1) { - //var name = string.Format("target{0}", i++); - var primTarget = prim.targets[i]; - var blendShape = context.blendShapes[i]; + colors.AddRange(ctx.GLTF.GetArrayFromAccessor(prim.attributes.COLOR_0)); + } - if (primTarget.POSITION != -1) + // 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) { - blendShape.Positions.Assign( - ctx.GLTF.GetArrayFromAccessor(primTarget.POSITION), x => x.ReverseZ()); - } - if (primTarget.NORMAL != -1) - { - blendShape.Normals.Assign( - ctx.GLTF.GetArrayFromAccessor(primTarget.NORMAL), x => x.ReverseZ()); - } - if (primTarget.TANGENT != -1) - { - blendShape.Tangents.Assign( - ctx.GLTF.GetArrayFromAccessor(primTarget.TANGENT), x => x.ReverseZ()); + 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; + + boneWeights.Add(bw); } } + + // blendshape + if (prim.targets != null && prim.targets.Count > 0) + { + for (int i = 0; i < prim.targets.Count; ++i) + { + //var name = string.Format("target{0}", i++); + var primTarget = prim.targets[i]; + var blendShape = new BlendShape(!string.IsNullOrEmpty(prim.extras.targetNames[i]) + ? prim.extras.targetNames[i] + : i.ToString()) + ; + if (primTarget.POSITION != -1) + { + blendShape.Positions.AddRange( + ctx.GLTF.GetArrayFromAccessor(primTarget.POSITION).Select(x => x.ReverseZ()).ToArray()); + } + if (primTarget.NORMAL != -1) + { + blendShape.Normals.AddRange( + ctx.GLTF.GetArrayFromAccessor(primTarget.NORMAL).Select(x => x.ReverseZ()).ToArray()); + } + if (primTarget.TANGENT != -1) + { + blendShape.Tangents.AddRange( + ctx.GLTF.GetArrayFromAccessor(primTarget.TANGENT).Select(x => x.ReverseZ()).ToArray()); + } + blendShapes.Add(blendShape); + } + } + + var indices = + (indexBuffer >= 0) + ? ctx.GLTF.GetIndices(indexBuffer) + : TriangleUtil.FlipTriangle(Enumerable.Range(0, positions.Count)).ToArray() // without index array + ; + for (int i = 0; i < indices.Length; ++i) + { + indices[i] += indexOffset; + } + + subMeshes.Add(indices); + + // material + materialIndices.Add(prim.material); } } - foreach (var prim in gltfMesh.primitives) + // multiple submesh sharing same VertexBuffer + public void ImportMeshSharingVertexBuffer(ImporterContext ctx, glTFMesh gltfMesh) { - if (prim.indices == -1) { - context.subMeshes.Add(TriangleUtil.FlipTriangle(Enumerable.Range(0, context.positions.Length)).ToArray()); - } - else - { - var indices = ctx.GLTF.GetIndices(prim.indices); - context.subMeshes.Add(indices); + var prim = gltfMesh.primitives.First(); + positions.AddRange(ctx.GLTF.GetArrayFromAccessor(prim.attributes.POSITION).SelectInplace(x => x.ReverseZ())); + + // normal + if (prim.attributes.NORMAL != -1) + { + normals.AddRange(ctx.GLTF.GetArrayFromAccessor(prim.attributes.NORMAL).SelectInplace(x => x.ReverseZ())); + } + +#if false + // tangent + if (prim.attributes.TANGENT != -1) + { + tangents.AddRange(ctx.GLTF.GetArrayFromAccessor(prim.attributes.TANGENT).SelectInplace(x => x.ReverseZ())); + } +#endif + + // 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).SelectInplace(x => x.ReverseY())); +#pragma warning restore 0612 + } + else + { + uv.AddRange(ctx.GLTF.GetArrayFromAccessor(prim.attributes.TEXCOORD_0).SelectInplace(x => x.ReverseUV())); + } + } + + // uv2 + if (prim.attributes.TEXCOORD_1 != -1) + { + uv2.AddRange(ctx.GLTF.GetArrayFromAccessor(prim.attributes.TEXCOORD_1).SelectInplace(x => x.ReverseUV())); + } + + // color + if (prim.attributes.COLOR_0 != -1) + { + if (ctx.GLTF.accessors[prim.attributes.COLOR_0].TypeCount == 3) + { + var vec3Color = ctx.GLTF.GetArrayFromAccessor(prim.attributes.COLOR_0); + colors.AddRange(new Color[vec3Color.Length]); + + for (int i = 0; i < vec3Color.Length; i++) + { + Vector3 color = vec3Color[i]; + colors[i] = new Color(color.x, color.y, color.z); + } + } + else if (ctx.GLTF.accessors[prim.attributes.COLOR_0].TypeCount == 4) + { + colors.AddRange(ctx.GLTF.GetArrayFromAccessor(prim.attributes.COLOR_0)); + } + else + { + throw new NotImplementedException(string.Format("unknown color type {0}", ctx.GLTF.accessors[prim.attributes.COLOR_0].type)); + } + } + + // 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); + for (int i = 0; i < weights0.Length; ++i) + { + weights0[i] = weights0[i].One(); + } + + 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; + + boneWeights.Add(bw); + } + } + + // blendshape + if (prim.targets != null && prim.targets.Count > 0) + { + blendShapes.AddRange(prim.targets.Select((x, i) => new BlendShape( + i < prim.extras.targetNames.Count && !string.IsNullOrEmpty(prim.extras.targetNames[i]) + ? prim.extras.targetNames[i] + : i.ToString()))); + for (int i = 0; i < prim.targets.Count; ++i) + { + //var name = string.Format("target{0}", i++); + var primTarget = prim.targets[i]; + var blendShape = blendShapes[i]; + + if (primTarget.POSITION != -1) + { + blendShape.Positions.Assign( + ctx.GLTF.GetArrayFromAccessor(primTarget.POSITION), x => x.ReverseZ()); + } + if (primTarget.NORMAL != -1) + { + blendShape.Normals.Assign( + ctx.GLTF.GetArrayFromAccessor(primTarget.NORMAL), x => x.ReverseZ()); + } + if (primTarget.TANGENT != -1) + { + blendShape.Tangents.Assign( + ctx.GLTF.GetArrayFromAccessor(primTarget.TANGENT), x => x.ReverseZ()); + } + } + } } - // material - context.materialIndices.Add(prim.material); - } - - return context; - } - - - [Serializable, StructLayout(LayoutKind.Sequential, Pack = 1)] - struct Float4 - { - public float x; - public float y; - public float z; - public float w; - - public Float4 One() - { - var sum = x + y + z + w; - var f = 1.0f / sum; - return new Float4 + foreach (var prim in gltfMesh.primitives) { - x = x * f, - y = y * f, - z = z * f, - w = w * f, - }; + if (prim.indices == -1) + { + subMeshes.Add(TriangleUtil.FlipTriangle(Enumerable.Range(0, positions.Count)).ToArray()); + } + else + { + var indices = ctx.GLTF.GetIndices(prim.indices); + subMeshes.Add(indices); + } + + // material + materialIndices.Add(prim.material); + } } } - - public class MeshContext - { - public string name; - public Vector3[] positions; - public Vector3[] normals; - public Vector4[] tangents; - public Vector2[] uv; - public Vector2[] uv2; - public Color[] colors; - public List boneWeights = new List(); - public List subMeshes = new List(); - public List materialIndices = new List(); - public List blendShapes = new List(); - } - - public MeshContext ReadMesh(ImporterContext ctx, int meshIndex) { var gltfMesh = ctx.GLTF.meshes[meshIndex]; bool sharedMorphTarget = gltfMesh.extras != null && gltfMesh.extras.targetNames.Count > 0; - MeshContext meshContext; + var meshContext = new MeshContext(gltfMesh.name, meshIndex); if (sharedMorphTarget) { - meshContext = _ImportMeshSharingMorphTarget(ctx, gltfMesh); + meshContext.ImportMeshSharingMorphTarget(ctx, gltfMesh); } else { @@ -560,21 +540,19 @@ namespace UniGLTF lastAttributes = prim.attributes; } - meshContext = sharedAttributes - ? _ImportMeshSharingVertexBuffer(ctx, gltfMesh) - : _ImportMeshIndependentVertexBuffer(ctx, gltfMesh); - } - - meshContext.name = gltfMesh.name; - if (string.IsNullOrEmpty(meshContext.name)) - { - meshContext.name = string.Format("UniGLTF import#{0}", meshIndex); + if (sharedAttributes) + { + meshContext.ImportMeshSharingVertexBuffer(ctx, gltfMesh); + } + else + { + meshContext.ImportMeshIndependentVertexBuffer(ctx, gltfMesh); + } } return meshContext; } - public static MeshWithMaterials BuildMesh(ImporterContext ctx, MeshImporter.MeshContext meshContext) { if (!meshContext.materialIndices.Any()) @@ -586,7 +564,7 @@ namespace UniGLTF var mesh = new Mesh(); mesh.name = meshContext.name; - if (meshContext.positions.Length > UInt16.MaxValue) + if (meshContext.positions.Count > UInt16.MaxValue) { #if UNITY_2017_3_OR_NEWER mesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32; @@ -596,24 +574,24 @@ namespace UniGLTF #endif } - mesh.vertices = meshContext.positions; + mesh.vertices = meshContext.positions.ToArray(); bool recalculateNormals = false; - if (meshContext.normals != null && meshContext.normals.Length > 0) + if (meshContext.normals != null && meshContext.normals.Count > 0) { - mesh.normals = meshContext.normals; + mesh.normals = meshContext.normals.ToArray(); } else { recalculateNormals = true; } - if (meshContext.uv != null && meshContext.uv.Length > 0) + if (meshContext.uv != null && meshContext.uv.Count == mesh.vertexCount) { - mesh.uv = meshContext.uv; + mesh.uv = meshContext.uv.ToArray(); } - if (meshContext.uv2 != null && meshContext.uv2.Length > 0) + if (meshContext.uv2 != null && meshContext.uv2.Count == mesh.vertexCount) { - mesh.uv2 = meshContext.uv2; + mesh.uv2 = meshContext.uv2.ToArray(); } bool recalculateTangents = true; @@ -625,9 +603,9 @@ namespace UniGLTF } #endif - if (meshContext.colors != null && meshContext.colors.Length > 0) + if (meshContext.colors != null && meshContext.colors.Count == mesh.vertexCount) { - mesh.colors = meshContext.colors; + mesh.colors = meshContext.colors.ToArray(); } if (meshContext.boneWeights != null && meshContext.boneWeights.Count > 0) { @@ -669,7 +647,7 @@ namespace UniGLTF { mesh.AddBlendShapeFrame(blendShape.Name, FRAME_WEIGHT, blendShape.Positions.ToArray(), - (meshContext.normals != null && meshContext.normals.Length == mesh.vertexCount && blendShape.Normals.Count() == blendShape.Positions.Count()) ? blendShape.Normals.ToArray() : null, + (meshContext.normals != null && meshContext.normals.Count == mesh.vertexCount && blendShape.Normals.Count() == blendShape.Positions.Count()) ? blendShape.Normals.ToArray() : null, null ); } @@ -708,7 +686,7 @@ namespace UniGLTF var mesh = new Mesh(); mesh.name = meshContext.name; - if (meshContext.positions.Length > UInt16.MaxValue) + if (meshContext.positions.Count > UInt16.MaxValue) { #if UNITY_2017_3_OR_NEWER mesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32; @@ -719,42 +697,43 @@ namespace UniGLTF } - mesh.vertices = meshContext.positions; + mesh.vertices = meshContext.positions.ToArray(); bool recalculateNormals = false; - if (meshContext.normals != null && meshContext.normals.Length > 0) + if (meshContext.normals != null && meshContext.normals.Count == mesh.vertexCount) { - mesh.normals = meshContext.normals; + mesh.normals = meshContext.normals.ToArray(); } else { recalculateNormals = true; } - if (meshContext.uv != null && meshContext.uv.Length > 0) + if (meshContext.uv != null && meshContext.uv.Count == mesh.vertexCount) { - mesh.uv = meshContext.uv; + mesh.uv = meshContext.uv.ToArray(); } bool recalculateTangents = true; #if UNIGLTF_IMPORT_TANGENTS - if (meshContext.tangents != null && meshContext.tangents.Length > 0) + if (meshContext.tangents != null && meshContext.tangents.Count == mesh.vertexCount) { - mesh.tangents = meshContext.tangents; + mesh.tangents = meshContext.tangents.ToArray(); recalculateTangents = false; } #endif - if (meshContext.colors != null && meshContext.colors.Length > 0) + if (meshContext.colors != null && meshContext.colors.Count == mesh.vertexCount) { - - mesh.colors = meshContext.colors; + mesh.colors = meshContext.colors.ToArray(); } - if (meshContext.boneWeights != null && meshContext.boneWeights.Count > 0) + + if (meshContext.boneWeights != null && meshContext.boneWeights.Count == mesh.vertexCount) { mesh.boneWeights = meshContext.boneWeights.ToArray(); } + mesh.subMeshCount = meshContext.subMeshes.Count; for (int i = 0; i < meshContext.subMeshes.Count; ++i) { @@ -795,7 +774,7 @@ namespace UniGLTF { mesh.AddBlendShapeFrame(blendShape.Name, FRAME_WEIGHT, blendShape.Positions.ToArray(), - (meshContext.normals != null && meshContext.normals.Length == mesh.vertexCount && blendShape.Normals.Count() == blendShape.Positions.Count()) ? blendShape.Normals.ToArray() : null, + (meshContext.normals != null && meshContext.normals.Count == mesh.vertexCount && blendShape.Normals.Count() == blendShape.Positions.Count()) ? blendShape.Normals.ToArray() : null, null ); yield return null; From 7113899644c7a97e61d24b680de9e97ed1888db6 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Fri, 13 Nov 2020 18:56:16 +0900 Subject: [PATCH 2/4] =?UTF-8?q?=E3=82=B3=E3=83=BC=E3=83=89=E6=95=B4?= =?UTF-8?q?=E7=90=86=E3=80=82=E5=8F=A4=E3=81=84=20#if=20=E3=82=92=E5=89=8A?= =?UTF-8?q?=E9=99=A4=E3=80=82=E5=90=8C=E3=81=98=E5=87=A6=E7=90=86=E3=82=92?= =?UTF-8?q?=E9=96=A2=E6=95=B0=E3=81=AB=E5=88=87=E3=82=8A=E5=87=BA=E3=81=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Assets/VRM/UniGLTF/Scripts/IO/MeshImporter.cs | 742 +++++++----------- 1 file changed, 301 insertions(+), 441 deletions(-) diff --git a/Assets/VRM/UniGLTF/Scripts/IO/MeshImporter.cs b/Assets/VRM/UniGLTF/Scripts/IO/MeshImporter.cs index f2467caa8..e8a7a77a9 100644 --- a/Assets/VRM/UniGLTF/Scripts/IO/MeshImporter.cs +++ b/Assets/VRM/UniGLTF/Scripts/IO/MeshImporter.cs @@ -39,19 +39,37 @@ namespace UniGLTF string m_name; public string name => m_name; - public readonly List positions = new List(); - public readonly List normals = new List(); + readonly List m_positions = new List(); + public List Positions => m_positions; + + readonly List m_normals = new List(); + public List Normals => m_normals; [Obsolete] - public readonly List tangents = new List(); + readonly List m_tangents = new List(); + [Obsolete] + public List Tangetns => m_tangents; - public readonly List uv = new List(); - public readonly List uv2 = new List(); - public readonly List colors = new List(); - public readonly List boneWeights = new List(); - public readonly List subMeshes = new List(); - public readonly List materialIndices = new List(); - public readonly List blendShapes = new List(); + readonly List m_uv = new List(); + public List UV => m_uv; + + readonly List m_uv2 = new List(); + public List UV2 => m_uv2; + + readonly List m_colors = new List(); + public List Colors => m_colors; + + readonly List m_boneWeights = new List(); + public List BoneWeights => m_boneWeights; + + readonly List m_subMeshes = new List(); + public List SubMeshes => m_subMeshes; + + readonly List m_materialIndices = new List(); + public List MaterialIndices => m_materialIndices; + + readonly List m_blendShapes = new List(); + public List BlendShapes => m_blendShapes; public MeshContext(string name, int meshIndex) { @@ -62,6 +80,178 @@ namespace UniGLTF m_name = name; } + void CheckHasSameMorphTargetAttributes(glTFMesh gltfMesh) + { + var targets = gltfMesh.primitives[0].targets; + for (int i = 1; i < gltfMesh.primitives.Count; ++i) + { + if (!gltfMesh.primitives[i].targets.SequenceEqual(targets)) + { + // + // 各 primitive の morphTarget の内容が違うことは許容しない + // + throw new NotImplementedException(string.Format("different targets: {0} with {1}", + gltfMesh.primitives[i], + targets)); + } + } + } + + void FillZero(IList list) + { + if (list.Count != m_positions.Count) + { + throw new NotImplementedException(); + } + } + + /// + /// 各 primitive の attribute の要素が同じでない。=> uv が有るものと無いものが混在するなど + /// glTF 的にはありうる。 + /// + /// primitive を独立した(Independent) Mesh として扱いこれを連結する。 + /// + /// + /// + /// + public void ImportMeshIndependentVertexBuffer(ImporterContext ctx, glTFMesh gltfMesh) + { + CheckHasSameMorphTargetAttributes(gltfMesh); + + foreach (var prim in gltfMesh.primitives) + { + var indexOffset = m_positions.Count; + var indexBuffer = prim.indices; + + // position は必ずある + var positionCount = m_positions.Count; + m_positions.AddRange(ctx.GLTF.GetArrayFromAccessor(prim.attributes.POSITION).Select(x => x.ReverseZ())); + positionCount = m_positions.Count - positionCount; + + // normal + if (prim.attributes.NORMAL != -1) + { + FillZero(m_normals); + m_normals.AddRange(ctx.GLTF.GetArrayFromAccessor(prim.attributes.NORMAL).Select(x => x.ReverseZ())); + } + +#if false + if (prim.attributes.TANGENT != -1) + { + FillZero(tangetns); + tangents.AddRange(ctx.GLTF.GetArrayFromAccessor(prim.attributes.TANGENT).Select(x => x.ReverseZ())); + } +#endif + + // uv + if (prim.attributes.TEXCOORD_0 != -1) + { + FillZero(m_uv); + if (ctx.IsGeneratedUniGLTFAndOlder(1, 16)) + { +#pragma warning disable 0612 + // backward compatibility + m_uv.AddRange(ctx.GLTF.GetArrayFromAccessor(prim.attributes.TEXCOORD_0).Select(x => x.ReverseY())); +#pragma warning restore 0612 + } + else + { + m_uv.AddRange(ctx.GLTF.GetArrayFromAccessor(prim.attributes.TEXCOORD_0).Select(x => x.ReverseUV())); + } + } + + // uv2 + if (prim.attributes.TEXCOORD_1 != -1) + { + FillZero(m_uv2); + m_uv2.AddRange(ctx.GLTF.GetArrayFromAccessor(prim.attributes.TEXCOORD_1).Select(x => x.ReverseUV())); + } + + // color + if (prim.attributes.COLOR_0 != -1) + { + FillZero(m_colors); + m_colors.AddRange(ctx.GLTF.GetArrayFromAccessor(prim.attributes.COLOR_0)); + } + + // skin + if (prim.attributes.JOINTS_0 != -1 && prim.attributes.WEIGHTS_0 != -1) + { + FillZero(m_boneWeights); + + 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; + + m_boneWeights.Add(bw); + } + } + + // blendshape + if (prim.targets != null && prim.targets.Count > 0) + { + for (int i = 0; i < prim.targets.Count; ++i) + { + //var name = string.Format("target{0}", i++); + var primTarget = prim.targets[i]; + var blendShape = new BlendShape(!string.IsNullOrEmpty(prim.extras.targetNames[i]) + ? prim.extras.targetNames[i] + : i.ToString()) + ; + if (primTarget.POSITION != -1) + { + FillZero(blendShape.Positions); + blendShape.Positions.AddRange( + ctx.GLTF.GetArrayFromAccessor(primTarget.POSITION).Select(x => x.ReverseZ()).ToArray()); + } + if (primTarget.NORMAL != -1) + { + FillZero(blendShape.Normals); + blendShape.Normals.AddRange( + ctx.GLTF.GetArrayFromAccessor(primTarget.NORMAL).Select(x => x.ReverseZ()).ToArray()); + } + if (primTarget.TANGENT != -1) + { + FillZero(blendShape.Tangents); + blendShape.Tangents.AddRange( + ctx.GLTF.GetArrayFromAccessor(primTarget.TANGENT).Select(x => x.ReverseZ()).ToArray()); + } + m_blendShapes.Add(blendShape); + } + } + + var indices = + (indexBuffer >= 0) + ? ctx.GLTF.GetIndices(indexBuffer) + : TriangleUtil.FlipTriangle(Enumerable.Range(0, m_positions.Count)).ToArray() // without index array + ; + for (int i = 0; i < indices.Length; ++i) + { + indices[i] += indexOffset; + } + + m_subMeshes.Add(indices); + + // material + m_materialIndices.Add(prim.material); + } + } + /// /// mesh.extras.targetNames が存在する => UniVRMでエクスポートしたものであると仮定 /// @@ -89,22 +279,22 @@ namespace UniGLTF for (var i = 0; i < targetNames.Count; i++) { var blendShape = new BlendShape(!string.IsNullOrEmpty(targetNames[i]) ? targetNames[i] : i.ToString()); - blendShapes.Add(blendShape); + m_blendShapes.Add(blendShape); } foreach (var prim in gltfMesh.primitives) { - var indexOffset = positions.Count; + var indexOffset = m_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; + var positionCount = m_positions.Count; + m_positions.AddRange(ctx.GLTF.GetArrayFromAccessor(prim.attributes.POSITION).Select(x => x.ReverseZ())); + positionCount = m_positions.Count - positionCount; // normal if (prim.attributes.NORMAL != -1) { - normals.AddRange(ctx.GLTF.GetArrayFromAccessor(prim.attributes.NORMAL).Select(x => x.ReverseZ())); + m_normals.AddRange(ctx.GLTF.GetArrayFromAccessor(prim.attributes.NORMAL).Select(x => x.ReverseZ())); } #if false @@ -122,30 +312,30 @@ namespace UniGLTF { #pragma warning disable 0612 // backward compatibility - uv.AddRange(ctx.GLTF.GetArrayFromAccessor(prim.attributes.TEXCOORD_0).Select(x => x.ReverseY())); + m_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())); + m_uv.AddRange(ctx.GLTF.GetArrayFromAccessor(prim.attributes.TEXCOORD_0).Select(x => x.ReverseUV())); } } else { // for inconsistent attributes in primitives - uv.AddRange(new Vector2[positionCount]); + m_uv.AddRange(new Vector2[positionCount]); } // uv1 if (prim.attributes.TEXCOORD_1 != -1) { - uv2.AddRange(ctx.GLTF.GetArrayFromAccessor(prim.attributes.TEXCOORD_1).Select(x => x.ReverseUV())); + m_uv2.AddRange(ctx.GLTF.GetArrayFromAccessor(prim.attributes.TEXCOORD_1).Select(x => x.ReverseUV())); } // color if (prim.attributes.COLOR_0 != -1) { - colors.AddRange(ctx.GLTF.GetArrayFromAccessor(prim.attributes.COLOR_0)); + m_colors.AddRange(ctx.GLTF.GetArrayFromAccessor(prim.attributes.COLOR_0)); } // skin @@ -170,7 +360,7 @@ namespace UniGLTF bw.boneIndex3 = joints0[j].w; bw.weight3 = weights0[j].w; - boneWeights.Add(bw); + m_boneWeights.Add(bw); } } @@ -182,17 +372,17 @@ namespace UniGLTF var primTarget = prim.targets[i]; if (primTarget.POSITION != -1) { - blendShapes[i].Positions.AddRange( + m_blendShapes[i].Positions.AddRange( ctx.GLTF.GetArrayFromAccessor(primTarget.POSITION).Select(x => x.ReverseZ()).ToArray()); } if (primTarget.NORMAL != -1) { - blendShapes[i].Normals.AddRange( + m_blendShapes[i].Normals.AddRange( ctx.GLTF.GetArrayFromAccessor(primTarget.NORMAL).Select(x => x.ReverseZ()).ToArray()); } if (primTarget.TANGENT != -1) { - blendShapes[i].Tangents.AddRange( + m_blendShapes[i].Tangents.AddRange( ctx.GLTF.GetArrayFromAccessor(primTarget.TANGENT).Select(x => x.ReverseZ()).ToArray()); } } @@ -201,184 +391,32 @@ namespace UniGLTF var indices = (indexBuffer >= 0) ? ctx.GLTF.GetIndices(indexBuffer) - : TriangleUtil.FlipTriangle(Enumerable.Range(0, positions.Count)).ToArray() // without index array + : TriangleUtil.FlipTriangle(Enumerable.Range(0, m_positions.Count)).ToArray() // without index array ; for (int i = 0; i < indices.Length; ++i) { indices[i] += indexOffset; } - subMeshes.Add(indices); + m_subMeshes.Add(indices); // material - materialIndices.Add(prim.material); + m_materialIndices.Add(prim.material); } } - /// - /// 各 primitive の attribute の要素が同じでない。=> uv が有るものと無いものが混在するなど - /// glTF 的にはありうる。 - /// - /// primitive を独立した(Independent) Mesh として扱いこれを連結する。 - /// - /// - /// - /// - public void ImportMeshIndependentVertexBuffer(ImporterContext ctx, glTFMesh gltfMesh) - { - var targets = gltfMesh.primitives[0].targets; - for (int i = 1; i < gltfMesh.primitives.Count; ++i) - { - if (!gltfMesh.primitives[i].targets.SequenceEqual(targets)) - { - // - // 各 primitive の morphTarget の内容が違うことは許容しない - // - throw new NotImplementedException(string.Format("different targets: {0} with {1}", - gltfMesh.primitives[i], - targets)); - } - } - - 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 false - if (prim.attributes.TANGENT != -1) - { - tangents.AddRange(ctx.GLTF.GetArrayFromAccessor(prim.attributes.TANGENT).Select(x => x.ReverseZ())); - } -#endif - - // 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]); - } - - // uv2 - if (prim.attributes.TEXCOORD_1 != -1) - { - uv2.AddRange(ctx.GLTF.GetArrayFromAccessor(prim.attributes.TEXCOORD_1).Select(x => x.ReverseUV())); - } - - // 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; - - boneWeights.Add(bw); - } - } - - // blendshape - if (prim.targets != null && prim.targets.Count > 0) - { - for (int i = 0; i < prim.targets.Count; ++i) - { - //var name = string.Format("target{0}", i++); - var primTarget = prim.targets[i]; - var blendShape = new BlendShape(!string.IsNullOrEmpty(prim.extras.targetNames[i]) - ? prim.extras.targetNames[i] - : i.ToString()) - ; - if (primTarget.POSITION != -1) - { - blendShape.Positions.AddRange( - ctx.GLTF.GetArrayFromAccessor(primTarget.POSITION).Select(x => x.ReverseZ()).ToArray()); - } - if (primTarget.NORMAL != -1) - { - blendShape.Normals.AddRange( - ctx.GLTF.GetArrayFromAccessor(primTarget.NORMAL).Select(x => x.ReverseZ()).ToArray()); - } - if (primTarget.TANGENT != -1) - { - blendShape.Tangents.AddRange( - ctx.GLTF.GetArrayFromAccessor(primTarget.TANGENT).Select(x => x.ReverseZ()).ToArray()); - } - blendShapes.Add(blendShape); - } - } - - var indices = - (indexBuffer >= 0) - ? ctx.GLTF.GetIndices(indexBuffer) - : TriangleUtil.FlipTriangle(Enumerable.Range(0, positions.Count)).ToArray() // without index array - ; - for (int i = 0; i < indices.Length; ++i) - { - indices[i] += indexOffset; - } - - subMeshes.Add(indices); - - // material - materialIndices.Add(prim.material); - } - } // multiple submesh sharing same VertexBuffer public void ImportMeshSharingVertexBuffer(ImporterContext ctx, glTFMesh gltfMesh) { { var prim = gltfMesh.primitives.First(); - positions.AddRange(ctx.GLTF.GetArrayFromAccessor(prim.attributes.POSITION).SelectInplace(x => x.ReverseZ())); + m_positions.AddRange(ctx.GLTF.GetArrayFromAccessor(prim.attributes.POSITION).SelectInplace(x => x.ReverseZ())); // normal if (prim.attributes.NORMAL != -1) { - normals.AddRange(ctx.GLTF.GetArrayFromAccessor(prim.attributes.NORMAL).SelectInplace(x => x.ReverseZ())); + m_normals.AddRange(ctx.GLTF.GetArrayFromAccessor(prim.attributes.NORMAL).SelectInplace(x => x.ReverseZ())); } #if false @@ -396,19 +434,19 @@ namespace UniGLTF { #pragma warning disable 0612 // backward compatibility - uv.AddRange(ctx.GLTF.GetArrayFromAccessor(prim.attributes.TEXCOORD_0).SelectInplace(x => x.ReverseY())); + m_uv.AddRange(ctx.GLTF.GetArrayFromAccessor(prim.attributes.TEXCOORD_0).SelectInplace(x => x.ReverseY())); #pragma warning restore 0612 } else { - uv.AddRange(ctx.GLTF.GetArrayFromAccessor(prim.attributes.TEXCOORD_0).SelectInplace(x => x.ReverseUV())); + m_uv.AddRange(ctx.GLTF.GetArrayFromAccessor(prim.attributes.TEXCOORD_0).SelectInplace(x => x.ReverseUV())); } } // uv2 if (prim.attributes.TEXCOORD_1 != -1) { - uv2.AddRange(ctx.GLTF.GetArrayFromAccessor(prim.attributes.TEXCOORD_1).SelectInplace(x => x.ReverseUV())); + m_uv2.AddRange(ctx.GLTF.GetArrayFromAccessor(prim.attributes.TEXCOORD_1).SelectInplace(x => x.ReverseUV())); } // color @@ -417,17 +455,17 @@ namespace UniGLTF if (ctx.GLTF.accessors[prim.attributes.COLOR_0].TypeCount == 3) { var vec3Color = ctx.GLTF.GetArrayFromAccessor(prim.attributes.COLOR_0); - colors.AddRange(new Color[vec3Color.Length]); + m_colors.AddRange(new Color[vec3Color.Length]); for (int i = 0; i < vec3Color.Length; i++) { Vector3 color = vec3Color[i]; - colors[i] = new Color(color.x, color.y, color.z); + m_colors[i] = new Color(color.x, color.y, color.z); } } else if (ctx.GLTF.accessors[prim.attributes.COLOR_0].TypeCount == 4) { - colors.AddRange(ctx.GLTF.GetArrayFromAccessor(prim.attributes.COLOR_0)); + m_colors.AddRange(ctx.GLTF.GetArrayFromAccessor(prim.attributes.COLOR_0)); } else { @@ -461,14 +499,14 @@ namespace UniGLTF bw.boneIndex3 = joints0[j].w; bw.weight3 = weights0[j].w; - boneWeights.Add(bw); + m_boneWeights.Add(bw); } } // blendshape if (prim.targets != null && prim.targets.Count > 0) { - blendShapes.AddRange(prim.targets.Select((x, i) => new BlendShape( + m_blendShapes.AddRange(prim.targets.Select((x, i) => new BlendShape( i < prim.extras.targetNames.Count && !string.IsNullOrEmpty(prim.extras.targetNames[i]) ? prim.extras.targetNames[i] : i.ToString()))); @@ -476,7 +514,7 @@ namespace UniGLTF { //var name = string.Format("target{0}", i++); var primTarget = prim.targets[i]; - var blendShape = blendShapes[i]; + var blendShape = m_blendShapes[i]; if (primTarget.POSITION != -1) { @@ -501,16 +539,16 @@ namespace UniGLTF { if (prim.indices == -1) { - subMeshes.Add(TriangleUtil.FlipTriangle(Enumerable.Range(0, positions.Count)).ToArray()); + m_subMeshes.Add(TriangleUtil.FlipTriangle(Enumerable.Range(0, m_positions.Count)).ToArray()); } else { var indices = ctx.GLTF.GetIndices(prim.indices); - subMeshes.Add(indices); + m_subMeshes.Add(indices); } // material - materialIndices.Add(prim.material); + m_materialIndices.Add(prim.material); } } } @@ -553,335 +591,157 @@ namespace UniGLTF return meshContext; } - public static MeshWithMaterials BuildMesh(ImporterContext ctx, MeshImporter.MeshContext meshContext) + static (Mesh, bool) _BuildMesh(MeshImporter.MeshContext meshContext) { - if (!meshContext.materialIndices.Any()) + if (!meshContext.MaterialIndices.Any()) { - meshContext.materialIndices.Add(0); + // add default material + meshContext.MaterialIndices.Add(0); } //Debug.Log(prims.ToJson()); var mesh = new Mesh(); mesh.name = meshContext.name; - if (meshContext.positions.Count > UInt16.MaxValue) + if (meshContext.Positions.Count > UInt16.MaxValue) { -#if UNITY_2017_3_OR_NEWER mesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32; -#else - Debug.LogWarningFormat("vertices {0} exceed 65535. not implemented. Unity2017.3 supports large mesh", - meshContext.positions.Length); -#endif } - mesh.vertices = meshContext.positions.ToArray(); + mesh.vertices = meshContext.Positions.ToArray(); bool recalculateNormals = false; - if (meshContext.normals != null && meshContext.normals.Count > 0) + if (meshContext.Normals != null && meshContext.Normals.Count > 0) { - mesh.normals = meshContext.normals.ToArray(); + mesh.normals = meshContext.Normals.ToArray(); } else { recalculateNormals = true; } - if (meshContext.uv != null && meshContext.uv.Count == mesh.vertexCount) + if (meshContext.UV.Count == mesh.vertexCount) { - mesh.uv = meshContext.uv.ToArray(); + mesh.uv = meshContext.UV.ToArray(); } - if (meshContext.uv2 != null && meshContext.uv2.Count == mesh.vertexCount) + if (meshContext.UV2.Count == mesh.vertexCount) { - mesh.uv2 = meshContext.uv2.ToArray(); + mesh.uv2 = meshContext.UV2.ToArray(); } bool recalculateTangents = true; #if UNIGLTF_IMPORT_TANGENTS - if (meshContext.tangents != null && meshContext.tangents.Length > 0) + if (meshContext.Tangents.Length > 0) { - mesh.tangents = meshContext.tangents; + mesh.tangents = meshContext.Tangents.ToArray(); recalculateTangents = false; } #endif - if (meshContext.colors != null && meshContext.colors.Count == mesh.vertexCount) + if (meshContext.Colors.Count == mesh.vertexCount) { - mesh.colors = meshContext.colors.ToArray(); + mesh.colors = meshContext.Colors.ToArray(); } - if (meshContext.boneWeights != null && meshContext.boneWeights.Count > 0) + if (meshContext.BoneWeights.Count > 0) { - mesh.boneWeights = meshContext.boneWeights.ToArray(); + mesh.boneWeights = meshContext.BoneWeights.ToArray(); } - mesh.subMeshCount = meshContext.subMeshes.Count; - for (int i = 0; i < meshContext.subMeshes.Count; ++i) + mesh.subMeshCount = meshContext.SubMeshes.Count; + for (int i = 0; i < meshContext.SubMeshes.Count; ++i) { - mesh.SetTriangles(meshContext.subMeshes[i], i); + mesh.SetTriangles(meshContext.SubMeshes[i], i); } if (recalculateNormals) { mesh.RecalculateNormals(); } + + return (mesh, recalculateTangents); + } + + static void BuildBlendShape(Mesh mesh, MeshContext meshContext, BlendShape blendShape, Vector3[] emptyVertices) + { + if (blendShape.Positions.Count > 0) + { + if (blendShape.Positions.Count == mesh.vertexCount) + { + mesh.AddBlendShapeFrame(blendShape.Name, FRAME_WEIGHT, + blendShape.Positions.ToArray(), + (meshContext.Normals.Count == mesh.vertexCount && blendShape.Normals.Count == blendShape.Positions.Count()) ? blendShape.Normals.ToArray() : null, + null + ); + } + else + { + Debug.LogWarningFormat("May be partial primitive has blendShape. Require separate mesh or extend blend shape, but not implemented: {0}", blendShape.Name); + } + } + else + { + // Debug.LogFormat("empty blendshape: {0}.{1}", mesh.name, blendShape.Name); + // add empty blend shape for keep blend shape index + mesh.AddBlendShapeFrame(blendShape.Name, FRAME_WEIGHT, + emptyVertices, + null, + null + ); + } + } + + public static MeshWithMaterials BuildMesh(ImporterContext ctx, MeshImporter.MeshContext meshContext) + { + var (mesh, recalculateTangents) = _BuildMesh(meshContext); + if (recalculateTangents) { -#if UNITY_5_6_OR_NEWER mesh.RecalculateTangents(); -#else - CalcTangents(mesh); -#endif } var result = new MeshWithMaterials { Mesh = mesh, - Materials = meshContext.materialIndices.Select(x => ctx.GetMaterial(x)).ToArray() + Materials = meshContext.MaterialIndices.Select(x => ctx.GetMaterial(x)).ToArray() }; - if (meshContext.blendShapes != null) + if (meshContext.BlendShapes.Count > 0) { - Vector3[] emptyVertices = null; - foreach (var blendShape in meshContext.blendShapes) + var emptyVertices = new Vector3[mesh.vertexCount]; + foreach (var blendShape in meshContext.BlendShapes) { - if (blendShape.Positions.Count > 0) - { - if (blendShape.Positions.Count == mesh.vertexCount) - { - mesh.AddBlendShapeFrame(blendShape.Name, FRAME_WEIGHT, - blendShape.Positions.ToArray(), - (meshContext.normals != null && meshContext.normals.Count == mesh.vertexCount && blendShape.Normals.Count() == blendShape.Positions.Count()) ? blendShape.Normals.ToArray() : null, - null - ); - } - else - { - Debug.LogWarningFormat("May be partial primitive has blendShape. Require separate mesh or extend blend shape, but not implemented: {0}", blendShape.Name); - } - } - else - { - if (emptyVertices == null) - { - emptyVertices = new Vector3[mesh.vertexCount]; - } - // Debug.LogFormat("empty blendshape: {0}.{1}", mesh.name, blendShape.Name); - // add empty blend shape for keep blend shape index - mesh.AddBlendShapeFrame(blendShape.Name, FRAME_WEIGHT, - emptyVertices, - null, - null - ); - } + BuildBlendShape(mesh, meshContext, blendShape, emptyVertices); } } - return result; } public static IEnumerator BuildMeshCoroutine(ImporterContext ctx, MeshImporter.MeshContext meshContext) { - if (!meshContext.materialIndices.Any()) - { - meshContext.materialIndices.Add(0); - } + var (mesh, recalculateTangents) = _BuildMesh(meshContext); - var mesh = new Mesh(); - mesh.name = meshContext.name; - - if (meshContext.positions.Count > UInt16.MaxValue) - { -#if UNITY_2017_3_OR_NEWER - mesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32; -#else - Debug.LogWarningFormat("vertices {0} exceed 65535. not implemented. Unity2017.3 supports large mesh", - meshContext.positions.Length); -#endif - } - - - mesh.vertices = meshContext.positions.ToArray(); - bool recalculateNormals = false; - if (meshContext.normals != null && meshContext.normals.Count == mesh.vertexCount) - { - - mesh.normals = meshContext.normals.ToArray(); - } - else - { - recalculateNormals = true; - } - - if (meshContext.uv != null && meshContext.uv.Count == mesh.vertexCount) - { - - mesh.uv = meshContext.uv.ToArray(); - } - - bool recalculateTangents = true; -#if UNIGLTF_IMPORT_TANGENTS - if (meshContext.tangents != null && meshContext.tangents.Count == mesh.vertexCount) - { - mesh.tangents = meshContext.tangents.ToArray(); - recalculateTangents = false; - } -#endif - - if (meshContext.colors != null && meshContext.colors.Count == mesh.vertexCount) - { - mesh.colors = meshContext.colors.ToArray(); - } - - if (meshContext.boneWeights != null && meshContext.boneWeights.Count == mesh.vertexCount) - { - mesh.boneWeights = meshContext.boneWeights.ToArray(); - } - - mesh.subMeshCount = meshContext.subMeshes.Count; - for (int i = 0; i < meshContext.subMeshes.Count; ++i) - { - mesh.SetTriangles(meshContext.subMeshes[i], i); - } - - if (recalculateNormals) - { - mesh.RecalculateNormals(); - } if (recalculateTangents) { -#if UNITY_5_6_OR_NEWER yield return null; mesh.RecalculateTangents(); yield return null; -#else - CalcTangents(mesh); -#endif } var result = new MeshWithMaterials { Mesh = mesh, - Materials = meshContext.materialIndices.Select(x => ctx.GetMaterial(x)).ToArray() + Materials = meshContext.MaterialIndices.Select(x => ctx.GetMaterial(x)).ToArray() }; yield return null; - if (meshContext.blendShapes != null) + if (meshContext.BlendShapes.Count > 0) { - Vector3[] emptyVertices = null; - - foreach (var blendShape in meshContext.blendShapes) + var emptyVertices = new Vector3[mesh.vertexCount]; + foreach (var blendShape in meshContext.BlendShapes) { - if (blendShape.Positions.Count > 0) - { - if (blendShape.Positions.Count == mesh.vertexCount) - { - mesh.AddBlendShapeFrame(blendShape.Name, FRAME_WEIGHT, - blendShape.Positions.ToArray(), - (meshContext.normals != null && meshContext.normals.Count == mesh.vertexCount && blendShape.Normals.Count() == blendShape.Positions.Count()) ? blendShape.Normals.ToArray() : null, - null - ); - yield return null; - } - else - { - Debug.LogWarningFormat("May be partial primitive has blendShape. Require separate mesh or extend blend shape, but not implemented: {0}", blendShape.Name); - } - } - else - { - if (emptyVertices == null) - { - emptyVertices = new Vector3[mesh.vertexCount]; - } - // Debug.LogFormat("empty blendshape: {0}.{1}", mesh.name, blendShape.Name); - // add empty blend shape for keep blend shape index - mesh.AddBlendShapeFrame(blendShape.Name, FRAME_WEIGHT, - emptyVertices, - null, - null - ); - yield return null; - } + BuildBlendShape(mesh, meshContext, blendShape, emptyVertices); } } yield return result; } - - /// - /// Meshの法線を元にタンジェントを計算する。 - /// - /// メッシュ - /// タンジェント - public static void CalcTangents(Mesh mesh) - { - int vertexCount = mesh.vertexCount; - Vector3[] vertices = mesh.vertices; - Vector3[] normals = mesh.normals; - Vector2[] texcoords = mesh.uv; - int[] triangles = mesh.triangles; - int triangleCount = triangles.Length / 3; - - Vector4[] tangents = new Vector4[vertexCount]; - Vector3[] tan1 = new Vector3[vertexCount]; - Vector3[] tan2 = new Vector3[vertexCount]; - - int tri = 0; - - for (int i = 0; i < (triangleCount); i++) - { - int i1 = triangles[tri]; - int i2 = triangles[tri + 1]; - int i3 = triangles[tri + 2]; - - Vector3 v1 = vertices[i1]; - Vector3 v2 = vertices[i2]; - Vector3 v3 = vertices[i3]; - - Vector2 w1 = texcoords[i1]; - Vector2 w2 = texcoords[i2]; - Vector2 w3 = texcoords[i3]; - - float x1 = v2.x - v1.x; - float x2 = v3.x - v1.x; - float y1 = v2.y - v1.y; - float y2 = v3.y - v1.y; - float z1 = v2.z - v1.z; - float z2 = v3.z - v1.z; - - float s1 = w2.x - w1.x; - float s2 = w3.x - w1.x; - float t1 = w2.y - w1.y; - float t2 = w3.y - w1.y; - - float r = 1.0f / (s1 * t2 - s2 * t1); - Vector3 sdir = new Vector3((t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r, (t2 * z1 - t1 * z2) * r); - Vector3 tdir = new Vector3((s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r, (s1 * z2 - s2 * z1) * r); - - tan1[i1] += sdir; - tan1[i2] += sdir; - tan1[i3] += sdir; - - tan2[i1] += tdir; - tan2[i2] += tdir; - tan2[i3] += tdir; - - tri += 3; - } - - for (int i = 0; i < (vertexCount); i++) - { - Vector3 n = normals[i]; - Vector3 t = tan1[i]; - - // Gram-Schmidt orthogonalize - Vector3.OrthoNormalize(ref n, ref t); - tangents[i].x = t.x; - tangents[i].y = t.y; - tangents[i].z = t.z; - - // Calculate handedness - tangents[i].w = (Vector3.Dot(Vector3.Cross(n, t), tan2[i]) < 0.0f) ? -1.0f : 1.0f; - } - - mesh.tangents = tangents; - } } } From 0bc6d1f222dafe0fe648eabb42b2124f3337cbda Mon Sep 17 00:00:00 2001 From: ousttrue Date: Fri, 13 Nov 2020 19:37:48 +0900 Subject: [PATCH 3/4] fix ImportMeshSharingMorphTarget bug vertex buffer length multiply submesh count --- Assets/VRM/UniGLTF/Scripts/IO/MeshImporter.cs | 269 +++++------------- 1 file changed, 68 insertions(+), 201 deletions(-) diff --git a/Assets/VRM/UniGLTF/Scripts/IO/MeshImporter.cs b/Assets/VRM/UniGLTF/Scripts/IO/MeshImporter.cs index e8a7a77a9..ed1538029 100644 --- a/Assets/VRM/UniGLTF/Scripts/IO/MeshImporter.cs +++ b/Assets/VRM/UniGLTF/Scripts/IO/MeshImporter.cs @@ -80,23 +80,6 @@ namespace UniGLTF m_name = name; } - void CheckHasSameMorphTargetAttributes(glTFMesh gltfMesh) - { - var targets = gltfMesh.primitives[0].targets; - for (int i = 1; i < gltfMesh.primitives.Count; ++i) - { - if (!gltfMesh.primitives[i].targets.SequenceEqual(targets)) - { - // - // 各 primitive の morphTarget の内容が違うことは許容しない - // - throw new NotImplementedException(string.Format("different targets: {0} with {1}", - gltfMesh.primitives[i], - targets)); - } - } - } - void FillZero(IList list) { if (list.Count != m_positions.Count) @@ -116,8 +99,6 @@ namespace UniGLTF /// public void ImportMeshIndependentVertexBuffer(ImporterContext ctx, glTFMesh gltfMesh) { - CheckHasSameMorphTargetAttributes(gltfMesh); - foreach (var prim in gltfMesh.primitives) { var indexOffset = m_positions.Count; @@ -207,12 +188,8 @@ namespace UniGLTF { for (int i = 0; i < prim.targets.Count; ++i) { - //var name = string.Format("target{0}", i++); var primTarget = prim.targets[i]; - var blendShape = new BlendShape(!string.IsNullOrEmpty(prim.extras.targetNames[i]) - ? prim.extras.targetNames[i] - : i.ToString()) - ; + var blendShape = new BlendShape(i.ToString()); if (primTarget.POSITION != -1) { FillZero(blendShape.Positions); @@ -253,163 +230,17 @@ namespace UniGLTF } /// - /// mesh.extras.targetNames が存在する => UniVRMでエクスポートしたものであると仮定 /// - /// * 各primitiveが同じ attribute を共有している - /// * 各primitiveが同じ targets を共有している - /// * 各primitiveは indices が異なる(submesh) - /// - /// を仮定して Mesh をロードする。 + /// 各primitiveが同じ attribute を共有している場合専用のローダー。 + /// /// /// /// /// - public void ImportMeshSharingMorphTarget(ImporterContext ctx, glTFMesh gltfMesh) - { - // 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()); - m_blendShapes.Add(blendShape); - } - - foreach (var prim in gltfMesh.primitives) - { - var indexOffset = m_positions.Count; - var indexBuffer = prim.indices; - - var positionCount = m_positions.Count; - m_positions.AddRange(ctx.GLTF.GetArrayFromAccessor(prim.attributes.POSITION).Select(x => x.ReverseZ())); - positionCount = m_positions.Count - positionCount; - - // normal - if (prim.attributes.NORMAL != -1) - { - m_normals.AddRange(ctx.GLTF.GetArrayFromAccessor(prim.attributes.NORMAL).Select(x => x.ReverseZ())); - } - -#if false - // tangent - if (prim.attributes.TANGENT != -1) - { - tangents.AddRange(ctx.GLTF.GetArrayFromAccessor(prim.attributes.TANGENT).Select(x => x.ReverseZ())); - } -#endif - - // uv - if (prim.attributes.TEXCOORD_0 != -1) - { - if (ctx.IsGeneratedUniGLTFAndOlder(1, 16)) - { -#pragma warning disable 0612 - // backward compatibility - m_uv.AddRange(ctx.GLTF.GetArrayFromAccessor(prim.attributes.TEXCOORD_0).Select(x => x.ReverseY())); -#pragma warning restore 0612 - } - else - { - m_uv.AddRange(ctx.GLTF.GetArrayFromAccessor(prim.attributes.TEXCOORD_0).Select(x => x.ReverseUV())); - } - } - else - { - // for inconsistent attributes in primitives - m_uv.AddRange(new Vector2[positionCount]); - } - - // uv1 - if (prim.attributes.TEXCOORD_1 != -1) - { - m_uv2.AddRange(ctx.GLTF.GetArrayFromAccessor(prim.attributes.TEXCOORD_1).Select(x => x.ReverseUV())); - } - - // color - if (prim.attributes.COLOR_0 != -1) - { - m_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; - - m_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) - { - m_blendShapes[i].Positions.AddRange( - ctx.GLTF.GetArrayFromAccessor(primTarget.POSITION).Select(x => x.ReverseZ()).ToArray()); - } - if (primTarget.NORMAL != -1) - { - m_blendShapes[i].Normals.AddRange( - ctx.GLTF.GetArrayFromAccessor(primTarget.NORMAL).Select(x => x.ReverseZ()).ToArray()); - } - if (primTarget.TANGENT != -1) - { - m_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, m_positions.Count)).ToArray() // without index array - ; - for (int i = 0; i < indices.Length; ++i) - { - indices[i] += indexOffset; - } - - m_subMeshes.Add(indices); - - // material - m_materialIndices.Add(prim.material); - } - } - - - // multiple submesh sharing same VertexBuffer public void ImportMeshSharingVertexBuffer(ImporterContext ctx, glTFMesh gltfMesh) { { + // 同じVertexBufferを共有しているので先頭のモノを使う var prim = gltfMesh.primitives.First(); m_positions.AddRange(ctx.GLTF.GetArrayFromAccessor(prim.attributes.POSITION).SelectInplace(x => x.ReverseZ())); @@ -506,10 +337,7 @@ namespace UniGLTF // blendshape if (prim.targets != null && prim.targets.Count > 0) { - m_blendShapes.AddRange(prim.targets.Select((x, i) => new BlendShape( - i < prim.extras.targetNames.Count && !string.IsNullOrEmpty(prim.extras.targetNames[i]) - ? prim.extras.targetNames[i] - : i.ToString()))); + m_blendShapes.AddRange(prim.targets.Select((x, i) => new BlendShape(i.ToString()))); for (int i = 0; i < prim.targets.Count; ++i) { //var name = string.Format("target{0}", i++); @@ -551,43 +379,82 @@ namespace UniGLTF m_materialIndices.Add(prim.material); } } + + public void RenameBlendShape(glTFMesh gltfMesh) + { + if (gltfMesh.extras != null && gltfMesh.extras.targetNames != null) + { + 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++) + { + BlendShapes[i].Name = targetNames[i]; + } + return; + } + + var prim = gltfMesh.primitives[0]; + { + if (prim.extras != null && prim.extras.targetNames != null) + { + var targetNames = prim.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++) + { + BlendShapes[i].Name = targetNames[i]; + } + } + } + } + } + + static bool HasSharedVertexBuffer(glTFMesh gltfMesh) + { + glTFAttributes lastAttributes = null; + var sharedAttributes = true; + foreach (var prim in gltfMesh.primitives) + { + if (lastAttributes != null && !prim.attributes.Equals(lastAttributes)) + { + sharedAttributes = false; + break; + } + + lastAttributes = prim.attributes; + } + return sharedAttributes; } public MeshContext ReadMesh(ImporterContext ctx, int meshIndex) { var gltfMesh = ctx.GLTF.meshes[meshIndex]; - bool sharedMorphTarget = gltfMesh.extras != null && gltfMesh.extras.targetNames.Count > 0; var meshContext = new MeshContext(gltfMesh.name, meshIndex); - if (sharedMorphTarget) + if (HasSharedVertexBuffer(gltfMesh)) { - meshContext.ImportMeshSharingMorphTarget(ctx, gltfMesh); + meshContext.ImportMeshSharingVertexBuffer(ctx, gltfMesh); } else { - glTFAttributes lastAttributes = null; - var sharedAttributes = true; - foreach (var prim in gltfMesh.primitives) - { - if (lastAttributes != null && !prim.attributes.Equals(lastAttributes)) - { - sharedAttributes = false; - break; - } - - lastAttributes = prim.attributes; - } - - if (sharedAttributes) - { - meshContext.ImportMeshSharingVertexBuffer(ctx, gltfMesh); - } - else - { - meshContext.ImportMeshIndependentVertexBuffer(ctx, gltfMesh); - } + meshContext.ImportMeshIndependentVertexBuffer(ctx, gltfMesh); } + meshContext.RenameBlendShape(gltfMesh); + return meshContext; } From abe2b82ddc30793136381cbebb89969a03de093d Mon Sep 17 00:00:00 2001 From: ousttrue Date: Fri, 13 Nov 2020 20:18:08 +0900 Subject: [PATCH 4/4] =?UTF-8?q?=E6=9C=AA=E4=BD=BF=E7=94=A8=E3=81=AE?= =?UTF-8?q?=E9=A0=82=E7=82=B9=E3=81=8C=E5=BE=8C=E3=82=8D=E3=81=AB=E3=81=82?= =?UTF-8?q?=E3=82=8B=E5=A0=B4=E5=90=88=E3=81=AB=E5=89=8A=E9=99=A4=E3=81=99?= =?UTF-8?q?=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #610 対策 --- Assets/VRM/UniGLTF/Scripts/IO/MeshImporter.cs | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/Assets/VRM/UniGLTF/Scripts/IO/MeshImporter.cs b/Assets/VRM/UniGLTF/Scripts/IO/MeshImporter.cs index ed1538029..09104286b 100644 --- a/Assets/VRM/UniGLTF/Scripts/IO/MeshImporter.cs +++ b/Assets/VRM/UniGLTF/Scripts/IO/MeshImporter.cs @@ -420,6 +420,43 @@ namespace UniGLTF } } } + + static void Truncate(List list, int maxIndex) + { + if (list == null) + { + return; + } + var count = maxIndex + 1; + if (list.Count > count) + { + // Debug.LogWarning($"remove {count} to {list.Count}"); + list.RemoveRange(count, list.Count - count); + } + } + + // + // https://github.com/vrm-c/UniVRM/issues/610 + // + // VertexBuffer の後ろに未使用頂点がある場合に削除する + // + public void DropUnusedVertices() + { + var maxIndex = m_subMeshes.SelectMany(x => x).Max(); + Truncate(m_positions, maxIndex); + Truncate(m_normals, maxIndex); + Truncate(m_uv, maxIndex); + Truncate(m_uv2, maxIndex); + Truncate(m_colors, maxIndex); + Truncate(m_boneWeights, maxIndex); + Truncate(m_tangents, maxIndex); + foreach (var blendshape in m_blendShapes) + { + Truncate(blendshape.Positions, maxIndex); + Truncate(blendshape.Normals, maxIndex); + Truncate(blendshape.Tangents, maxIndex); + } + } } static bool HasSharedVertexBuffer(glTFMesh gltfMesh) @@ -455,6 +492,8 @@ namespace UniGLTF meshContext.RenameBlendShape(gltfMesh); + meshContext.DropUnusedVertices(); + return meshContext; }