diff options
-rw-r--r-- | rigify/rigs/limbs/arm.py | 67 | ||||
-rw-r--r-- | rigify/rigs/limbs/limb_rigs.py | 4 | ||||
-rw-r--r-- | rigify/rigs/spines/spine_rigs.py | 3 | ||||
-rw-r--r-- | rigify/utils/switch_parent.py | 45 |
4 files changed, 106 insertions, 13 deletions
diff --git a/rigify/rigs/limbs/arm.py b/rigify/rigs/limbs/arm.py index 1ac979d0..0eced859 100644 --- a/rigify/rigs/limbs/arm.py +++ b/rigify/rigs/limbs/arm.py @@ -21,12 +21,15 @@ import bpy from itertools import count +from mathutils import Matrix -from ...utils.bones import BoneDict, compute_chain_x_axis, align_bone_x_axis, align_bone_z_axis +from ...utils.bones import put_bone, compute_chain_x_axis, align_bone_x_axis, align_bone_z_axis from ...utils.naming import make_derived_name from ...utils.misc import map_list +from ...utils.widgets import adjust_widget_transform_mesh from ..widgets import create_hand_widget +from ...utils.widgets_basic import create_circle_widget from ...base_rig import stage @@ -42,6 +45,8 @@ class Rig(BaseLimbRig): super().initialize() + self.make_palm_pivot = self.params.make_ik_palm_pivot + def prepare_bones(self): orgs = self.bones.org.main @@ -68,10 +73,70 @@ class Rig(BaseLimbRig): create_hand_widget(self.obj, ctrl) #################################################### + # Palm Pivot + + def get_ik_input_bone(self): + if self.make_palm_pivot: + return self.bones.mch.ik_palm + else: + return self.get_ik_control_output() + + def get_extra_ik_controls(self): + controls = super().get_extra_ik_controls() + if self.make_palm_pivot: + controls += [self.bones.ctrl.ik_palm] + return controls + + @stage.generate_bones + def make_palm_pivot_control(self): + if self.make_palm_pivot: + org = self.bones.org.main[2] + self.bones.ctrl.ik_palm = self.make_palm_pivot_bone(org) + self.bones.mch.ik_palm = self.copy_bone(org, make_derived_name(org, 'mch'), scale=0.25) + + def make_palm_pivot_bone(self, org): + name = self.copy_bone(org, make_derived_name(org, 'ctrl', '_ik_palm'), scale=0.5) + put_bone(self.obj, name, self.get_bone(org).tail) + return name + + @stage.parent_bones + def parent_palm_pivot_control(self): + if self.make_palm_pivot: + ctrl = self.bones.ctrl.ik_palm + self.set_bone_parent(ctrl, self.get_ik_control_output()) + self.set_bone_parent(self.bones.mch.ik_palm, ctrl) + + @stage.generate_widgets + def make_palm_pivot_widget(self): + if self.make_palm_pivot: + ctrl = self.bones.ctrl.ik_palm + + if self.main_axis == 'x': + obj = create_circle_widget(self.obj, ctrl, head_tail=-0.3, head_tail_x=0.5) + else: + obj = create_circle_widget(self.obj, ctrl, head_tail=0.5, head_tail_x=-0.3) + + if obj: + org_bone = self.get_bone(self.bones.org.main[2]) + offset = org_bone.head - self.get_bone(ctrl).head + adjust_widget_transform_mesh(obj, Matrix.Translation(offset)) + + #################################################### # Settings @classmethod + def add_parameters(self, params): + super().add_parameters(params) + + params.make_ik_palm_pivot = bpy.props.BoolProperty( + name="IK Palm Pivot", default=False, + description="Make an extra IK hand control pivoting around the tip of the hand" + ) + + @classmethod def parameters_ui(self, layout, params): + layout.prop(params, "make_ik_palm_pivot") + super().parameters_ui(layout, params, 'Hand') diff --git a/rigify/rigs/limbs/limb_rigs.py b/rigify/rigs/limbs/limb_rigs.py index e09dfb7b..b68fbdd0 100644 --- a/rigify/rigs/limbs/limb_rigs.py +++ b/rigify/rigs/limbs/limb_rigs.py @@ -376,8 +376,8 @@ class BaseLimbRig(BaseRig): pbuilder.register_parent(self, self.rig_parent_bone) pbuilder.register_parent( - self, self.get_ik_control_output(), name=self.bones.ctrl.ik, - exclude_self=True, tags={'limb_ik'}, + self, self.get_ik_control_output, name=self.bones.ctrl.ik, + exclude_self=True, tags={'limb_ik', 'child'}, ) def build_ik_parent_switch(self, pbuilder): diff --git a/rigify/rigs/spines/spine_rigs.py b/rigify/rigs/spines/spine_rigs.py index 25450717..070a6bd3 100644 --- a/rigify/rigs/spines/spine_rigs.py +++ b/rigify/rigs/spines/spine_rigs.py @@ -99,7 +99,8 @@ class BaseSpineRig(TweakChainRig): org_parent = self.get_bone_parent(self.bones.org[0]) parents = [org_parent] if org_parent else [] - pbuilder.register_parent(self, self.get_master_control_output, name='Torso', tags={'torso'}) + pbuilder.register_parent(self, self.get_master_control_output, name='Torso', tags={'torso', 'child'}) + pbuilder.build_child( self, master_name, exclude_self=True, extra_parents=parents, select_parent=org_parent, diff --git a/rigify/utils/switch_parent.py b/rigify/utils/switch_parent.py index bb2d9045..8247a7c8 100644 --- a/rigify/utils/switch_parent.py +++ b/rigify/utils/switch_parent.py @@ -96,6 +96,8 @@ class SwitchParentBuilder(GeneratorPlugin, MechanismUtilityMixin): ignore_global Ignore the is_global flag of potential parents. exclude_self Ignore parents registered by the rig itself. context_rig Rig to use for selecting parents. + no_implicit Only use parents listed as extra_parents. + only_selected Like no_implicit, but allow the 'default' selected parent. prop_bone Name of the bone to add the property to. prop_id Actual name of the control property. @@ -159,6 +161,7 @@ class SwitchParentBuilder(GeneratorPlugin, MechanismUtilityMixin): 'prop_bone': None, 'prop_id': None, 'prop_name': None, 'controls': None, 'select_parent': None, 'ignore_global': False, 'exclude_self': False, 'context_rig': None, 'select_tags': None, + 'no_implicit': False, 'only_selected': False, 'ctrl_bone': None, 'no_fix_location': False, 'no_fix_rotation': False, 'no_fix_scale': False, 'copy_location': None, 'copy_rotation': None, 'copy_scale': None, @@ -255,33 +258,57 @@ class SwitchParentBuilder(GeneratorPlugin, MechanismUtilityMixin): parent_tags[parent['bone']] |= parent['tags'] last_main_parent_bone = child['parents'][-1]['bone'] - num_main_parents = len(parent_map.items()) + extra_parents = set() for parent in force_lazy(child['extra_parents'] or []): if not isinstance(parent, tuple): parent = (parent, None) + extra_parents.add(parent[0]) if parent[0] not in parent_map: parent_map[parent[0]] = parent[1] + for parent in parent_map: + if parent in self.child_map: + parent_tags[parent] |= {'child'} + parent_bones = list(parent_map.items()) - child['parent_bones'] = parent_bones # Find which bone to select select_bone = force_lazy(child['select_parent']) or last_main_parent_bone select_tags = force_lazy(child['select_tags']) or [] - select_index = num_main_parents - try: - select_index = 1 + next(i for i, (bone, _) in enumerate(parent_bones) if bone == select_bone) - except StopIteration: - print("RIGIFY ERROR: Can't find bone '%s' to select as default parent of '%s'\n" % (select_bone, bone)) + if child['no_implicit']: + assert len(extra_parents) > 0 + parent_bones = [ item for item in parent_bones if item[0] in extra_parents ] + if last_main_parent_bone not in extra_parents: + last_main_parent_bone = parent_bones[-1][0] for tag in select_tags: - matching = [ i for i, (bone, _) in enumerate(parent_bones) if tag in parent_tags[bone] ] + tag_set = tag if isinstance(tag, set) else {tag} + matching = [ + bone for (bone, _) in parent_bones + if not tag_set.isdisjoint(parent_tags[bone]) + ] if len(matching) > 0: - select_index = 1 + matching[-1] + select_bone = matching[-1] break + if select_bone not in parent_map: + print("RIGIFY ERROR: Can't find bone '%s' to select as default parent of '%s'\n" % (select_bone, bone)) + select_bone = last_main_parent_bone + + if child['only_selected']: + filter_set = { select_bone, *extra_parents } + parent_bones = [ item for item in parent_bones if item[0] in filter_set ] + + try: + select_index = 1 + next(i for i, (bone, _) in enumerate(parent_bones) if bone == select_bone) + except StopIteration: + select_index = len(parent_bones) + print("RIGIFY ERROR: Invalid default parent '%s' of '%s'\n" % (select_bone, bone)) + + child['parent_bones'] = parent_bones + # Create the controlling property prop_bone = child['prop_bone'] = force_lazy(child['prop_bone']) or bone prop_name = child['prop_name'] or child['prop_id'] or 'Parent Switch' |