Prune duplicate PBs on merge armature

This fixes issues where outfits which duplicate the PB components from the
base avatar can result in PB motion breaking after merge.
This commit is contained in:
bd_ 2022-12-09 12:30:43 -08:00
parent 2ac191555e
commit 59d56fb602

View File

@ -283,6 +283,8 @@ namespace nadena.dev.modular_avatar.core.editor
mergedSrcBone.transform.localScale = src.transform.localScale;
mergedSrcBone.transform.SetParent(newParent.transform, true);
if (zipMerge) PruneDuplicatePhysBones(newParent, src);
bool retain = HasAdditionalComponents(src, out var constraintType);
if (constraintType != null)
{
@ -359,5 +361,40 @@ namespace nadena.dev.modular_avatar.core.editor
return retain;
}
/**
* Sometimes outfit authors copy the entire armature, including PhysBones components. If we merge these and
* end up with multiple PB components referencing the same target, PB refuses to animate the bone. So detect
* and prune this case.
*
* For simplicity - we currently only detect the case where the physbone references the component it's on.
* TODO - detect duplicate colliders, contacts, et - these can cause perf issues but usually not quite as large
* of a correctness issue.
*/
private void PruneDuplicatePhysBones(GameObject baseBone, GameObject mergeBone)
{
bool hasSelfReferencePB = false;
foreach (var pb in baseBone.GetComponents<VRCPhysBone>())
{
var target = pb.rootTransform;
if (target == null || target == baseBone.transform)
{
hasSelfReferencePB = true;
break;
}
}
if (!hasSelfReferencePB) return;
foreach (var pb in mergeBone.GetComponents<VRCPhysBone>())
{
var target = pb.rootTransform;
if (target == null || target == baseBone.transform)
{
Object.DestroyImmediate(pb);
}
}
}
}
}