diff --git a/Assets/UniGLTF/Runtime/MeshUtility/BoneNormalizer.cs b/Assets/UniGLTF/Runtime/MeshUtility/BoneNormalizer.cs index f9d5a2cfb..bfad06d94 100644 --- a/Assets/UniGLTF/Runtime/MeshUtility/BoneNormalizer.cs +++ b/Assets/UniGLTF/Runtime/MeshUtility/BoneNormalizer.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using UniGLTF.Utils; using UnityEngine; @@ -8,97 +9,20 @@ namespace UniGLTF.MeshUtility { public static class BoneNormalizer { - public static (GameObject, Dictionary) CreateNormalizedHierarchy(GameObject go, - bool removeScaling = true, - bool removeRotation = true) + private static MeshAttachInfo CreateMeshInfo(Transform src) { - var boneMap = new Dictionary(); - var normalized = new GameObject(go.name + "(normalized)"); - normalized.transform.position = go.transform.position; - - if (removeScaling && removeRotation) - { - RemoveScaleAndRotationRecursive(go.transform, normalized.transform, boneMap); - } - else if (removeScaling) - { - RemoveScaleAndRotationRecursive(go.transform, normalized.transform, boneMap); - } - else if (removeRotation) - { - throw new NotImplementedException(); - } - else - { - throw new ArgumentNullException(); - } - - return (normalized, boneMap); - } - - static void RemoveScaleRecursive(Transform src, Transform dst, Dictionary boneMap) - { - boneMap[src] = dst; - - foreach (Transform child in src) - { - if (child.gameObject.activeSelf) - { - var dstChild = new GameObject(child.name); - dstChild.transform.SetParent(dst); - dstChild.transform.position = child.position; // copy world position - dstChild.transform.rotation = child.localToWorldMatrix.rotation; // copy world rotation - // scale is removed - RemoveScaleRecursive(child, dstChild.transform, boneMap); - } - } - } - - static void RemoveScaleAndRotationRecursive(Transform src, Transform dst, Dictionary boneMap) - { - boneMap[src] = dst; - - foreach (Transform child in src) - { - if (child.gameObject.activeSelf) - { - var dstChild = new GameObject(child.name); - dstChild.transform.SetParent(dst); - dstChild.transform.position = child.position; // copy world position - - RemoveScaleAndRotationRecursive(child, dstChild.transform, boneMap); - } - } - } - - public static MeshAttachInfo CreateMeshInfo(Transform src, Dictionary boneMap) - { - Transform dst; - if (!boneMap.TryGetValue(src, out dst)) - { - return default; - } - // SkinnedMeshRenderer var smr = src.GetComponent(); - var mesh = MeshFreezer.NormalizeSkinnedMesh( - smr, - boneMap); + var mesh = MeshFreezer.NormalizeSkinnedMesh(smr); if (mesh != null) { - var info = new MeshAttachInfo + return new MeshAttachInfo { Mesh = mesh, Materials = smr.sharedMaterials, + Bones = smr.bones, + RootBone = smr.rootBone, }; - if (smr.rootBone != null) - { - if (boneMap.TryGetValue(smr.rootBone, out Transform found)) - { - info.RootBone = found; - } - } - return info; } // MeshRenderer @@ -127,58 +51,68 @@ namespace UniGLTF.MeshUtility /// BlendShapeを0クリアするか否か。false の場合 BlendShape の現状を Bake する /// Avatarを作る関数 /// - public static (GameObject, Dictionary, Dictionary) NormalizeHierarchyFreezeMesh( + public static Dictionary NormalizeHierarchyFreezeMesh( GameObject go, bool removeScaling = true, bool removeRotation = true ) { - // - // 正規化されたヒエラルキーを作る - // - var (normalized, boneMap) = CreateNormalizedHierarchy(go, removeScaling, removeRotation); - // // 各メッシュから回転・スケールを取り除いてBinding行列を再計算する // var result = new Dictionary(); foreach (var src in go.transform.Traverse()) { - var info = CreateMeshInfo(src, boneMap); + var info = CreateMeshInfo(src); if (info != null) { result.Add(src, info); } } - return (normalized, boneMap, result); + return result; } - public static void WriteBackResult(GameObject go, GameObject normalized, Dictionary boneMap) + public static void Replace(GameObject go, Dictionary newMesh, + bool FreezeRotation, bool FreezeScaling) { - Func getSrc = dst => + var boneMap = go.transform.Traverse().ToDictionary(x => x, x => new EuclideanTransform(x.rotation, x.position)); + // Func getSrc = dst => + // { + // foreach (var (k, v) in boneMap) + // { + // if (v == dst) + // { + // return k; + // } + // } + // throw new NotImplementedException(); + // }; + + foreach (var (src, tr) in boneMap) { - foreach (var (k, v) in boneMap) + src.position = tr.Translation; + if (FreezeRotation) { - if (v == dst) - { - return k; - } + src.rotation = Quaternion.identity; } - throw new NotImplementedException(); - }; - foreach (var (src, dst) in boneMap) - { - src.localPosition = dst.localPosition; - src.localRotation = dst.localRotation; - src.localScale = dst.localScale; - var srcR = src.GetComponent(); - var dstR = dst.GetComponent(); - if (srcR != null && dstR != null) + else { - srcR.sharedMesh = dstR.sharedMesh; - srcR.bones = dstR.bones.Select(x => getSrc(x)).ToArray(); + src.rotation = tr.Rotation; + } + if (FreezeScaling) + { + src.localScale = Vector3.one; + } + else + { + throw new NotImplementedException(); + } + + if (newMesh.TryGetValue(src, out var info)) + { + info.ReplaceMesh(src.gameObject); } } } } -} +} \ No newline at end of file diff --git a/Assets/UniGLTF/Runtime/MeshUtility/GltfMeshUtility.cs b/Assets/UniGLTF/Runtime/MeshUtility/GltfMeshUtility.cs index d230b666e..2ebd9e15d 100644 --- a/Assets/UniGLTF/Runtime/MeshUtility/GltfMeshUtility.cs +++ b/Assets/UniGLTF/Runtime/MeshUtility/GltfMeshUtility.cs @@ -157,30 +157,17 @@ namespace UniGLTF.MeshUtility public virtual (List, List) Process(GameObject go) { - // TODO unpack prefab - - // 正規化されたヒエラルキーを作る if (FreezeBlendShape || FreezeRotation || FreezeScaling) { - var (normalized, boneMap, newMesh) = BoneNormalizer.NormalizeHierarchyFreezeMesh(go, + // MeshをBakeする + var newMesh = BoneNormalizer.NormalizeHierarchyFreezeMesh(go, removeScaling: FreezeScaling, removeRotation: FreezeRotation); - foreach (var (k, v) in newMesh) - { - v.AttachTo(k.gameObject); - } - - // write back normalized transform to boneMap - BoneNormalizer.WriteBackResult(go, normalized, boneMap); - if (Application.isPlaying) - { - GameObject.Destroy(normalized); - } - else - { - GameObject.DestroyImmediate(normalized); - } + // - ヒエラルキーから回転・拡縮を除去する + // - BakeされたMeshで置き換える + // - bindPoses を再計算する + BoneNormalizer.Replace(go, newMesh, FreezeRotation, FreezeScaling); } var copy = CopyMeshIntegrationGroups(); diff --git a/Assets/UniGLTF/Runtime/MeshUtility/MeshAttachInfo.cs b/Assets/UniGLTF/Runtime/MeshUtility/MeshAttachInfo.cs index 16b4f0fdf..6684777c4 100644 --- a/Assets/UniGLTF/Runtime/MeshUtility/MeshAttachInfo.cs +++ b/Assets/UniGLTF/Runtime/MeshUtility/MeshAttachInfo.cs @@ -9,14 +9,14 @@ namespace UniGLTF.MeshUtility public Material[] Materials; public Transform[] Bones; public Transform RootBone; - public void AttachTo(GameObject dst) + public void ReplaceMesh(GameObject dst) { if (Bones != null) { // recalc bindposes Mesh.bindposes = Bones.Select(x => x.worldToLocalMatrix * dst.transform.localToWorldMatrix).ToArray(); - var dstRenderer = dst.AddComponent(); + var dstRenderer = dst.GetComponent(); dstRenderer.sharedMesh = Mesh; dstRenderer.sharedMaterials = Materials; dstRenderer.bones = Bones; @@ -24,7 +24,7 @@ namespace UniGLTF.MeshUtility } else { - var dstFilter = dst.AddComponent(); + var dstFilter = dst.GetComponent(); dstFilter.sharedMesh = Mesh; var dstRenderer = dst.gameObject.AddComponent(); dstRenderer.sharedMaterials = Materials; diff --git a/Assets/UniGLTF/Runtime/MeshUtility/MeshFreezer.cs b/Assets/UniGLTF/Runtime/MeshUtility/MeshFreezer.cs index 4b65f6094..3a7c5c804 100644 --- a/Assets/UniGLTF/Runtime/MeshUtility/MeshFreezer.cs +++ b/Assets/UniGLTF/Runtime/MeshUtility/MeshFreezer.cs @@ -128,9 +128,7 @@ namespace UniGLTF.MeshUtility /// 正規化前のボーンから正規化後のボーンを得る /// /// - public static Mesh NormalizeSkinnedMesh( - SkinnedMeshRenderer src, - Dictionary boneMap) + public static Mesh NormalizeSkinnedMesh(SkinnedMeshRenderer src) { if (src == null || !src.enabled @@ -144,12 +142,6 @@ namespace UniGLTF.MeshUtility var srcMesh = src.sharedMesh; var originalSrcMesh = srcMesh; - // 元の Transform[] bones から、無効なboneを取り除いて前に詰めた配列を作る - var dstBones = src.bones - .Where(x => x != null && boneMap.ContainsKey(x)) - .Select(x => boneMap[x]) - .ToArray(); - var hasBoneWeight = src.bones != null && src.bones.Length > 0; if (!hasBoneWeight) { @@ -172,7 +164,6 @@ namespace UniGLTF.MeshUtility srcMesh.bindposes = new Matrix4x4[] { Matrix4x4.identity }; src.rootBone = src.transform; - dstBones = new[] { boneMap[src.transform] }; src.bones = new[] { src.transform }; src.sharedMesh = srcMesh; } @@ -182,8 +173,7 @@ namespace UniGLTF.MeshUtility mesh.name = srcMesh.name + ".baked"; src.BakeMesh(mesh); - // 新しい骨格のボーンウェイトを作成する - mesh.boneWeights = MapBoneWeight(srcMesh.boneWeights, boneMap, src.bones, dstBones); + mesh.boneWeights = srcMesh.boneWeights; //var m = src.localToWorldMatrix; // include scaling var m = default(Matrix4x4); @@ -195,20 +185,6 @@ namespace UniGLTF.MeshUtility // CopyBlendShapes(src, srcMesh, mesh, m); - // var blendShapeBackup = new List(); - // if (!FreezeBlendShape) - // { - // for (int i = 0; i < srcMesh.blendShapeCount; ++i) - // { - // blendShapeBackup.Add(src.GetBlendShapeWeight(i)); - // src.SetBlendShapeWeight(i, 0); - // } - // } - // for (int i = 0; i < blendShapeBackup.Count; ++i) - // { - // src.SetBlendShapeWeight(i, blendShapeBackup[i]); - // } - if (!hasBoneWeight) { // restore bones diff --git a/Assets/VRM/Runtime/SkinnedMeshUtility/VRMBoneNormalizer.cs b/Assets/VRM/Runtime/SkinnedMeshUtility/VRMBoneNormalizer.cs index 479641975..3004d866a 100644 --- a/Assets/VRM/Runtime/SkinnedMeshUtility/VRMBoneNormalizer.cs +++ b/Assets/VRM/Runtime/SkinnedMeshUtility/VRMBoneNormalizer.cs @@ -66,37 +66,19 @@ namespace VRM } } - // 正規化されたヒエラルキーを作る - var (normalized, bMap, newMesh) = BoneNormalizer.NormalizeHierarchyFreezeMesh(go); - - foreach (var (k, v) in newMesh) - { - v.AttachTo(k.gameObject); - } + // Meshの焼きこみ + var newMesh = BoneNormalizer.NormalizeHierarchyFreezeMesh(go); + // 焼いたMeshで置き換える + BoneNormalizer.Replace(go, newMesh, true, true); // 新しいヒエラルキーからAvatarを作る - var newAvatar = UniHumanoid.AvatarDescription.CreateAvatarForCopyHierarchy( - go.GetComponent(), normalized, bMap, avatarDescription => - { - var vrmHuman = go.GetComponent(); - if (vrmHuman != null && vrmHuman.Description != null) - { - avatarDescription.armStretch = vrmHuman.Description.armStretch; - avatarDescription.legStretch = vrmHuman.Description.legStretch; - avatarDescription.upperArmTwist = vrmHuman.Description.upperArmTwist; - avatarDescription.lowerArmTwist = vrmHuman.Description.lowerArmTwist; - avatarDescription.upperLegTwist = vrmHuman.Description.upperLegTwist; - avatarDescription.lowerLegTwist = vrmHuman.Description.lowerLegTwist; - avatarDescription.feetSpacing = vrmHuman.Description.feetSpacing; - avatarDescription.hasTranslationDoF = vrmHuman.Description.hasTranslationDoF; - } - }); - var newAnimator = normalized.GetOrAddComponent(); + var newAnimator = go.GetComponent(); + var newAvatar = UniHumanoid.AvatarDescription.RecreateAvatar(newAnimator); newAnimator.avatar = newAvatar; - CopyVRMComponents(go, normalized, bMap); + // CopyVRMComponents(go, normalized, bMap); - return normalized; + return go; } ///