diff options
author | Alexander Gavrilov <angavrilov@gmail.com> | 2021-10-22 22:50:06 +0300 |
---|---|---|
committer | Alexander Gavrilov <angavrilov@gmail.com> | 2021-10-27 18:55:58 +0300 |
commit | 293cc140f5348ac6382575302d88b2deec37b4a7 (patch) | |
tree | 24991c8f35028ea662af66e118c0ae260f9a8e21 | |
parent | 0573bc7daeb1e5fc1e0d0e6a37c5efc043aebb13 (diff) |
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.
-rw-r--r-- | rigify/rigs/limbs/limb_rigs.py | 48 | ||||
-rw-r--r-- | rigify/rigs/limbs/rear_paw.py | 11 |
2 files changed, 31 insertions, 28 deletions
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) |