[Bf-extensions-cvs] [c871246f] master: Rigify: support foot IK control bone pivoting around the ankle.

Alexander Gavrilov noreply at git.blender.org
Wed Oct 16 17:29:53 CEST 2019


Commit: c871246f8d4d57953f737696f2199ba65898cffd
Author: Alexander Gavrilov
Date:   Wed Oct 16 18:29:11 2019 +0300
Branches: master
https://developer.blender.org/rBAc871246f8d4d57953f737696f2199ba65898cffd

Rigify: support foot IK control bone pivoting around the ankle.

Allow switching the foot IK control between pivoting around
the base of the toe as before, around the ankle, or ankle with
additional toe pivot. Also rewrite the foot roll mechanism to
use correct Euler orders that match the actual bone hierarchy.

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

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

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

diff --git a/rigify/rigs/limbs/leg.py b/rigify/rigs/limbs/leg.py
index 900af982..309688e3 100644
--- a/rigify/rigs/limbs/leg.py
+++ b/rigify/rigs/limbs/leg.py
@@ -22,13 +22,14 @@ import bpy
 import math
 
 from itertools import count
-from mathutils import Vector
+from mathutils import Vector, Matrix
 
 from ...utils.rig import is_rig_base_bone
 from ...utils.bones import align_chain_x_axis, align_bone_x_axis, align_bone_y_axis, align_bone_z_axis
 from ...utils.bones import align_bone_to_axis, flip_bone, put_bone, align_bone_orientation
 from ...utils.naming import make_derived_name
-from ...utils.misc import map_list
+from ...utils.misc import map_list, matrix_from_axis_roll, matrix_from_axis_pair
+from ...utils.widgets import adjust_widget_transform_mesh
 
 from ..widgets import create_foot_widget, create_ballsocket_widget
 
@@ -62,10 +63,18 @@ class Rig(BaseLimbRig):
 
         super().initialize()
 
+        self.pivot_type = self.params.foot_pivot_type
+        self.heel_euler_order = 'ZXY' if self.main_axis == 'x' else 'XZY'
+
+        assert self.pivot_type in {'ANKLE', 'TOE', 'ANKLE_TOE'}
+
     def prepare_bones(self):
         orgs = self.bones.org.main
+        foot = self.get_bone(orgs[2])
 
-        foot_x = self.vector_without_z(self.get_bone(orgs[2]).y_axis).cross((0, 0, -1))
+        ik_y_axis = (0, 1, 0)
+        foot_y_axis = -self.vector_without_z(foot.y_axis)
+        foot_x = foot_y_axis.cross((0, 0, 1))
 
         if self.params.rotation_axis == 'automatic':
             align_chain_x_axis(self.obj, orgs[0:2])
@@ -84,6 +93,12 @@ class Rig(BaseLimbRig):
                 align_bone_z_axis(self.obj, orgs[2], foot_x)
                 align_bone_z_axis(self.obj, orgs[3], -foot_x)
 
+        else:
+            ik_y_axis = foot_y_axis
+
+        # Orientation of the IK main and roll control bones
+        self.ik_matrix = matrix_from_axis_roll(ik_y_axis, 0)
+        self.roll_matrix = matrix_from_axis_pair(ik_y_axis, foot_x, self.main_axis)
 
     ####################################################
     # EXTRA BONES
@@ -92,6 +107,8 @@ class Rig(BaseLimbRig):
     #   heel:
     #     Heel location marker bone
     # ctrl:
+    #   ik_spin:
+    #     Toe spin control.
     #   heel:
     #     Foot roll control
     # mch:
@@ -104,21 +121,17 @@ class Rig(BaseLimbRig):
     # IK controls
 
     def get_extra_ik_controls(self):
-        return [self.bones.ctrl.heel]
+        if self.pivot_type == 'ANKLE_TOE':
+            return [self.bones.ctrl.heel, self.bones.ctrl.ik_spin]
+        else:
+            return [self.bones.ctrl.heel]
 
     def make_ik_control_bone(self, orgs):
         name = self.copy_bone(orgs[2], make_derived_name(orgs[2], 'ctrl', '_ik'))
-
-        if self.params.rotation_axis == 'automatic' or self.params.auto_align_extremity:
-            align_bone_to_axis(self.obj, name, 'y', flip=True)
-
+        if self.pivot_type == 'TOE':
+            put_bone(self.obj, name, self.get_bone(name).tail, matrix=self.ik_matrix)
         else:
-            flip_bone(self.obj, name)
-
-            bone = self.get_bone(name)
-            bone.tail[2] = bone.head[2]
-            bone.roll = 0
-
+            put_bone(self.obj, name, None, matrix=self.ik_matrix)
         return name
 
     def build_ik_pivot(self, ik_name, **args):
@@ -135,8 +148,42 @@ class Rig(BaseLimbRig):
         pbuilder.register_parent(self, self.bones.org.main[2], exclude_self=True)
 
     def make_ik_ctrl_widget(self, ctrl):
-        create_foot_widget(self.obj, ctrl)
+        obj = create_foot_widget(self.obj, ctrl)
 
+        if self.pivot_type != 'TOE':
+            org = self.get_bone(self.bones.org.main[2])
+            adjust_widget_transform_mesh(obj, Matrix.Translation(org.vector))
+
+    ####################################################
+    # IK pivot controls
+
+    def get_ik_pivot_output(self):
+        if self.pivot_type == 'ANKLE_TOE':
+            return self.bones.ctrl.ik_spin
+        else:
+            return self.get_ik_control_output()
+
+    @stage.generate_bones
+    def make_ik_pivot_controls(self):
+        if self.pivot_type == 'ANKLE_TOE':
+            self.bones.ctrl.ik_spin = self.make_ik_spin_bone(self.bones.org.main)
+
+    def make_ik_spin_bone(self, orgs):
+        name = self.copy_bone(orgs[2], make_derived_name(orgs[2], 'ctrl', '_spin_ik'))
+        put_bone(self.obj, name, self.get_bone(orgs[3]).head, matrix=self.ik_matrix, scale=0.5)
+        return name
+
+    @stage.parent_bones
+    def parent_ik_pivot_controls(self):
+        if self.pivot_type == 'ANKLE_TOE':
+            self.set_bone_parent(self.bones.ctrl.ik_spin, self.get_ik_control_output())
+
+    @stage.generate_widgets
+    def make_ik_spin_control_widget(self):
+        if self.pivot_type == 'ANKLE_TOE':
+            obj = create_ballsocket_widget(self.obj, self.bones.ctrl.ik_spin, size=0.75)
+            rotfix = Matrix.Rotation(math.pi/2, 4, self.main_axis.upper())
+            adjust_widget_transform_mesh(obj, rotfix, local=True)
 
     ####################################################
     # Heel control
@@ -144,25 +191,19 @@ class Rig(BaseLimbRig):
     @stage.generate_bones
     def make_heel_control_bone(self):
         org = self.bones.org.main[2]
-        name = self.copy_bone(org, make_derived_name(org, 'ctrl', '_heel_ik'), scale=1/2)
+        name = self.copy_bone(org, make_derived_name(org, 'ctrl', '_heel_ik'))
+        put_bone(self.obj, name, None, matrix=self.roll_matrix, scale=0.5)
         self.bones.ctrl.heel = name
 
-        self.align_roll_bone(org, name, -self.vector_without_z(self.get_bone(org).vector))
-
     @stage.parent_bones
     def parent_heel_control_bone(self):
-        self.set_bone_parent(self.bones.ctrl.heel, self.get_ik_control_output())
+        self.set_bone_parent(self.bones.ctrl.heel, self.get_ik_pivot_output(), inherit_scale='AVERAGE')
 
     @stage.configure_bones
     def configure_heel_control_bone(self):
         bone = self.get_bone(self.bones.ctrl.heel)
         bone.lock_location = True, True, True
-
-        if self.main_axis == 'x':
-            bone.lock_rotation = False, False, True
-        else:
-            bone.lock_rotation = True, False, False
-
+        bone.rotation_mode = self.heel_euler_order
         bone.lock_scale = True, True, True
 
     @stage.generate_widgets
@@ -181,34 +222,27 @@ class Rig(BaseLimbRig):
     def make_roll_mch_bones(self, foot, toe, heel):
         foot_bone = self.get_bone(foot)
         heel_bone = self.get_bone(heel)
-        axis = -self.vector_without_z(foot_bone.vector)
-
-        roll1 = self.copy_bone(foot, make_derived_name(heel, 'mch', '_roll1'))
 
-        flip_bone(self.obj, roll1)
-        self.align_roll_bone(foot, roll1, -foot_bone.vector)
+        heel_middle = (heel_bone.head + heel_bone.tail) / 2
 
-        roll2 = self.copy_bone(toe, make_derived_name(heel, 'mch', '_roll2'), scale=1/4)
-
-        put_bone(self.obj, roll2, (heel_bone.head + heel_bone.tail) / 2)
-        self.align_roll_bone(foot, roll2, -axis)
+        result = self.copy_bone(foot, make_derived_name(foot, 'mch', '_roll'), scale=0.25)
 
+        roll1 = self.copy_bone(toe, make_derived_name(heel, 'mch', '_roll1'), scale=0.3)
+        roll2 = self.copy_bone(toe, make_derived_name(heel, 'mch', '_roll2'), scale=0.3)
         rock1 = self.copy_bone(heel, make_derived_name(heel, 'mch', '_rock1'))
-
-        align_bone_to_axis(self.obj, rock1, 'y', roll=0, length=heel_bone.length/2, flip=True)
-        align_bone_y_axis(self.obj, rock1, axis)
-
         rock2 = self.copy_bone(heel, make_derived_name(heel, 'mch', '_rock2'))
 
-        align_bone_to_axis(self.obj, rock2, 'y', roll=0, length=heel_bone.length/2)
-        align_bone_y_axis(self.obj, rock2, axis)
+        put_bone(self.obj, roll1, None, matrix=self.roll_matrix)
+        put_bone(self.obj, roll2, heel_middle, matrix=self.roll_matrix)
+        put_bone(self.obj, rock1, heel_bone.tail, matrix=self.roll_matrix, scale=0.5)
+        put_bone(self.obj, rock2, heel_bone.head, matrix=self.roll_matrix, scale=0.5)
 
-        return [ rock2, rock1, roll2, roll1 ]
+        return [ rock2, rock1, roll2, roll1, result ]
 
     @stage.parent_bones
     def parent_roll_mch_chain(self):
         chain = self.bones.mch.heel
-        self.set_bone_parent(chain[0], self.get_ik_control_output())
+        self.set_bone_parent(chain[0], self.get_ik_pivot_output())
         self.parent_bone_chain(chain)
 
     @stage.rig_bones
@@ -216,28 +250,37 @@ class Rig(BaseLimbRig):
         self.rig_roll_mch_bones(self.bones.mch.heel, self.bones.ctrl.heel, self.bones.org.heel)
 
     def rig_roll_mch_bones(self, chain, heel, org_heel):
-        rock2, rock1, roll2, roll1 = chain
+        rock2, rock1, roll2, roll1, result = chain
+
+        # This order is required for correct working of the constraints
+        for bone in chain:
+            self.get_bone(bone).rotation_mode = self.heel_euler_order
 
-        self.make_constraint(roll1, 'COPY_ROTATION', heel, space='LOCAL')
-        self.make_constraint(roll2, 'COPY_ROTATION', heel, space='LOCAL')
+        self.make_constraint(roll1, 'COPY_ROTATION', heel, space='POSE')
 
         if self.main_axis == 'x':
-            self.make_constraint(roll1, 'LIMIT_ROTATION', use_limit_x=True, max_x=DEG_360, space='LOCAL')
-            self.make_constraint(roll2, 'LIMIT_ROTATION', use_limit_xyz=ALL_TRUE, min_x=-DEG_360, space='LOCAL')
+            self.make_constraint(roll2, 'COPY_ROTATION', heel, space='LOCAL', use_xyz=(True, False, False))
+            self.make_constraint(roll2, 'LIMIT_ROTATION', min_x=-DEG_360, space='LOCAL')
         else:
-            self.make_constraint(roll1, 'LIMIT_ROTATION', use_limit_z=True, max_z=DEG_360, space='LOCAL')
-            self.make_constraint(roll2, 'LIMIT_ROTATION', use_limit_xyz=ALL_TRUE, min_z=-DEG_360, space='LOCAL')
+            self.make_constraint(roll2, 'COPY_ROTATION', heel, space='LOCAL', use_xyz=(False, False, True))
+            self.make_constraint(roll2, 'LIMIT_ROTATION', min_z=-DEG_360, space='LOCAL')
 
         direction = self.get_main_axis(self.get_bone(heel)).dot(self.get_bone(org_heel).vector)
 
         if direction < 0:
             rock2, rock1 = rock1, r

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-extensions-cvs mailing list