feat: improve behavior when called setup outfit for setuped outfit (#1200)

This commit is contained in:
Sayamame-beans 2024-10-20 09:52:51 +09:00 committed by GitHub
parent 5bafb0ba9d
commit 26153ea60d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -145,25 +145,54 @@ namespace nadena.dev.modular_avatar.core.editor
out var avatarRoot, out var avatarHips, out var outfitHips) out var avatarRoot, out var avatarHips, out var outfitHips)
) return; ) return;
Undo.SetCurrentGroupName("Setup Outfit");
var avatarArmature = avatarHips.transform.parent; var avatarArmature = avatarHips.transform.parent;
var outfitArmature = outfitHips.transform.parent; var outfitArmature = outfitHips.transform.parent;
if (outfitArmature.GetComponent<ModularAvatarMergeArmature>() == null) var merge = outfitArmature.GetComponent<ModularAvatarMergeArmature>();
if (merge == null)
{
merge = Undo.AddComponent<ModularAvatarMergeArmature>(outfitArmature.gameObject);
} else {
Undo.RecordObject(merge, "");
}
if (merge.mergeTarget == null || merge.mergeTargetObject == null)
{ {
var merge = Undo.AddComponent<ModularAvatarMergeArmature>(outfitArmature.gameObject);
merge.mergeTarget = new AvatarObjectReference(); merge.mergeTarget = new AvatarObjectReference();
merge.mergeTarget.referencePath = RuntimeUtil.RelativePath(avatarRoot, avatarArmature.gameObject); merge.mergeTarget.referencePath = RuntimeUtil.RelativePath(avatarRoot, avatarArmature.gameObject);
merge.LockMode = ArmatureLockMode.BaseToMerge; merge.LockMode = ArmatureLockMode.BaseToMerge;
}
if (string.IsNullOrEmpty(merge.prefix) && string.IsNullOrEmpty(merge.suffix))
{
merge.InferPrefixSuffix(); merge.InferPrefixSuffix();
}
List<Transform> subRoots = new List<Transform>(); PrefabUtility.RecordPrefabInstancePropertyModifications(merge);
HeuristicBoneMapper.RenameBonesByHeuristic(merge, skipped: subRoots);
// If the outfit has an UpperChest bone but the avatar doesn't, add an additional MergeArmature to List<Transform> subRoots = new List<Transform>();
// help with this HeuristicBoneMapper.RenameBonesByHeuristic(merge, skipped: subRoots);
foreach (var subRoot in subRoots)
// If the outfit has an UpperChest bone but the avatar doesn't, add an additional MergeArmature to
// help with this
foreach (var subRoot in subRoots)
{
var subConfig = subRoot.GetComponent<ModularAvatarMergeArmature>();
var subConfigMangleNames = false;
if (subConfig == null)
{
subConfig = Undo.AddComponent<ModularAvatarMergeArmature>(subRoot.gameObject);
}
else
{
Undo.RecordObject(subConfig, "");
subConfigMangleNames = subConfig.mangleNames;
}
if (subConfig.mergeTarget == null || subConfig.mergeTargetObject == null)
{ {
var subConfig = Undo.AddComponent<ModularAvatarMergeArmature>(subRoot.gameObject);
var parentTransform = subConfig.transform.parent; var parentTransform = subConfig.transform.parent;
var parentConfig = parentTransform.GetComponentInParent<ModularAvatarMergeArmature>(); var parentConfig = parentTransform.GetComponentInParent<ModularAvatarMergeArmature>();
var parentMapping = parentConfig.MapBone(parentTransform); var parentMapping = parentConfig.MapBone(parentTransform);
@ -174,34 +203,48 @@ namespace nadena.dev.modular_avatar.core.editor
subConfig.LockMode = ArmatureLockMode.BaseToMerge; subConfig.LockMode = ArmatureLockMode.BaseToMerge;
subConfig.prefix = merge.prefix; subConfig.prefix = merge.prefix;
subConfig.suffix = merge.suffix; subConfig.suffix = merge.suffix;
subConfig.mangleNames = false; subConfig.mangleNames = subConfigMangleNames;
PrefabUtility.RecordPrefabInstancePropertyModifications(subConfig);
} }
}
var avatarRootMatchingArmature = avatarRoot.transform.Find(outfitArmature.gameObject.name); var avatarRootMatchingArmature = avatarRoot.transform.Find(outfitArmature.gameObject.name);
if (merge.prefix == "" && merge.suffix == "" && avatarRootMatchingArmature != null) if (merge.prefix == "" && merge.suffix == "" && avatarRootMatchingArmature != null)
{ {
// We have an armature whose names exactly match the root armature - this can cause some serious // We have an armature whose names exactly match the root armature - this can cause some serious
// confusion in Unity's humanoid armature matching system. Fortunately, we can avoid this by // confusion in Unity's humanoid armature matching system. Fortunately, we can avoid this by
// renaming a bone close to the root; this will ensure the number of matching bones is small, and // renaming a bone close to the root; this will ensure the number of matching bones is small, and
// Unity's heuristics (apparently) will choose the base avatar's armature as the "true" armature. // Unity's heuristics (apparently) will choose the base avatar's armature as the "true" armature.
outfitArmature.name += ".1"; outfitArmature.name += ".1";
// Also make sure to refresh the avatar's animator humanoid bone cache. // Also make sure to refresh the avatar's animator humanoid bone cache.
var avatarAnimator = avatarRoot.GetComponent<Animator>(); var avatarAnimator = avatarRoot.GetComponent<Animator>();
var humanDescription = avatarAnimator.avatar; var humanDescription = avatarAnimator.avatar;
avatarAnimator.avatar = null; avatarAnimator.avatar = null;
// ReSharper disable once Unity.InefficientPropertyAccess // ReSharper disable once Unity.InefficientPropertyAccess
avatarAnimator.avatar = humanDescription; avatarAnimator.avatar = humanDescription;
}
} }
FixAPose(avatarRoot, outfitArmature); FixAPose(avatarRoot, outfitArmature);
var meshSettings = outfitRoot.GetComponent<ModularAvatarMeshSettings>();
var mSInheritProbeAnchor = ModularAvatarMeshSettings.InheritMode.SetOrInherit;
var mSInheritBounds = ModularAvatarMeshSettings.InheritMode.SetOrInherit;
if (outfitRoot != null if (outfitRoot != null
&& outfitRoot.GetComponent<ModularAvatarMeshSettings>() == null && meshSettings == null
&& outfitRoot.GetComponentInParent<ModularAvatarMeshSettings>() == null) && outfitRoot.GetComponentInParent<ModularAvatarMeshSettings>() == null)
{ {
var meshSettings = Undo.AddComponent<ModularAvatarMeshSettings>(outfitRoot.gameObject); meshSettings = Undo.AddComponent<ModularAvatarMeshSettings>(outfitRoot.gameObject);
} else if (outfitRoot != null && meshSettings != null) {
Undo.RecordObject(meshSettings, "");
mSInheritProbeAnchor = meshSettings.InheritProbeAnchor;
mSInheritBounds = meshSettings.InheritBounds;
}
if (meshSettings != null
&& (meshSettings.ProbeAnchor == null || meshSettings.ProbeAnchor.Get(meshSettings) == null
|| meshSettings.RootBone == null || meshSettings.RootBone.Get(meshSettings) == null))
{
Transform rootBone = null, probeAnchor = null; Transform rootBone = null, probeAnchor = null;
Bounds bounds = ModularAvatarMeshSettings.DEFAULT_BOUNDS; Bounds bounds = ModularAvatarMeshSettings.DEFAULT_BOUNDS;
@ -217,8 +260,8 @@ namespace nadena.dev.modular_avatar.core.editor
rootBone = avatarRoot.transform; rootBone = avatarRoot.transform;
} }
meshSettings.InheritProbeAnchor = ModularAvatarMeshSettings.InheritMode.SetOrInherit; meshSettings.InheritProbeAnchor = mSInheritProbeAnchor;
meshSettings.InheritBounds = ModularAvatarMeshSettings.InheritMode.SetOrInherit; meshSettings.InheritBounds = mSInheritBounds;
meshSettings.ProbeAnchor = new AvatarObjectReference(); meshSettings.ProbeAnchor = new AvatarObjectReference();
meshSettings.ProbeAnchor.referencePath = RuntimeUtil.RelativePath(avatarRoot, probeAnchor.gameObject); meshSettings.ProbeAnchor.referencePath = RuntimeUtil.RelativePath(avatarRoot, probeAnchor.gameObject);
@ -226,6 +269,8 @@ namespace nadena.dev.modular_avatar.core.editor
meshSettings.RootBone = new AvatarObjectReference(); meshSettings.RootBone = new AvatarObjectReference();
meshSettings.RootBone.referencePath = RuntimeUtil.RelativePath(avatarRoot, rootBone.gameObject); meshSettings.RootBone.referencePath = RuntimeUtil.RelativePath(avatarRoot, rootBone.gameObject);
meshSettings.Bounds = bounds; meshSettings.Bounds = bounds;
PrefabUtility.RecordPrefabInstancePropertyModifications(meshSettings);
} }
} }