From ced5dc891877da4d6bcf6ea613c5d46f6fdb75dc Mon Sep 17 00:00:00 2001 From: ousttrue Date: Wed, 25 Oct 2023 21:50:06 +0900 Subject: [PATCH] implement FreezeScaling --- .../Runtime/MeshUtility/BoneNormalizer.cs | 63 ++++++++++++------- .../Runtime/UniHumanoid/AvatarDescription.cs | 38 +++++++++++ .../SkinnedMeshUtility/VRMBoneNormalizer.cs | 29 ++------- .../Runtime/MeshUtility/Vrm10MeshUtility.cs | 19 +++++- 4 files changed, 99 insertions(+), 50 deletions(-) diff --git a/Assets/UniGLTF/Runtime/MeshUtility/BoneNormalizer.cs b/Assets/UniGLTF/Runtime/MeshUtility/BoneNormalizer.cs index e642d0cba..24d3caad0 100644 --- a/Assets/UniGLTF/Runtime/MeshUtility/BoneNormalizer.cs +++ b/Assets/UniGLTF/Runtime/MeshUtility/BoneNormalizer.cs @@ -11,36 +11,35 @@ namespace UniGLTF.MeshUtility { public delegate Avatar CreateAvatarFunc(GameObject original, GameObject normalized, Dictionary boneMap); - static (GameObject, Dictionary) NormalizeHierarchy(GameObject go, CreateAvatarFunc createAvatar) + public static (GameObject, Dictionary) CreateNormalizedHierarchy(GameObject go, + bool removeScaling = true, + bool removeRotation = true) { var boneMap = new Dictionary(); - - // - // 回転・スケールの無いヒエラルキーをコピーする - // var normalized = new GameObject(go.name + "(normalized)"); normalized.transform.position = go.transform.position; - CopyAndBuild(go.transform, normalized.transform, boneMap); - // - // 新しいヒエラルキーからAvatarを作る - // + if (removeScaling && removeRotation) { - var animator = normalized.AddComponent(); - var avatar = createAvatar(go, normalized, boneMap); - avatar.name = go.name + ".normalized"; - animator.avatar = avatar; + 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 CopyAndBuild(Transform src, Transform dst, Dictionary boneMap) + static void RemoveScaleRecursive(Transform src, Transform dst, Dictionary boneMap) { boneMap[src] = dst; @@ -50,9 +49,27 @@ namespace UniGLTF.MeshUtility { var dstChild = new GameObject(child.name); dstChild.transform.SetParent(dst); - dstChild.transform.position = child.position; // copy position only + 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); + } + } + } - CopyAndBuild(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); } } } @@ -489,12 +506,12 @@ namespace UniGLTF.MeshUtility /// BlendShapeを0クリアするか否か。false の場合 BlendShape の現状を Bake する /// Avatarを作る関数 /// - public static (GameObject, Dictionary) Execute(GameObject go, CreateAvatarFunc createAvatar) + public static (GameObject, Dictionary) Execute(GameObject go) { // // 正規化されたヒエラルキーを作る // - var (normalized, boneMap) = NormalizeHierarchy(go, createAvatar); + var (normalized, boneMap) = CreateNormalizedHierarchy(go); // // 各メッシュから回転・スケールを取り除いてBinding行列を再計算する diff --git a/Assets/UniGLTF/Runtime/UniHumanoid/AvatarDescription.cs b/Assets/UniGLTF/Runtime/UniHumanoid/AvatarDescription.cs index 13b2e76c6..c3412d014 100644 --- a/Assets/UniGLTF/Runtime/UniHumanoid/AvatarDescription.cs +++ b/Assets/UniGLTF/Runtime/UniHumanoid/AvatarDescription.cs @@ -5,6 +5,7 @@ using UnityEngine; using System; using System.Linq; using System.Collections.Generic; +using UniGLTF.Utils; namespace UniHumanoid @@ -271,5 +272,42 @@ namespace UniHumanoid return false; } #endif + + public static void AddAnimator(GameObject _src, + GameObject dst, + IDictionary boneMap, + Action modAvatarDesc = null) + { + var src = _src.GetComponent(); + + var srcHumanBones = CachedEnum.GetValues() + .Where(x => x != HumanBodyBones.LastBone) + .Select(x => new { Key = x, Value = src.GetBoneTransform(x) }) + .Where(x => x.Value != null) + ; + + var map = + srcHumanBones + .Where(x => boneMap.ContainsKey(x.Value)) + .ToDictionary(x => x.Key, x => boneMap[x.Value]) + ; + + var animator = dst.AddComponent(); + if (animator == null) + { + animator = dst.AddComponent(); + } + + var avatarDescription = UniHumanoid.AvatarDescription.Create(); + if (modAvatarDesc != null) + { + modAvatarDesc(avatarDescription); + } + avatarDescription.SetHumanBones(map); + var avatar = avatarDescription.CreateAvatar(dst.transform); + + avatar.name = dst.name; + animator.avatar = avatar; + } } } \ No newline at end of file diff --git a/Assets/VRM/Runtime/SkinnedMeshUtility/VRMBoneNormalizer.cs b/Assets/VRM/Runtime/SkinnedMeshUtility/VRMBoneNormalizer.cs index f3fe1dca7..56fcca10b 100644 --- a/Assets/VRM/Runtime/SkinnedMeshUtility/VRMBoneNormalizer.cs +++ b/Assets/VRM/Runtime/SkinnedMeshUtility/VRMBoneNormalizer.cs @@ -65,31 +65,13 @@ namespace VRM } } - // // 正規化されたヒエラルキーを作る - // - var (normalized, bMap) = BoneNormalizer.Execute(go, (_src, dst, boneMap) => + var (normalized, bMap) = BoneNormalizer.Execute(go); + + // 新しいヒエラルキーからAvatarを作る + UniHumanoid.AvatarDescription.AddAnimator(go, normalized, bMap, avatarDescription => { - var src = _src.GetComponent(); - - var srcHumanBones = CachedEnum.GetValues() - .Where(x => x != HumanBodyBones.LastBone) - .Select(x => new { Key = x, Value = src.GetBoneTransform(x) }) - .Where(x => x.Value != null) - ; - - var map = - srcHumanBones - .Where(x => boneMap.ContainsKey(x.Value)) - .ToDictionary(x => x.Key, x => boneMap[x.Value]) - ; - - if (dst.GetComponent() == null) - { - var animator = dst.AddComponent(); - } var vrmHuman = go.GetComponent(); - var avatarDescription = AvatarDescription.Create(); if (vrmHuman != null && vrmHuman.Description != null) { avatarDescription.armStretch = vrmHuman.Description.armStretch; @@ -101,9 +83,6 @@ namespace VRM avatarDescription.feetSpacing = vrmHuman.Description.feetSpacing; avatarDescription.hasTranslationDoF = vrmHuman.Description.hasTranslationDoF; } - avatarDescription.SetHumanBones(map); - var avatar = avatarDescription.CreateAvatar(dst.transform); - return avatar; }); CopyVRMComponents(go, normalized, bMap); diff --git a/Assets/VRM10/Runtime/MeshUtility/Vrm10MeshUtility.cs b/Assets/VRM10/Runtime/MeshUtility/Vrm10MeshUtility.cs index 684c1f680..da612bee9 100644 --- a/Assets/VRM10/Runtime/MeshUtility/Vrm10MeshUtility.cs +++ b/Assets/VRM10/Runtime/MeshUtility/Vrm10MeshUtility.cs @@ -1,5 +1,7 @@ using System.Collections.Generic; using System.Linq; +using UniGLTF.MeshUtility; +using UniHumanoid; using UnityEngine; namespace UniVRM10 @@ -118,9 +120,22 @@ namespace UniVRM10 } } - public void Process() + public void Process(GameObject go) { - Debug.Log("Process !"); + // TODO: UNDO + + // 正規化されたヒエラルキーを作る + var (normalized, boneMap) = BoneNormalizer.CreateNormalizedHierarchy(go, + removeScaling: FreezeScaling, + removeRotation: FreezeRotation); + + // TODO: update: spring + // TODO: update: constraint + // TODO: update: firstPoint offset + + AvatarDescription.AddAnimator(go, normalized, boneMap); + + // TODO: write back normalized transform to boneMap } } }