[Bf-extensions-cvs] [0391f865] master: Rigify: support separate IK and FK controls for the toe.

Alexander Gavrilov noreply at git.blender.org
Sun Jan 9 20:34:59 CET 2022


Commit: 0391f865e12d432ad06050f654a04f259361f123
Author: Alexander Gavrilov
Date:   Tue Jan 4 18:40:07 2022 +0300
Branches: master
https://developer.blender.org/rBA0391f865e12d432ad06050f654a04f259361f123

Rigify: support separate IK and FK controls for the toe.

Currently the leg rig tries to share one control between IK and FK
modes, which looks as a nice optimization at first, but makes it
impossible to IK/FK snap correctly if the IK foot is rolled forward.

This commit adds an option to generate separate toe controls.

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

M	rigify/rigs/limbs/front_paw.py
M	rigify/rigs/limbs/leg.py
M	rigify/rigs/limbs/limb_rigs.py
M	rigify/rigs/limbs/paw.py
M	rigify/rigs/limbs/rear_paw.py

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

diff --git a/rigify/rigs/limbs/front_paw.py b/rigify/rigs/limbs/front_paw.py
index f89ca6c4..83cbbd81 100644
--- a/rigify/rigs/limbs/front_paw.py
+++ b/rigify/rigs/limbs/front_paw.py
@@ -55,10 +55,11 @@ class Rig(pawRig):
         return [self.bones.ctrl.heel]
 
     def get_ik_fk_position_chains(self):
-        ik_chain, fk_chain = super().get_ik_fk_position_chains()
+        ik_chain, tail_chain, fk_chain = super().get_ik_fk_position_chains()
+        assert not tail_chain
         if not self.use_heel2:
             return [*ik_chain, ik_chain[-1]], [*fk_chain, fk_chain[-1]]
-        return ik_chain, fk_chain
+        return ik_chain, tail_chain, fk_chain
 
     def get_extra_ik_controls(self):
         extra = [self.bones.ctrl.heel2] if self.use_heel2 else []
diff --git a/rigify/rigs/limbs/leg.py b/rigify/rigs/limbs/leg.py
index d1b82c15..051c0ec0 100644
--- a/rigify/rigs/limbs/leg.py
+++ b/rigify/rigs/limbs/leg.py
@@ -63,6 +63,11 @@ class Rig(BaseLimbRig):
 
         self.pivot_type = self.params.foot_pivot_type
         self.heel_euler_order = 'ZXY' if self.main_axis == 'x' else 'XZY'
+        self.use_ik_toe = self.params.extra_ik_toe
+
+        if self.use_ik_toe:
+            self.fk_name_suffix_cutoff = 3
+            self.fk_ik_layer_cutoff = 4
 
         assert self.pivot_type in {'ANKLE', 'TOE', 'ANKLE_TOE'}
 
@@ -118,6 +123,9 @@ class Rig(BaseLimbRig):
     ####################################################
     # IK controls
 
+    def get_tail_ik_controls(self):
+        return [self.bones.ctrl.ik_toe] if self.use_ik_toe else []
+
     def get_extra_ik_controls(self):
         controls = super().get_extra_ik_controls() + [self.bones.ctrl.heel]
         if self.pivot_type == 'ANKLE_TOE':
@@ -210,6 +218,31 @@ class Rig(BaseLimbRig):
     def generate_heel_control_widget(self):
         create_ballsocket_widget(self.obj, self.bones.ctrl.heel)
 
+    ####################################################
+    # IK toe control
+
+    @stage.generate_bones
+    def make_ik_toe_control(self):
+        if self.use_ik_toe:
+            self.bones.ctrl.ik_toe = self.make_ik_toe_control_bone(self.bones.org.main[3])
+
+    def make_ik_toe_control_bone(self, org):
+        return self.copy_bone(org, make_derived_name(org, 'ctrl', '_ik'))
+
+    @stage.parent_bones
+    def parent_ik_toe_control(self):
+        if self.use_ik_toe:
+            self.set_bone_parent(self.bones.ctrl.ik_toe, self.bones.mch.heel[2])
+
+    @stage.configure_bones
+    def configure_ik_toe_control(self):
+        if self.use_ik_toe:
+            self.copy_bone_properties(self.bones.org.main[3], self.bones.ctrl.ik_toe)
+
+    @stage.generate_widgets
+    def make_ik_toe_control_widget(self):
+        if self.use_ik_toe:
+            self.make_fk_control_widget(3, self.bones.ctrl.ik_toe)
 
     ####################################################
     # Heel roll MCH
@@ -288,23 +321,26 @@ class Rig(BaseLimbRig):
 
     def parent_fk_parent_bone(self, i, parent_mch, prev_ctrl, org, prev_org):
         if i == 3:
-            align_bone_orientation(self.obj, parent_mch, self.bones.mch.heel[2])
+            if not self.use_ik_toe:
+                align_bone_orientation(self.obj, parent_mch, self.bones.mch.heel[2])
 
-            self.set_bone_parent(parent_mch, prev_org, use_connect=True)
+                self.set_bone_parent(parent_mch, prev_org, use_connect=True)
+            else:
+                self.set_bone_parent(parent_mch, prev_ctrl, use_connect=True, inherit_scale='ALIGNED')
 
         else:
             super().parent_fk_parent_bone(i, parent_mch, prev_ctrl, org, prev_org)
 
     def rig_fk_parent_bone(self, i, parent_mch, org):
         if i == 3:
-            con = self.make_constraint(parent_mch, 'COPY_TRANSFORMS', self.bones.mch.heel[2])
+            if not self.use_ik_toe:
+                con = self.make_constraint(parent_mch, 'COPY_TRANSFORMS', self.bones.mch.heel[2])
 
-            self.make_driver(con, 'influence', variables=[(self.prop_bone, 'IK_FK')], polynomial=[1.0, -1.0])
+                self.make_driver(con, 'influence', variables=[(self.prop_bone, 'IK_FK')], polynomial=[1.0, -1.0])
 
         else:
             super().rig_fk_parent_bone(i, parent_mch, org)
 
-
     ####################################################
     # IK system MCH
 
@@ -340,9 +376,17 @@ class Rig(BaseLimbRig):
             default = 'ANKLE_TOE'
         )
 
+        params.extra_ik_toe = bpy.props.BoolProperty(
+            name='Separate IK Toe',
+            default=False,
+            description="Generate a separate IK toe control for better IK/FK snapping"
+        )
+
+
     @classmethod
     def parameters_ui(self, layout, params):
         layout.prop(params, 'foot_pivot_type')
+        layout.prop(params, 'extra_ik_toe')
 
         super().parameters_ui(layout, params, 'Foot')
 
diff --git a/rigify/rigs/limbs/limb_rigs.py b/rigify/rigs/limbs/limb_rigs.py
index ae854638..2e6fe538 100644
--- a/rigify/rigs/limbs/limb_rigs.py
+++ b/rigify/rigs/limbs/limb_rigs.py
@@ -257,6 +257,7 @@ class BaseLimbRig(BaseRig):
         self.bones.ctrl.fk = map_list(self.make_fk_control_bone, count(0), self.bones.org.main)
 
     fk_name_suffix_cutoff = 2
+    fk_ik_layer_cutoff = 3
 
     def get_fk_name(self, i, org, kind):
         return make_derived_name(org, kind, '_fk' if i <= self.fk_name_suffix_cutoff else '')
@@ -283,8 +284,9 @@ class BaseLimbRig(BaseRig):
         for args in zip(count(0), self.bones.ctrl.fk, self.bones.org.main):
             self.configure_fk_control_bone(*args)
 
-        ControlLayersOption.FK.assign_rig(self, self.bones.ctrl.fk[0:3])
-        ControlLayersOption.FK.assign_rig(self, self.bones.ctrl.fk[3:], combine=True, priority=1)
+        cut = self.fk_ik_layer_cutoff
+        ControlLayersOption.FK.assign_rig(self, self.bones.ctrl.fk[0:cut])
+        ControlLayersOption.FK.assign_rig(self, self.bones.ctrl.fk[cut:], combine=True, priority=1)
 
     def configure_fk_control_bone(self, i, ctrl, org):
         self.copy_bone_properties(org, ctrl)
@@ -352,16 +354,24 @@ class BaseLimbRig(BaseRig):
     def get_middle_ik_controls(self):
         return []
 
+    def get_tail_ik_controls(self):
+        return []
+
     def get_ik_fk_position_chains(self):
         ik_chain = self.get_ik_output_chain()
-        return ik_chain, self.bones.ctrl.fk[0:len(ik_chain)]
+        tail_chain = self.get_tail_ik_controls()
+        return ik_chain, tail_chain, self.bones.ctrl.fk[0:len(ik_chain)+len(tail_chain)]
 
     def get_ik_control_chain(self):
         ctrl = self.bones.ctrl
         return [ctrl.ik_base, ctrl.ik_pole, *self.get_middle_ik_controls(), ctrl.ik]
 
     def get_all_ik_controls(self):
-        return self.get_ik_control_chain() + self.get_extra_ik_controls()
+        return [
+            *self.get_ik_control_chain(),
+            *self.get_tail_ik_controls(),
+            *self.get_extra_ik_controls(),
+        ]
 
     @stage.generate_bones
     def make_ik_controls(self):
@@ -596,22 +606,20 @@ class BaseLimbRig(BaseRig):
 
     def add_global_buttons(self, panel, rig_name):
         ctrl = self.bones.ctrl
-        ik_chain = self.get_ik_output_chain()
-        fk_chain = ctrl.fk[0:len(ik_chain)]
+        ik_chain, tail_chain, fk_chain = self.get_ik_fk_position_chains()
 
         add_generic_snap_fk_to_ik(
             panel,
-            fk_bones=fk_chain, ik_bones=ik_chain,
+            fk_bones=fk_chain, ik_bones=ik_chain+tail_chain,
             ik_ctrl_bones=self.get_all_ik_controls(),
             rig_name=rig_name
         )
 
-        ik_chain, fk_chain = self.get_ik_fk_position_chains()
 
         add_limb_snap_ik_to_fk(
             panel,
             master=ctrl.master,
-            fk_bones=fk_chain, ik_bones=ik_chain,
+            fk_bones=fk_chain, ik_bones=ik_chain, tail_bones=tail_chain,
             ik_ctrl_bones=self.get_ik_control_chain(),
             ik_extra_ctrls=self.get_extra_ik_controls(),
             rig_name=rig_name
@@ -619,7 +627,7 @@ class BaseLimbRig(BaseRig):
 
     def add_ik_only_buttons(self, panel, rig_name):
         ctrl = self.bones.ctrl
-        ik_chain, fk_chain = self.get_ik_fk_position_chains()
+        ik_chain, tail_chain, fk_chain = self.get_ik_fk_position_chains()
 
         add_limb_toggle_pole(
             panel, master=ctrl.master,
@@ -688,7 +696,7 @@ class BaseLimbRig(BaseRig):
 
     @stage.rig_bones
     def rig_org_chain(self):
-        ik = self.get_ik_output_chain()
+        ik = self.get_ik_output_chain() + self.get_tail_ik_controls()
         for args in zip(count(0), self.bones.org.main, self.bones.ctrl.fk, padnone(ik)):
             self.rig_org_bone(*args)
 
@@ -979,6 +987,7 @@ class RigifyLimbIk2FkBase:
     fk_bones:     StringProperty(name="FK Bone Chain")
     ik_bones:     StringProperty(name="IK Result Bone Chain")
     ctrl_bones:   StringProperty(name="IK Controls")
+    tail_bones:   StringProperty(name="Tail IK Controls", default="[]")
     extra_ctrls:  StringProperty(name="Extra IK Controls")
 
     def init_execute(self, context):
@@ -986,6 +995,7 @@ class RigifyLimbIk2FkBase:
             self.fk_bone_list = json.loads(self.fk_bones)
         self.ik_bone_list = json.loads(self.ik_bones)
         self.ctrl_bone_list = json.loads(self.ctrl_bones)
+        self.tail_bone_list = json.loads(self.tail_bones)
         self.extra_ctrl_list = json.loads(self.extra_ctrls)
 
     def get_use_pole(self, obj):
@@ -1016,9 +1026,15 @@ class RigifyLimbIk2FkBase:
             mat = convert_pose_matrix_via_rest_delta(mat, ik, ctrl)
             set_transform_from_matrix(obj, ctrl.name, mat, keyflags=keyflags)
 
-    def apply_frame_state(self, context, obj, matrices):
+    def apply_frame_state(self, context, obj, all_matrices):
         ik_bones = [ obj.pose.bones[k] for k in self.ik_bone_list ]
         ctrl_bones = [ obj.pose.bones[k] for k in self.ctrl_bone_list ]
+        tail_bones = [ obj.pose.bones[k] for k in self.tail_bone_list ]
+
+        assert len(all_matrices) == len(ik_bones) + len(tail_bones)
+
+        matrices = all_matrices[0:len(ik_bones)]
+        tail_matrices = all_matrices[len(ik_bones):]
 
         use_pole = self.get_use_pole(obj)
 
@@ -1055,6 +1071,11 @@ 

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-extensions-cvs mailing list