AvatarDescription を使うところを減らして、HumanoidLoader を使う

This commit is contained in:
ousttrue
2025-04-12 00:54:17 +09:00
parent fbb9932d0c
commit f184f29fa9
12 changed files with 57 additions and 72 deletions

View File

@@ -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<Animator>(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<HumanBodyBones>()
.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;
}

View File

@@ -159,7 +159,7 @@ namespace UniHumanoid
/// <returns></returns>
public Avatar CreateAvatar()
{
return HumanoidLoader.LoadHumanoidAvatar(transform, BoneMap);
return HumanoidLoader.BuildHumanAvatarFromMap(transform, BoneMap);
}
public Transform GetBoneTransform(HumanBodyBones bone)

View File

@@ -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);
/// <summary>
/// Avatar を保持する既存の Animatorヒエラルキーの Transform を変更したのちに、
/// HumanBone のマッピングを流用して、新たな Avatar を作り直す。
/// 古い Avatar は破棄する。
/// </summary>
public static void RebuildHumanAvatar(Animator animator)
{
if (animator == null)
{
throw new ArgumentNullException("src");
}
var target = animator.gameObject;
var map = CachedEnum.GetValues<HumanBodyBones>()
.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<Animator>().avatar = newAvatar;
}
}
}
}

View File

@@ -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<Animator>();

View File

@@ -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

View File

@@ -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<Animator>();
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);

View File

@@ -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");

View File

@@ -81,23 +81,10 @@ namespace VRM
BoneNormalizer.Replace(go, newMeshMap, false);
// 回転とスケールが除去された新しいヒエラルキーからAvatarを作る
Avatar newAvatar = default;
if (go.TryGetComponent<Animator>(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<Animator>().avatar = newAvatar;
}
/// <summary>

View File

@@ -107,23 +107,10 @@ namespace VRM
if (FreezeMesh)
{
Avatar newAvatar = null;
if (target.TryGetComponent<Animator>(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<Animator>().avatar = newAvatar;
}
return (list, newList);

View File

@@ -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<Animator>(out var animator))

View File

@@ -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>();
animator.avatar = avatar;
}

View File

@@ -116,14 +116,10 @@ namespace UniVRM10
if (FreezeMesh)
{
Avatar newAvatar = default;
if (target.TryGetComponent<Animator>(out var animator))
{
newAvatar = AvatarDescription.RecreateAvatar(animator);
GameObject.DestroyImmediate(animator);
HumanoidLoader.RebuildHumanAvatar(animator);
}
animator = target.AddComponent<Animator>();
animator.avatar = newAvatar;
}
return (list, newList);