Prune duplicate PBs on merge armature (#150)

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:39:39 -08:00 committed by GitHub
parent 2ac191555e
commit 56e08513a5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

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);
}
}
}
}
}