From 56e08513a506f13a06fd83337efb330eb140b5ab Mon Sep 17 00:00:00 2001 From: bd_ Date: Fri, 9 Dec 2022 12:39:39 -0800 Subject: [PATCH] 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. --- .../Editor/MergeArmatureHook.cs | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/Packages/nadena.dev.modular-avatar/Editor/MergeArmatureHook.cs b/Packages/nadena.dev.modular-avatar/Editor/MergeArmatureHook.cs index 035591c1..a4429ae6 100644 --- a/Packages/nadena.dev.modular-avatar/Editor/MergeArmatureHook.cs +++ b/Packages/nadena.dev.modular-avatar/Editor/MergeArmatureHook.cs @@ -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()) + { + var target = pb.rootTransform; + if (target == null || target == baseBone.transform) + { + hasSelfReferencePB = true; + break; + } + } + + if (!hasSelfReferencePB) return; + + foreach (var pb in mergeBone.GetComponents()) + { + var target = pb.rootTransform; + if (target == null || target == baseBone.transform) + { + Object.DestroyImmediate(pb); + } + } + } } } \ No newline at end of file