diff --git a/rigify/__init__.py b/rigify/__init__.py index 1b5c2680a..582abbcc3 100644 --- a/rigify/__init__.py +++ b/rigify/__init__.py @@ -567,6 +567,11 @@ def register(): bpy.types.Armature.rigify_finalize_script = PointerProperty(type=bpy.types.Text, name="Finalize Script", description="Run this script after generation to apply user-specific changes") + + bpy.types.Armature.rigify_parent_all_deform_bones = BoolProperty(name="(EXPERIMENTAL)Force Parent All Deform Bones", + description="Force parent all deform bones according to metarig\'s bone hierarchy.", + default=False) + IDStore.rigify_transfer_only_selected = BoolProperty( name="Transfer Only Selected", description="Transfer selected bones only", default=True) @@ -611,6 +616,7 @@ def unregister(): del ArmStore.rigify_force_widget_update del ArmStore.rigify_target_rig del ArmStore.rigify_rig_ui + del ArmStore.rigify_parent_all_deform_bones IDStore = bpy.types.WindowManager del IDStore.rigify_collection diff --git a/rigify/base_rig.py b/rigify/base_rig.py index a1f9e952d..071db8b54 100644 --- a/rigify/base_rig.py +++ b/rigify/base_rig.py @@ -205,6 +205,38 @@ class BaseRig(GenerateCallbackHost, RaiseErrorMixin, BoneUtilityMixin, Mechanism """ return [pose_bone.name] + def filter_derived_deform_bones(self, org_bone): + """ + Returns a filter containing all deforming bones derived from specified org bone. + """ + if not org_bone in self.rigify_derived_bones: + return None + derived_bones = self.rigify_derived_bones[org_bone] + pred = (lambda b: b == self.bones.deform) if type(self.bones.deform) == str else (lambda b: b in self.bones.deform) + return filter(pred, derived_bones) + + def find_most_relevant_parent_deform_bone(self, rig_parent): + """ + Finds a most relevant deform bone derived from specified org bone in parent rig, returns its name, + or returns None if this rig does not have a parent. + + This method raises error if such a bone can not be found(but having a parent rig). + + If there're multiple derived deform bones, the first one is returned. + """ + if not self.rigify_parent: + return None + filtered = self.rigify_parent.filter_derived_deform_bones(rig_parent) + if not filtered: + return None + derived_deform_bones_of_parent = list(filtered) + if len(derived_deform_bones_of_parent) == 0: + self.raise_error("Can not decide parent deform bone of %s" % rig_parent) + if not len(derived_deform_bones_of_parent) == 1: + print('Warn: there\' re multiple deform bones derived from parent: %s. The first one would be used.' % derived_deform_bones_of_parent) + parent_deform_bone = derived_deform_bones_of_parent[0] + return parent_deform_bone + ########################################################### # Parameters and UI diff --git a/rigify/generate.py b/rigify/generate.py index 8a2aa942b..2bd271157 100644 --- a/rigify/generate.py +++ b/rigify/generate.py @@ -451,6 +451,7 @@ class Generator(base_generate.BaseGenerator): obj.data["rig_id"] = self.rig_id self.script = rig_ui_template.ScriptGenerator(self) + self.rigify_parent_all_deform_bones = metarig.data.rigify_parent_all_deform_bones #------------------------------------------ bpy.ops.object.mode_set(mode='OBJECT') diff --git a/rigify/rigs/basic/super_copy.py b/rigify/rigs/basic/super_copy.py index fc4b4d336..9534ce5c3 100644 --- a/rigify/rigs/basic/super_copy.py +++ b/rigify/rigs/basic/super_copy.py @@ -47,7 +47,14 @@ class Rig(BaseRig, RelinkConstraintsMixin): bones = self.bones if self.make_deform: - self.set_bone_parent(bones.deform, bones.org, use_connect=False) + parent_deform_bone = None + if self.generator.rigify_parent_all_deform_bones: + parent_deform_bone = self.find_most_relevant_parent_deform_bone(self.get_bone_parent(bones.org)) + + if parent_deform_bone: + self.set_bone_parent(bones.deform, parent_deform_bone, use_connect=False) + else: + self.set_bone_parent(bones.deform, bones.org, use_connect=False) new_parent = self.relink_bone_parent(bones.org) diff --git a/rigify/rigs/chain_rigs.py b/rigify/rigs/chain_rigs.py index f0aeb1247..bb4474085 100644 --- a/rigify/rigs/chain_rigs.py +++ b/rigify/rigs/chain_rigs.py @@ -102,6 +102,12 @@ class SimpleChainRig(BaseRig): @stage.parent_bones def parent_deform_chain(self): + parent_deform_bone = None + if self.generator.rigify_parent_all_deform_bones: + parent_deform_bone = self.find_most_relevant_parent_deform_bone(self.rig_parent_bone) + + if parent_deform_bone: + self.set_bone_parent(self.bones.deform[0], parent_deform_bone) self.parent_bone_chain(self.bones.deform, use_connect=True) @stage.rig_bones diff --git a/rigify/rigs/limbs/limb_rigs.py b/rigify/rigs/limbs/limb_rigs.py index a094e1767..43a5f6f27 100644 --- a/rigify/rigs/limbs/limb_rigs.py +++ b/rigify/rigs/limbs/limb_rigs.py @@ -863,7 +863,14 @@ class BaseLimbRig(BaseRig): @stage.parent_bones def parent_deform_chain(self): - self.set_bone_parent(self.bones.deform[0], self.rig_parent_bone) + parent_deform_bone = None + if self.generator.rigify_parent_all_deform_bones: + parent_deform_bone = self.find_most_relevant_parent_deform_bone(self.rig_parent_bone) + + if parent_deform_bone: + self.set_bone_parent(self.bones.deform[0], parent_deform_bone) + else: + self.set_bone_parent(self.bones.deform[0], self.rig_parent_bone) self.parent_bone_chain(self.bones.deform, use_connect=True) @stage.rig_bones diff --git a/rigify/ui.py b/rigify/ui.py index 8b719a3f1..3f66a0d97 100644 --- a/rigify/ui.py +++ b/rigify/ui.py @@ -156,6 +156,9 @@ class DATA_PT_rigify_advanced(bpy.types.Panel): col.separator() col.row().prop(armature_id_store, "rigify_finalize_script", text="Run Script") + col.separator() + col.row().prop(armature_id_store, "rigify_parent_all_deform_bones") + class DATA_PT_rigify_samples(bpy.types.Panel): bl_label = "Samples"