Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender-addons.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Gavrilov <angavrilov@gmail.com>2021-10-22 22:50:06 +0300
committerAlexander Gavrilov <angavrilov@gmail.com>2021-10-27 18:55:58 +0300
commit293cc140f5348ac6382575302d88b2deec37b4a7 (patch)
tree24991c8f35028ea662af66e118c0ae260f9a8e21
parent0573bc7daeb1e5fc1e0d0e6a37c5efc043aebb13 (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.py48
-rw-r--r--rigify/rigs/limbs/rear_paw.py11
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)