[Bf-extensions-cvs] [293cc140] master: Rigify: rework limb IK stretch limit and add a manual swing structure.

Alexander Gavrilov noreply at git.blender.org
Wed Oct 27 18:08:44 CEST 2021


Commit: 293cc140f5348ac6382575302d88b2deec37b4a7
Author: Alexander Gavrilov
Date:   Fri Oct 22 22:50:06 2021 +0300
Branches: master
https://developer.blender.org/rBA293cc140f5348ac6382575302d88b2deec37b4a7

Rigify: rework limb IK stretch limit and add a manual swing structure.

After introduction of the Custom space it is possible to easily
use Limit Distance within rigs while accounting for rig scale.
This allows replacing the Stretch To + Limit Scale mechanism
used for the IK stretch switch in rigify.

Instead, use the freed bone to manually handle limb swing before
allowing the actual IK solver to handle limb contraction. This
improves stability in marginal cases of limbs nearly straight
in the rest pose, because previously the solver could destroy
the slight knee bend in the process of swinging the limb forward,
causing a flip.

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

M	rigify/rigs/limbs/limb_rigs.py
M	rigify/rigs/limbs/rear_paw.py

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

diff --git a/rigify/rigs/limbs/limb_rigs.py b/rigify/rigs/limbs/limb_rigs.py
index a5df27f4..1443c9bc 100644
--- a/rigify/rigs/limbs/limb_rigs.py
+++ b/rigify/rigs/limbs/limb_rigs.py
@@ -162,8 +162,8 @@ class BaseLimbRig(BaseRig):
     #     FK chain parents (or None)
     #   ik_pivot
     #     Custom IK pivot result (optional).
-    #   ik_stretch
-    #     IK stretch switch implementation.
+    #   ik_swing
+    #     Bone that tracks ik_target to manually handle limb swing.
     #   ik_target
     #     Corrected target position.
     #   ik_base
@@ -422,7 +422,10 @@ class BaseLimbRig(BaseRig):
 
     @stage.parent_bones
     def parent_ik_controls(self):
-        self.set_bone_parent(self.bones.ctrl.ik_base, self.bones.mch.follow)
+        if self.use_mch_ik_base:
+            self.set_bone_parent(self.bones.ctrl.ik_base, self.bones.mch.follow)
+        else:
+            self.set_bone_parent(self.bones.ctrl.ik_base, self.bones.mch.ik_swing)
 
     @stage.configure_bones
     def configure_ik_controls(self):
@@ -515,16 +518,17 @@ class BaseLimbRig(BaseRig):
         if self.use_mch_ik_base:
             self.bones.mch.ik_base = self.make_ik_mch_base_bone(orgs)
 
-        self.bones.mch.ik_stretch = self.make_ik_mch_stretch_bone(orgs)
+        self.bones.mch.ik_swing = self.make_ik_mch_swing_bone(orgs)
         self.bones.mch.ik_target = self.make_ik_mch_target_bone(orgs)
         self.bones.mch.ik_end = self.copy_bone(orgs[1], make_derived_name(orgs[1], 'mch', '_ik'))
 
     def make_ik_mch_base_bone(self, orgs):
         return self.copy_bone(orgs[0], make_derived_name(orgs[0], 'mch', '_ik'))
 
-    def make_ik_mch_stretch_bone(self, orgs):
-        name = self.copy_bone(orgs[0], make_derived_name(orgs[0], 'mch', '_ik_stretch'))
-        self.get_bone(name).tail = self.get_bone(orgs[2]).head
+    def make_ik_mch_swing_bone(self, orgs):
+        name = self.copy_bone(orgs[0], make_derived_name(orgs[0], 'mch', '_ik_swing'))
+        bone = self.get_bone(name)
+        bone.tail = bone.head + (self.get_bone(orgs[2]).head - bone.head).normalized() * bone.length * 0.3
         return name
 
     def make_ik_mch_target_bone(self, orgs):
@@ -533,8 +537,11 @@ class BaseLimbRig(BaseRig):
     @stage.parent_bones
     def parent_ik_mch_chain(self):
         if self.use_mch_ik_base:
-            self.set_bone_parent(self.bones.mch.ik_base, self.bones.ctrl.ik_base, inherit_scale='AVERAGE')
-        self.set_bone_parent(self.bones.mch.ik_stretch, self.bones.mch.follow)
+            self.set_bone_parent(self.bones.mch.ik_swing, self.bones.ctrl.ik_base, inherit_scale='AVERAGE')
+            self.set_bone_parent(self.bones.mch.ik_base, self.bones.mch.ik_swing)
+        else:
+            self.set_bone_parent(self.bones.mch.ik_swing, self.bones.mch.follow)
+
         self.set_bone_parent(self.bones.mch.ik_target, self.get_ik_input_bone())
         self.set_bone_parent(self.bones.mch.ik_end, self.get_ik_chain_base())
 
@@ -608,26 +615,29 @@ class BaseLimbRig(BaseRig):
         mch = self.bones.mch
         input_bone = self.get_ik_input_bone()
 
-        self.rig_ik_mch_stretch_bones(mch.ik_target, mch.ik_stretch, input_bone, self.ik_input_head_tail, 2)
+        self.make_constraint(mch.ik_swing, 'DAMPED_TRACK', mch.ik_target)
+
+        self.rig_ik_mch_stretch_limit(mch.ik_target, mch.follow, input_bone, self.ik_input_head_tail, 2)
         self.rig_ik_mch_end_bone(mch.ik_end, mch.ik_target, self.bones.ctrl.ik_pole)
 
-    def rig_ik_mch_stretch_bones(self, mch_target, mch_stretch, input_bone, head_tail, org_count, bias=1.035):
+    def rig_ik_mch_stretch_limit(self, mch_target, base_bone, input_bone, head_tail, org_count, bias=1.035):
         # Compute increase in length to fully straighten
         orgs = self.bones.org.main[0:org_count]
-        len_cur = (self.get_bone(orgs[-1]).tail - self.get_bone(orgs[0]).head).length
         len_full = sum(self.get_bone(org).length for org in orgs)
-        len_scale = len_full / len_cur
 
-        # Limited stretch on the stretch bone
-        self.make_constraint(mch_stretch, 'STRETCH_TO', input_bone, head_tail=head_tail, keep_axis='SWING_Y')
+        # Snap the target to the input position
+        self.make_constraint(mch_target, 'COPY_LOCATION', input_bone, head_tail=head_tail)
 
-        con = self.make_constraint(mch_stretch, 'LIMIT_SCALE', min_y=0.0, max_y=len_scale*bias, owner_space='LOCAL')
+        # Limit distance from the base of the limb
+        con = self.make_constraint(
+            mch_target, 'LIMIT_DISTANCE', base_bone,
+            limit_mode='LIMITDIST_INSIDE', distance=len_full*bias,
+            # Use custom space to tolerate rig scaling
+            space='CUSTOM', space_object=self.obj, space_subtarget=self.bones.mch.follow,
+        )
 
         self.make_driver(con, "influence", variables=[(self.prop_bone, 'IK_Stretch')], polynomial=[1.0, -1.0])
 
-        # Snap the target to the end of the stretch bone
-        self.make_constraint(mch_target, 'COPY_LOCATION', mch_stretch, head_tail=1.0)
-
     def rig_ik_mch_end_bone(self, mch_ik, mch_target, ctrl_pole, chain=2):
         con = self.make_constraint(
             mch_ik, 'IK', mch_target, chain_count=chain,
diff --git a/rigify/rigs/limbs/rear_paw.py b/rigify/rigs/limbs/rear_paw.py
index 5c1bf5c8..1292dc2e 100644
--- a/rigify/rigs/limbs/rear_paw.py
+++ b/rigify/rigs/limbs/rear_paw.py
@@ -39,7 +39,7 @@ class Rig(pawRig):
     # EXTRA BONES
     #
     # mch:
-    #   ik2_stretch, ik2_target
+    #   ik2_target
     #     Three bone IK stretch limit
     #   ik2_chain[2]
     #     Second IK system (pre-driving thigh and ik3)
@@ -88,14 +88,8 @@ class Rig(pawRig):
     def make_ik2_mch_stretch(self):
         orgs = self.bones.org.main
 
-        self.bones.mch.ik2_stretch = self.make_ik2_mch_stretch_bone(orgs)
         self.bones.mch.ik2_target = self.make_ik2_mch_target_bone(orgs)
 
-    def make_ik2_mch_stretch_bone(self, orgs):
-        name = self.copy_bone(orgs[0], make_derived_name(orgs[0], 'mch', '_ik2_stretch'))
-        self.get_bone(name).tail = self.get_bone(orgs[3]).head
-        return name
-
     def make_ik2_mch_target_bone(self, orgs):
         return self.copy_bone(orgs[3], make_derived_name(orgs[0], 'mch', '_ik2_target'), scale=1/2)
 
@@ -120,7 +114,6 @@ class Rig(pawRig):
     @stage.parent_bones
     def parent_ik2_mch_chain(self):
         mch = self.bones.mch
-        self.set_bone_parent(mch.ik2_stretch, mch.follow)
         self.set_bone_parent(mch.ik2_target, self.get_ik2_input_bone())
         self.set_bone_parent(mch.ik2_chain[0], self.bones.ctrl.ik_base, inherit_scale='AVERAGE')
         self.parent_bone_chain(mch.ik2_chain, use_connect=True)
@@ -143,7 +136,7 @@ class Rig(pawRig):
         input_bone = self.get_ik2_input_bone()
         head_tail = 1 if self.use_heel2 else 0
 
-        self.rig_ik_mch_stretch_bones(mch.ik2_target, mch.ik2_stretch, input_bone, head_tail, 3)
+        self.rig_ik_mch_stretch_limit(mch.ik2_target, mch.follow, input_bone, head_tail, 3)
         self.rig_ik_mch_end_bone(mch.ik2_chain[-1], mch.ik2_target, self.bones.ctrl.ik_pole)



More information about the Bf-extensions-cvs mailing list