mirror of
https://github.com/bdunderscore/modular-avatar.git
synced 2025-04-11 23:19:00 +08:00
feat: support using Humanoid Rig on RenameBonesByHeuristic
This commit is contained in:
parent
9bbec4c86b
commit
97d8261557
@ -306,7 +306,9 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
GameObject src,
|
||||
GameObject newParent,
|
||||
List<Transform> skipped = null,
|
||||
HashSet<Transform> unassigned = null
|
||||
HashSet<Transform> unassigned = null,
|
||||
Animator avatarAnimator = null,
|
||||
Dictionary<Transform, HumanBodyBones> humanoidBones = null
|
||||
)
|
||||
{
|
||||
Dictionary<Transform, Transform> mappings = new Dictionary<Transform, Transform>();
|
||||
@ -355,21 +357,65 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
var childName = child.gameObject.name;
|
||||
var targetObjectName = childName.Substring(config.prefix.Length,
|
||||
childName.Length - config.prefix.Length - config.suffix.Length);
|
||||
|
||||
if (!NameToBoneMap.TryGetValue(
|
||||
NormalizeName(targetObjectName), out var bodyBones))
|
||||
List<HumanBodyBones> bodyBones = null;
|
||||
var isMapped = false;
|
||||
|
||||
if (humanoidBones != null && humanoidBones.TryGetValue(child, out var humanoidBone))
|
||||
{
|
||||
if (avatarAnimator != null)
|
||||
{
|
||||
var avatarBone = avatarAnimator.GetBoneTransform(humanoidBone);
|
||||
if (avatarBone != null)
|
||||
{
|
||||
mappings[child] = avatarBone;
|
||||
unassigned.Remove(avatarBone);
|
||||
lcNameToXform.Remove(NormalizeName(avatarBone.gameObject.name));
|
||||
isMapped = true;
|
||||
} else {
|
||||
bodyBones = new List<HumanBodyBones> { humanoidBone };
|
||||
}
|
||||
} else {
|
||||
bodyBones = new List<HumanBodyBones>() { humanoidBone };
|
||||
}
|
||||
}
|
||||
|
||||
if (!isMapped && bodyBones == null && !NameToBoneMap.TryGetValue(
|
||||
NormalizeName(targetObjectName), out bodyBones))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (var otherName in bodyBones.SelectMany(bone => BoneToNameMap[bone]))
|
||||
if (!isMapped)
|
||||
{
|
||||
if (lcNameToXform.TryGetValue(otherName, out var targetObject))
|
||||
foreach (var bodyBone in bodyBones)
|
||||
{
|
||||
mappings[child] = targetObject;
|
||||
unassigned.Remove(targetObject);
|
||||
lcNameToXform.Remove(otherName.ToLowerInvariant());
|
||||
break;
|
||||
if (avatarAnimator != null)
|
||||
{
|
||||
var avatarBone = avatarAnimator.GetBoneTransform(bodyBone);
|
||||
if (avatarBone != null && unassigned.Contains(avatarBone))
|
||||
{
|
||||
mappings[child] = avatarBone;
|
||||
unassigned.Remove(avatarBone);
|
||||
lcNameToXform.Remove(NormalizeName(avatarBone.gameObject.name));
|
||||
isMapped = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!isMapped)
|
||||
{
|
||||
foreach (var otherName in bodyBones.SelectMany(bone => BoneToNameMap[bone]))
|
||||
{
|
||||
if (lcNameToXform.TryGetValue(otherName, out var targetObject))
|
||||
{
|
||||
mappings[child] = targetObject;
|
||||
unassigned.Remove(targetObject);
|
||||
lcNameToXform.Remove(otherName.ToLowerInvariant());
|
||||
isMapped = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -388,7 +434,7 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
return mappings;
|
||||
}
|
||||
|
||||
internal static void RenameBonesByHeuristic(ModularAvatarMergeArmature config, List<Transform> skipped = null)
|
||||
internal static void RenameBonesByHeuristic(ModularAvatarMergeArmature config, List<Transform> skipped = null, Dictionary<Transform, HumanBodyBones> humanoidBones = null, Animator avatarAnimator = null)
|
||||
{
|
||||
var target = config.mergeTarget.Get(RuntimeUtil.FindAvatarTransformInParents(config.transform));
|
||||
if (target == null) return;
|
||||
@ -399,7 +445,7 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
|
||||
void Traverse(Transform src, Transform dst)
|
||||
{
|
||||
var mappings = AssignBoneMappings(config, src.gameObject, dst.gameObject, skipped: skipped);
|
||||
var mappings = AssignBoneMappings(config, src.gameObject, dst.gameObject, skipped: skipped, humanoidBones: humanoidBones, avatarAnimator: avatarAnimator);
|
||||
|
||||
foreach (var pair in mappings)
|
||||
{
|
||||
|
@ -114,7 +114,9 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
{
|
||||
if (GUILayout.Button(G("merge_armature.adjust_names")))
|
||||
{
|
||||
HeuristicBoneMapper.RenameBonesByHeuristic(target);
|
||||
var avatarRoot = RuntimeUtil.FindAvatarTransformInParents(target.mergeTarget.Get(target).transform);
|
||||
var avatarAnimator = avatarRoot != null ? avatarRoot.GetComponent<Animator>() : null;
|
||||
HeuristicBoneMapper.RenameBonesByHeuristic(target, avatarAnimator: avatarAnimator);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8,6 +8,7 @@ using UnityEditor;
|
||||
using UnityEngine;
|
||||
using Object = UnityEngine.Object;
|
||||
using static nadena.dev.modular_avatar.core.editor.Localization;
|
||||
using System;
|
||||
|
||||
#endregion
|
||||
|
||||
@ -156,8 +157,36 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
merge.LockMode = ArmatureLockMode.BaseToMerge;
|
||||
merge.InferPrefixSuffix();
|
||||
|
||||
var outfitAnimator = outfitRoot.GetComponent<Animator>();
|
||||
if (outfitAnimator != null)
|
||||
{
|
||||
var hipsCheck = outfitAnimator.isHuman ? outfitAnimator.GetBoneTransform(HumanBodyBones.Hips) : null;
|
||||
if (hipsCheck != null && hipsCheck.parent == outfitRoot.transform)
|
||||
{
|
||||
// Sometimes broken rigs can have the hips as a direct child of the root, instead of having
|
||||
// an intermediate Armature object. We do not currently support this kind of rig, and so we'll
|
||||
// assume the outfit's humanoid rig is broken and move on to heuristic matching.
|
||||
outfitAnimator = null;
|
||||
} else if (hipsCheck == null) {
|
||||
outfitAnimator = null;
|
||||
}
|
||||
}
|
||||
|
||||
Dictionary<Transform, HumanBodyBones> humanoidBones = null;
|
||||
if (outfitAnimator != null)
|
||||
{
|
||||
humanoidBones = new Dictionary<Transform, HumanBodyBones>();
|
||||
foreach (HumanBodyBones boneIndex in Enum.GetValues(typeof(HumanBodyBones)))
|
||||
{
|
||||
var bone = boneIndex != HumanBodyBones.LastBone ? outfitAnimator.GetBoneTransform(boneIndex) : null;
|
||||
if (bone == null) continue;
|
||||
humanoidBones[bone] = boneIndex;
|
||||
}
|
||||
}
|
||||
|
||||
var avatarAnimator = avatarRoot.GetComponent<Animator>();
|
||||
List<Transform> subRoots = new List<Transform>();
|
||||
HeuristicBoneMapper.RenameBonesByHeuristic(merge, skipped: subRoots);
|
||||
HeuristicBoneMapper.RenameBonesByHeuristic(merge, skipped: subRoots, humanoidBones: humanoidBones, avatarAnimator: avatarAnimator);
|
||||
|
||||
// If the outfit has an UpperChest bone but the avatar doesn't, add an additional MergeArmature to
|
||||
// help with this
|
||||
@ -187,7 +216,6 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
outfitArmature.name += ".1";
|
||||
|
||||
// Also make sure to refresh the avatar's animator humanoid bone cache.
|
||||
var avatarAnimator = avatarRoot.GetComponent<Animator>();
|
||||
var humanDescription = avatarAnimator.avatar;
|
||||
avatarAnimator.avatar = null;
|
||||
// ReSharper disable once Unity.InefficientPropertyAccess
|
||||
@ -542,4 +570,4 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
return avatarHips != null && outfitHips != null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user