From f184f29fa932673ee8bf1ec3a480c1b1b1aac087 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Sat, 12 Apr 2025 00:54:17 +0900 Subject: [PATCH] =?UTF-8?q?AvatarDescription=20=E3=82=92=E4=BD=BF=E3=81=86?= =?UTF-8?q?=E3=81=A8=E3=81=93=E3=82=8D=E3=82=92=E6=B8=9B=E3=82=89=E3=81=97?= =?UTF-8?q?=E3=81=A6=E3=80=81HumanoidLoader=E3=80=80=E3=82=92=E4=BD=BF?= =?UTF-8?q?=E3=81=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Runtime/UniHumanoid/AvatarDescription.cs | 30 +------------ .../UniGLTF/Runtime/UniHumanoid/Humanoid.cs | 2 +- .../Runtime/UniHumanoid/HumanoidLoader.cs | 42 ++++++++++++++++++- .../UniHumanoid/IO/BvhImporterContext.cs | 2 +- .../Runtime/Utils/ForceTransformUniqueName.cs | 1 - .../UniHumanoid/HumanBuilderTest.cs | 9 +++- Assets/VRM/Runtime/IO/VRMImporterContext.cs | 2 +- .../SkinnedMeshUtility/VRMBoneNormalizer.cs | 15 +------ .../SkinnedMeshUtility/VrmMeshUtility.cs | 15 +------ .../ControlRig/Vrm10RuntimeControlRig.cs | 2 +- .../VRM10/Runtime/IO/VrmAnimationImporter.cs | 3 +- .../Runtime/MeshUtility/Vrm10MeshUtility.cs | 6 +-- 12 files changed, 57 insertions(+), 72 deletions(-) diff --git a/Assets/UniGLTF/Runtime/UniHumanoid/AvatarDescription.cs b/Assets/UniGLTF/Runtime/UniHumanoid/AvatarDescription.cs index 5c9a89d02..d47f07e87 100644 --- a/Assets/UniGLTF/Runtime/UniHumanoid/AvatarDescription.cs +++ b/Assets/UniGLTF/Runtime/UniHumanoid/AvatarDescription.cs @@ -103,7 +103,7 @@ namespace UniHumanoid public Avatar CreateAvatarAndSetup(Transform root) { - var avatar = HumanoidLoader.LoadHumanoidAvatar(root, ToHumanoidMap(root)); + var avatar = HumanoidLoader.BuildHumanAvatarFromMap(root, ToHumanoidMap(root)); avatar.name = name; if (root.TryGetComponent(out var animator)) @@ -269,33 +269,7 @@ namespace UniHumanoid modAvatarDesc(avatarDescription); } avatarDescription.SetHumanBones(map); - var avatar = HumanoidLoader.LoadHumanoidAvatar(dst.transform, avatarDescription.ToHumanoidMap(dst.transform)); - avatar.name = "created"; - return avatar; - } - - public static Avatar RecreateAvatar(Animator src) - { - if (src == null) - { - throw new ArgumentNullException("src"); - } - - 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 - .ToDictionary(x => x.Key, x => x.Value) - ; - - var avatarDescription = UniHumanoid.AvatarDescription.Create(); - avatarDescription.SetHumanBones(map); - - var avatar = HumanoidLoader.LoadHumanoidAvatar(src.transform, avatarDescription.ToHumanoidMap(src.transform)); + var avatar = HumanoidLoader.BuildHumanAvatarFromMap(dst.transform, avatarDescription.ToHumanoidMap(dst.transform)); avatar.name = "created"; return avatar; } diff --git a/Assets/UniGLTF/Runtime/UniHumanoid/Humanoid.cs b/Assets/UniGLTF/Runtime/UniHumanoid/Humanoid.cs index 8261b90f9..fb508ba62 100644 --- a/Assets/UniGLTF/Runtime/UniHumanoid/Humanoid.cs +++ b/Assets/UniGLTF/Runtime/UniHumanoid/Humanoid.cs @@ -159,7 +159,7 @@ namespace UniHumanoid /// public Avatar CreateAvatar() { - return HumanoidLoader.LoadHumanoidAvatar(transform, BoneMap); + return HumanoidLoader.BuildHumanAvatarFromMap(transform, BoneMap); } public Transform GetBoneTransform(HumanBodyBones bone) diff --git a/Assets/UniGLTF/Runtime/UniHumanoid/HumanoidLoader.cs b/Assets/UniGLTF/Runtime/UniHumanoid/HumanoidLoader.cs index 1f419c29c..62e1e3e1a 100644 --- a/Assets/UniGLTF/Runtime/UniHumanoid/HumanoidLoader.cs +++ b/Assets/UniGLTF/Runtime/UniHumanoid/HumanoidLoader.cs @@ -6,9 +6,11 @@ using UnityEngine; namespace UniHumanoid { + using BoneMap = IEnumerable<(Transform, HumanBodyBones)>; + public static class HumanoidLoader { - public static Avatar LoadHumanoidAvatar(Transform root, IEnumerable<(Transform, HumanBodyBones)> boneMap) + public static Avatar BuildHumanAvatarFromMap(Transform root, BoneMap boneMap) { ForceTransformUniqueName.Process(root); @@ -49,5 +51,41 @@ namespace UniHumanoid HumanTrait.BoneName.ToDictionary( x => TraitToHumanBone(x), x => x); + + /// + /// Avatar を保持する既存の Animatorヒエラルキーの Transform を変更したのちに、 + /// HumanBone のマッピングを流用して、新たな Avatar を作り直す。 + /// 古い Avatar は破棄する。 + /// + public static void RebuildHumanAvatar(Animator animator) + { + if (animator == null) + { + throw new ArgumentNullException("src"); + } + + var target = animator.gameObject; + + var map = CachedEnum.GetValues() + .Where(x => x != HumanBodyBones.LastBone) + .Select(x => (animator.GetBoneTransform(x), x)) + .Where(x => x.Item1 != null) + ; + var newAvatar = HumanoidLoader.BuildHumanAvatarFromMap(animator.transform, map); + newAvatar.name = "re-created"; + + // var newAvatar = LoadHumanoidAvatarFromAnimator(animator); + // Animator.avatar を代入したときに副作用でTransformが変更されるのを回避するために削除します。 + if (Application.isPlaying) + { + GameObject.Destroy(animator); + } + else + { + GameObject.DestroyImmediate(animator); + } + // 新たに AddComponent する + target.AddComponent().avatar = newAvatar; + } } -} +} \ No newline at end of file diff --git a/Assets/UniGLTF/Runtime/UniHumanoid/IO/BvhImporterContext.cs b/Assets/UniGLTF/Runtime/UniHumanoid/IO/BvhImporterContext.cs index 579ff78d6..fb485492f 100644 --- a/Assets/UniGLTF/Runtime/UniHumanoid/IO/BvhImporterContext.cs +++ b/Assets/UniGLTF/Runtime/UniHumanoid/IO/BvhImporterContext.cs @@ -111,7 +111,7 @@ namespace UniHumanoid // // avatar // - Avatar = HumanoidLoader.LoadHumanoidAvatar(Root.transform, description.ToHumanoidMap(Root.transform)); + Avatar = HumanoidLoader.BuildHumanAvatarFromMap(Root.transform, description.ToHumanoidMap(Root.transform)); Avatar.name = "Avatar"; AvatarDescription = description; var animator = Root.AddComponent(); diff --git a/Assets/UniGLTF/Runtime/Utils/ForceTransformUniqueName.cs b/Assets/UniGLTF/Runtime/Utils/ForceTransformUniqueName.cs index d3832b0f9..37032d16a 100644 --- a/Assets/UniGLTF/Runtime/Utils/ForceTransformUniqueName.cs +++ b/Assets/UniGLTF/Runtime/Utils/ForceTransformUniqueName.cs @@ -40,7 +40,6 @@ namespace UniGLTF.Utils /// /// AvatarBuilder 'GLTF': Ambiguous Transform '32/root/torso_1/torso_2/torso_3/torso_4/torso_5/torso_6/torso_7/neck_1/neck_2/head/ENDSITE' and '32/root/torso_1/torso_2/torso_3/torso_4/torso_5/torso_6/torso_7/l_shoulder/l_up_arm/l_low_arm/l_hand/ENDSITE' found in hierarchy for human bone 'Head'. Transform name mapped to a human bone must be unique. /// UnityEngine.AvatarBuilder:BuildHumanAvatar (UnityEngine.GameObject,UnityEngine.HumanDescription) - /// UniHumanoid.AvatarDescription:CreateAvatar (UnityEngine.Transform) /// /// 主に BVH の EndSite 由来の GameObject 名が重複することへの対策 /// ex: parent-ENDSITE diff --git a/Assets/UniGLTF_Samples/UniHumanoid/HumanBuilderTest.cs b/Assets/UniGLTF_Samples/UniHumanoid/HumanBuilderTest.cs index fb5aa785b..b3fdd1b23 100644 --- a/Assets/UniGLTF_Samples/UniHumanoid/HumanBuilderTest.cs +++ b/Assets/UniGLTF_Samples/UniHumanoid/HumanBuilderTest.cs @@ -94,6 +94,12 @@ namespace UniHumanoid Add(HumanBodyBones.RightFoot, HumanBodyBones.RightLowerLeg, new Vector3(0, -foot, foot)); Add(HumanBodyBones.RightToes, HumanBodyBones.RightFoot, new Vector3(0, 0, toe)); } + + public Avatar Build() + { + var description = AvatarDescription.Create(Skeleton); + return HumanoidLoader.BuildHumanAvatarFromMap(m_root, description.ToHumanoidMap(m_root)); + } } void OnEnable() @@ -118,13 +124,12 @@ namespace UniHumanoid builder.AddArm(0.1f, 0.3f, 0.3f, 0.1f); builder.AddLeg(0.1f, 0.3f, 0.4f, 0.1f, 0.1f); - var description = AvatarDescription.Create(builder.Skeleton); var animator = GetComponent(); if (animator == null) { throw new System.ArgumentException("no animator"); } - animator.avatar = HumanoidLoader.LoadHumanoidAvatar(root, description.ToHumanoidMap(root)); + animator.avatar = builder.Build(); // create SkinnedMesh for bone visualize var renderer = SkeletonMeshUtility.CreateRenderer(animator); diff --git a/Assets/VRM/Runtime/IO/VRMImporterContext.cs b/Assets/VRM/Runtime/IO/VRMImporterContext.cs index e4d735224..7e03ce134 100644 --- a/Assets/VRM/Runtime/IO/VRMImporterContext.cs +++ b/Assets/VRM/Runtime/IO/VRMImporterContext.cs @@ -259,7 +259,7 @@ namespace VRM { AvatarDescription = VRM.humanoid.ToDescription(Nodes); AvatarDescription.name = "AvatarDescription"; - HumanoidAvatar = UniHumanoid.HumanoidLoader.LoadHumanoidAvatar(Root.transform, AvatarDescription.ToHumanoidMap(Root.transform)); + HumanoidAvatar = UniHumanoid.HumanoidLoader.BuildHumanAvatarFromMap(Root.transform, AvatarDescription.ToHumanoidMap(Root.transform)); if (!HumanoidAvatar.isValid || !HumanoidAvatar.isHuman) { throw new Exception("fail to create avatar"); diff --git a/Assets/VRM/Runtime/SkinnedMeshUtility/VRMBoneNormalizer.cs b/Assets/VRM/Runtime/SkinnedMeshUtility/VRMBoneNormalizer.cs index 3e53c3cba..77269756d 100644 --- a/Assets/VRM/Runtime/SkinnedMeshUtility/VRMBoneNormalizer.cs +++ b/Assets/VRM/Runtime/SkinnedMeshUtility/VRMBoneNormalizer.cs @@ -81,23 +81,10 @@ namespace VRM BoneNormalizer.Replace(go, newMeshMap, false); // 回転とスケールが除去された新しいヒエラルキーからAvatarを作る - Avatar newAvatar = default; if (go.TryGetComponent(out var animator)) { - newAvatar = UniHumanoid.AvatarDescription.RecreateAvatar(animator); - - // Animator.avatar を代入したときに副作用でTransformが変更されるのを回避するために削除します。 - if (Application.isPlaying) - { - GameObject.Destroy(animator); - } - else - { - GameObject.DestroyImmediate(animator); - } + HumanoidLoader.RebuildHumanAvatar(animator); } - - go.GetOrAddComponent().avatar = newAvatar; } /// diff --git a/Assets/VRM/Runtime/SkinnedMeshUtility/VrmMeshUtility.cs b/Assets/VRM/Runtime/SkinnedMeshUtility/VrmMeshUtility.cs index 02dbb1125..4277c680d 100644 --- a/Assets/VRM/Runtime/SkinnedMeshUtility/VrmMeshUtility.cs +++ b/Assets/VRM/Runtime/SkinnedMeshUtility/VrmMeshUtility.cs @@ -107,23 +107,10 @@ namespace VRM if (FreezeMesh) { - Avatar newAvatar = null; if (target.TryGetComponent(out var animator)) { - newAvatar = AvatarDescription.RecreateAvatar(animator); - // ??? clear old avatar ??? - var t = animator.gameObject; - if (Application.isPlaying) - { - GameObject.Destroy(animator); - } - else - { - GameObject.DestroyImmediate(animator); - } + HumanoidLoader.RebuildHumanAvatar(animator); } - - target.AddComponent().avatar = newAvatar; } return (list, newList); diff --git a/Assets/VRM10/Runtime/Components/Vrm10Runtime/ControlRig/Vrm10RuntimeControlRig.cs b/Assets/VRM10/Runtime/Components/Vrm10Runtime/ControlRig/Vrm10RuntimeControlRig.cs index 9c6e07226..1acb9e1ef 100644 --- a/Assets/VRM10/Runtime/Components/Vrm10Runtime/ControlRig/Vrm10RuntimeControlRig.cs +++ b/Assets/VRM10/Runtime/Components/Vrm10Runtime/ControlRig/Vrm10RuntimeControlRig.cs @@ -38,7 +38,7 @@ namespace UniVRM10 _hipBone.ControlBone.SetParent(_controlRigRoot); var transformBonePairs = _bones.Select(kv => (kv.Value.ControlBone, kv.Key)); - _controlRigAvatar = HumanoidLoader.LoadHumanoidAvatar(vrmRoot, transformBonePairs); + _controlRigAvatar = HumanoidLoader.BuildHumanAvatarFromMap(vrmRoot, transformBonePairs); _controlRigAvatar.name = "Runtime Control Rig"; if (vrmRoot.TryGetComponent(out var animator)) diff --git a/Assets/VRM10/Runtime/IO/VrmAnimationImporter.cs b/Assets/VRM10/Runtime/IO/VrmAnimationImporter.cs index c3af9a539..152d1d77d 100644 --- a/Assets/VRM10/Runtime/IO/VrmAnimationImporter.cs +++ b/Assets/VRM10/Runtime/IO/VrmAnimationImporter.cs @@ -262,9 +262,8 @@ namespace UniVRM10 // // avatar // - var avatar = HumanoidLoader.LoadHumanoidAvatar(Root.transform, humanMap); + var avatar = HumanoidLoader.BuildHumanAvatarFromMap(Root.transform, humanMap); avatar.name = "Avatar"; - // AvatarDescription = description; var animator = Root.AddComponent(); animator.avatar = avatar; } diff --git a/Assets/VRM10/Runtime/MeshUtility/Vrm10MeshUtility.cs b/Assets/VRM10/Runtime/MeshUtility/Vrm10MeshUtility.cs index e48e2274d..335ba0e04 100644 --- a/Assets/VRM10/Runtime/MeshUtility/Vrm10MeshUtility.cs +++ b/Assets/VRM10/Runtime/MeshUtility/Vrm10MeshUtility.cs @@ -116,14 +116,10 @@ namespace UniVRM10 if (FreezeMesh) { - Avatar newAvatar = default; if (target.TryGetComponent(out var animator)) { - newAvatar = AvatarDescription.RecreateAvatar(animator); - GameObject.DestroyImmediate(animator); + HumanoidLoader.RebuildHumanAvatar(animator); } - animator = target.AddComponent(); - animator.avatar = newAvatar; } return (list, newList);