From 85bfe4bcd15c7c5081b858ab9fbe347c51ddd24e Mon Sep 17 00:00:00 2001 From: ousttrue Date: Mon, 24 Jun 2024 17:39:27 +0900 Subject: [PATCH] fix blendshape bake. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 簡単になるように処理順をみなおし。 var mesh = src.sharedMesh.Copy(false, ".baked"); src.BakeMesh(mesh); CopyBlendShapes(src, mesh); var m = Matrix4x4.TRS(Vector3.zero, src.transform.rotation, Vector3.one); mesh.ApplyMatrixAlsoBlendShapes(m); // 最後の一回だけまとめて matrix を適用する --- .../Runtime/MeshUtility/MeshExtensions.cs | 68 ++++++++- .../Runtime/MeshUtility/MeshFreezer.cs | 136 +++++++++--------- 2 files changed, 138 insertions(+), 66 deletions(-) diff --git a/Assets/UniGLTF/Runtime/MeshUtility/MeshExtensions.cs b/Assets/UniGLTF/Runtime/MeshUtility/MeshExtensions.cs index 736a63645..b22e263db 100644 --- a/Assets/UniGLTF/Runtime/MeshUtility/MeshExtensions.cs +++ b/Assets/UniGLTF/Runtime/MeshUtility/MeshExtensions.cs @@ -1,6 +1,8 @@ using UnityEngine; using System.Linq; using VRMShaders; +using System; +using System.Collections.Generic; namespace UniGLTF.MeshUtility @@ -23,10 +25,10 @@ namespace UniGLTF.MeshUtility return null; } - public static Mesh Copy(this Mesh src, bool copyBlendShape) + public static Mesh Copy(this Mesh src, bool copyBlendShape, string nameSuffix = "(copy)") { var dst = new Mesh(); - dst.name = src.name + "(copy)"; + dst.name = src.name + nameSuffix; #if UNITY_2017_3_OR_NEWER dst.indexFormat = src.indexFormat; #endif @@ -108,5 +110,67 @@ namespace UniGLTF.MeshUtility }).ToArray(); } } + + class BlendShape + { + public readonly string Name; + public readonly float FrameWeight; + public readonly Vector3[] Vertices; + public readonly Vector3[] Normals; + public readonly Vector3[] Tangents; + public BlendShape(string name, float frameweight, + IEnumerable vertices, + IEnumerable normals, + IEnumerable tangents) + { + Name = name; + FrameWeight = frameweight; + Vertices = vertices.ToArray(); + Normals = normals.ToArray(); + Tangents = tangents.ToArray(); + } + + public static BlendShape FromMesh(Mesh mesh, int i, Matrix4x4 m) + { + var blendShapePositions = new Vector3[mesh.vertexCount]; + var blendShapeNormals = new Vector3[mesh.vertexCount]; + var blendShapeTangents = new Vector3[mesh.vertexCount]; + mesh.GetBlendShapeFrameVertices(i, 0, blendShapePositions, blendShapeNormals, blendShapeTangents); + return new BlendShape( + mesh.GetBlendShapeName(i), mesh.GetBlendShapeFrameWeight(i, 0), + blendShapePositions.Select(x => m.MultiplyPoint(x)), + blendShapeNormals.Select(x => m.MultiplyPoint(x)), + blendShapeTangents.Select(x => m.MultiplyPoint(x))); + } + } + + public static void ApplyMatrixAlsoBlendShapes(this Mesh src, Matrix4x4 m) + { + src.vertices = src.vertices.Select(x => m.MultiplyPoint(x)).ToArray(); + if (src.normals != null && src.normals.Length > 0) + { + src.normals = src.normals.Select(x => m.MultiplyVector(x.normalized)).ToArray(); + } + if (src.tangents != null && src.tangents.Length > 0) + { + src.tangents = src.tangents.Select(x => + { + var t = m.MultiplyVector((Vector3)x); + return new Vector4(t.x, t.y, t.z, x.w); + }).ToArray(); + } + + var blendshapes = new List(); + for (int i = 0; i < src.blendShapeCount; ++i) + { + blendshapes.Add(BlendShape.FromMesh(src, i, m)); + } + src.ClearBlendShapes(); + foreach (var blendshape in blendshapes) + { + src.AddBlendShapeFrame(blendshape.Name, blendshape.FrameWeight, + blendshape.Vertices, null, null); + } + } } } diff --git a/Assets/UniGLTF/Runtime/MeshUtility/MeshFreezer.cs b/Assets/UniGLTF/Runtime/MeshUtility/MeshFreezer.cs index 3bd3c45e9..276826c41 100644 --- a/Assets/UniGLTF/Runtime/MeshUtility/MeshFreezer.cs +++ b/Assets/UniGLTF/Runtime/MeshUtility/MeshFreezer.cs @@ -140,62 +140,67 @@ namespace UniGLTF.MeshUtility return default; } - var srcMesh = src.sharedMesh; - var originalSrcMesh = srcMesh; - - var hasBoneWeight = src.bones != null && src.bones.Length > 0; - if (!hasBoneWeight) + if (!HasBoneWeight(src)) { // Before bake, bind no weight bones - - srcMesh = srcMesh.Copy(true); - srcMesh.ApplyRotationAndScale(src.transform.localToWorldMatrix, false); - - var bw = new BoneWeight - { - boneIndex0 = 0, - boneIndex1 = 0, - boneIndex2 = 0, - boneIndex3 = 0, - weight0 = 1.0f, - weight1 = 0.0f, - weight2 = 0.0f, - weight3 = 0.0f, - }; - srcMesh.boneWeights = Enumerable.Range(0, srcMesh.vertexCount).Select(x => bw).ToArray(); - src.bones = new[] { src.rootBone ?? src.transform }; - srcMesh.bindposes = src.bones.Select(x => x.worldToLocalMatrix).ToArray(); - - src.sharedMesh = srcMesh; + // + // blendshape があって bone が無い SkinnedMeshRenderer と思われる。 + // SkinnedMeshRenderer.transform に対する boneweight を付与する。 + AssignSingleBoneWeight(src); } // BakeMesh - var mesh = srcMesh.Copy(false); - mesh.name = srcMesh.name + ".baked"; + var mesh = src.sharedMesh.Copy(false, ".baked"); src.BakeMesh(mesh); + CopyBlendShapes(src, mesh); - mesh.boneWeights = srcMesh.boneWeights; - - { - // apply SkinnedMesh.transform rotation - var m = Matrix4x4.TRS(Vector3.zero, src.transform.rotation, Vector3.one); - mesh.ApplyMatrix(m); - } + // apply SkinnedMesh.transform rotation + var m = Matrix4x4.TRS(Vector3.zero, src.transform.rotation, Vector3.one); + mesh.ApplyMatrixAlsoBlendShapes(m); // // BlendShapes // - { - var m = src.localToWorldMatrix; // include scaling - m.SetColumn(3, new Vector4(0, 0, 0, 1)); // no translation - CopyBlendShapes(src, srcMesh, mesh, m); - } + // { + // var m = src.localToWorldMatrix; // include scaling + // m.SetColumn(3, new Vector4(0, 0, 0, 1)); // no translation + // CopyBlendShapes(src, srcMesh, mesh, m); + // } return mesh; } - private static void CopyBlendShapes(SkinnedMeshRenderer src, Mesh srcMesh, Mesh mesh, Matrix4x4 m) + public static bool HasBoneWeight(SkinnedMeshRenderer src) { + return src.bones != null && src.bones.Length > 0; + } + + public static void AssignSingleBoneWeight(SkinnedMeshRenderer src) + { + var srcMesh = src.sharedMesh.Copy(true); + srcMesh.ApplyRotationAndScale(src.transform.localToWorldMatrix, false); + + var bw = new BoneWeight + { + boneIndex0 = 0, + boneIndex1 = 0, + boneIndex2 = 0, + boneIndex3 = 0, + weight0 = 1.0f, + weight1 = 0.0f, + weight2 = 0.0f, + weight3 = 0.0f, + }; + srcMesh.boneWeights = Enumerable.Range(0, srcMesh.vertexCount).Select(x => bw).ToArray(); + src.bones = new[] { src.rootBone ?? src.transform }; + srcMesh.bindposes = src.bones.Select(x => x.worldToLocalMatrix).ToArray(); + + src.sharedMesh = srcMesh; + } + + private static void CopyBlendShapes(SkinnedMeshRenderer src, Mesh mesh) + { + var srcMesh = src.sharedMesh; var blendShapeValues = new Dictionary(); for (int i = 0; i < srcMesh.blendShapeCount; i++) { @@ -258,28 +263,30 @@ namespace UniGLTF.MeshUtility for (int j = 0; j < vertices.Length; ++j) { - if (originalBlendShapePositions[j] == Vector3.zero) - { - vertices[j] = Vector3.zero; - } - else - { - vertices[j] = m.MultiplyPoint(vertices[j] - meshVertices[j]); - } + // if (originalBlendShapePositions[j] == Vector3.zero) + // { + // vertices[j] = Vector3.zero; + // } + // else + // { + // vertices[j] = m.MultiplyPoint(vertices[j] - meshVertices[j]); + // } + vertices[j] = vertices[j] - meshVertices[j]; } Vector3[] normals = blendShapeMesh.normals; for (int j = 0; j < normals.Length; ++j) { - if (originalBlendShapeNormals[j] == Vector3.zero) - { - normals[j] = Vector3.zero; + // if (originalBlendShapeNormals[j] == Vector3.zero) + // { + // normals[j] = Vector3.zero; - } - else - { - normals[j] = m.MultiplyVector(normals[j].normalized) - meshNormals[j]; - } + // } + // else + // { + // normals[j] = m.MultiplyVector(normals[j].normalized) - meshNormals[j]; + // } + normals[j] = normals[j] - meshNormals[j]; } Vector3[] tangents = blendShapeMesh.tangents.Select(x => (Vector3)x).ToArray(); @@ -287,14 +294,15 @@ namespace UniGLTF.MeshUtility { for (int j = 0; j < tangents.Length; ++j) { - if (originalBlendShapeTangents[j] == Vector3.zero) - { - tangents[j] = Vector3.zero; - } - else - { - tangents[j] = m.MultiplyVector(tangents[j]) - meshTangents[j]; - } + // if (originalBlendShapeTangents[j] == Vector3.zero) + // { + // tangents[j] = Vector3.zero; + // } + // else + // { + // tangents[j] = m.MultiplyVector(tangents[j]) - meshTangents[j]; + // } + tangents[j] = tangents[j] - meshTangents[j]; } }