[Bf-extensions-cvs] [db3e15be] master: Rigify: implement an optional IK palm pivot control in the arm rig.

Alexander Gavrilov noreply at git.blender.org
Sat Nov 2 10:00:30 CET 2019


Commit: db3e15be7a0f7b403bedb5b762d79e1970a4fc59
Author: Alexander Gavrilov
Date:   Mon Oct 21 18:01:03 2019 +0300
Branches: master
https://developer.blender.org/rBAdb3e15be7a0f7b403bedb5b762d79e1970a4fc59

Rigify: implement an optional IK palm pivot control in the arm rig.

The control itself is simply a pivot around the end of the hand
bone, similar to those in the foot and paw. However, the main
point of it is that it allows future finger IK to use the IK
control as the parent, while still allowing the wrist to be moved
relative to it.

===================================================================

M	rigify/rigs/limbs/arm.py
M	rigify/rigs/limbs/limb_rigs.py
M	rigify/rigs/spines/spine_rigs.py
M	rigify/utils/switch_parent.py

===================================================================

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
 
@@ -67,11 +72,71 @@ class Rig(BaseLimbRig):
     def make_ik_ctrl_widget(self, ctrl):
         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'



More information about the Bf-extensions-cvs mailing list