From 0f24f76bc870146aec5c0c6fb15daac24c0ae1cc Mon Sep 17 00:00:00 2001 From: Nathan Vegdahl Date: Thu, 24 Feb 2011 02:16:38 +0000 Subject: The leg/foot rig can now rock from side to side. Requires a special metarig setup (not yet added to the default human metarig). --- rigify/rigs/biped/leg/__init__.py | 7 ++ rigify/rigs/biped/leg/deform.py | 8 +-- rigify/rigs/biped/leg/fk.py | 8 +-- rigify/rigs/biped/leg/ik.py | 132 +++++++++++++++++++++++++++----------- rigify/utils.py | 9 +++ 5 files changed, 119 insertions(+), 45 deletions(-) (limited to 'rigify') diff --git a/rigify/rigs/biped/leg/__init__.py b/rigify/rigs/biped/leg/__init__.py index 4c9997bf..65af500a 100644 --- a/rigify/rigs/biped/leg/__init__.py +++ b/rigify/rigs/biped/leg/__init__.py @@ -177,6 +177,13 @@ class Rig: bone.use_connect = True bone.parent = arm.edit_bones[bones['shin']] bones['heel'] = bone.name + bone = arm.edit_bones.new('heel.02') + bone.head[:] = -0.0500, -0.0200, 0.0000 + bone.tail[:] = 0.0500, -0.0200, 0.0000 + bone.roll = 0.0000 + bone.use_connect = False + bone.parent = arm.edit_bones[bones['heel']] + bones['heel.02'] = bone.name bone = arm.edit_bones.new('toe') bone.head[:] = 0.0000, -0.1200, 0.0300 bone.tail[:] = 0.0000, -0.2000, 0.0300 diff --git a/rigify/rigs/biped/leg/deform.py b/rigify/rigs/biped/leg/deform.py index df6c6a60..2f9b2b02 100644 --- a/rigify/rigs/biped/leg/deform.py +++ b/rigify/rigs/biped/leg/deform.py @@ -21,7 +21,7 @@ from math import acos, degrees from mathutils import Vector, Matrix from rigify.utils import MetarigError from rigify.utils import copy_bone, flip_bone, put_bone -from rigify.utils import connected_children_names +from rigify.utils import connected_children_names, has_connected_children from rigify.utils import strip_org, make_mechanism_name, make_deformer_name @@ -94,10 +94,10 @@ class Rig: heel = None for b in self.obj.data.bones[leg_bones[1]].children: if b.use_connect == True: - if len(b.children) == 0: - heel = b.name - else: + if len(b.children) >= 1 and has_connected_children(b): foot = b.name + else: + heel = b.name if foot == None or heel == None: raise MetarigError("RIGIFY ERROR: Bone '%s': incorrect bone configuration for rig type." % (strip_org(bone))) diff --git a/rigify/rigs/biped/leg/fk.py b/rigify/rigs/biped/leg/fk.py index 628798f8..f32fc36d 100644 --- a/rigify/rigs/biped/leg/fk.py +++ b/rigify/rigs/biped/leg/fk.py @@ -21,7 +21,7 @@ import math from mathutils import Vector from rigify.utils import MetarigError from rigify.utils import copy_bone, flip_bone, put_bone -from rigify.utils import connected_children_names +from rigify.utils import connected_children_names, has_connected_children from rigify.utils import strip_org, make_mechanism_name, make_deformer_name from rigify.utils import get_layers from rigify.utils import create_widget, create_limb_widget @@ -54,10 +54,10 @@ class Rig: heel = None for b in self.obj.data.bones[leg_bones[1]].children: if b.use_connect == True: - if len(b.children) == 0: - heel = b.name - else: + if len(b.children) >= 1 and has_connected_children(b): foot = b.name + else: + heel = b.name if foot == None or heel == None: raise MetarigError("RIGIFY ERROR: Bone '%s': incorrect bone configuration for rig type." % (strip_org(bone))) diff --git a/rigify/rigs/biped/leg/ik.py b/rigify/rigs/biped/leg/ik.py index 6dc232df..b2328f4d 100644 --- a/rigify/rigs/biped/leg/ik.py +++ b/rigify/rigs/biped/leg/ik.py @@ -21,7 +21,7 @@ from mathutils import Vector from math import pi, acos from rigify.utils import MetarigError from rigify.utils import copy_bone, flip_bone, put_bone -from rigify.utils import connected_children_names +from rigify.utils import connected_children_names, has_connected_children from rigify.utils import strip_org, make_mechanism_name, insert_before_lr from rigify.utils import get_layers from rigify.utils import create_widget, create_line_widget, create_sphere_widget, create_circle_widget @@ -102,14 +102,19 @@ class Rig: # Get the foot and heel foot = None heel = None + rocker = None for b in self.obj.data.bones[leg_bones[1]].children: if b.use_connect == True: - if len(b.children) == 0: - heel = b.name - else: + if len(b.children) >= 1 and has_connected_children(b): foot = b.name + else: + heel = b.name + if len(b.children) > 0: + rocker = b.children[0].name + if foot == None or heel == None: + print("blah") raise MetarigError("RIGIFY ERROR: Bone '%s': incorrect bone configuration for rig type." % (strip_org(bone))) # Get the toe @@ -122,7 +127,7 @@ class Rig: if toe == None: raise MetarigError("RIGIFY ERROR: Bone '%s': incorrect bone configuration for rig type." % (strip_org(bone))) - self.org_bones = leg_bones + [foot, toe, heel] + self.org_bones = leg_bones + [foot, toe, heel, rocker] # Get rig parameters if params.separate_ik_layers: @@ -140,6 +145,10 @@ class Rig: """ bpy.ops.object.mode_set(mode='EDIT') + make_rocker = False + if self.org_bones[5] is not None: + make_rocker = True + # Create the bones thigh = copy_bone(self.obj, self.org_bones[0], make_mechanism_name(strip_org(insert_before_lr(self.org_bones[0], "_ik")))) shin = copy_bone(self.obj, self.org_bones[1], make_mechanism_name(strip_org(insert_before_lr(self.org_bones[1], "_ik")))) @@ -154,8 +163,12 @@ class Rig: toe_parent_socket2 = copy_bone(self.obj, self.org_bones[2], make_mechanism_name(strip_org(self.org_bones[3] + ".socket2"))) foot_roll = copy_bone(self.obj, self.org_bones[4], strip_org(insert_before_lr(self.org_bones[2], "_roll"))) - roll1 = copy_bone(self.obj, self.org_bones[4], make_mechanism_name(strip_org(self.org_bones[2] + ".roll"))) - roll2 = copy_bone(self.obj, self.org_bones[4], make_mechanism_name(strip_org(self.org_bones[2] + ".roll"))) + roll1 = copy_bone(self.obj, self.org_bones[4], make_mechanism_name(strip_org(self.org_bones[2] + ".roll.01"))) + roll2 = copy_bone(self.obj, self.org_bones[4], make_mechanism_name(strip_org(self.org_bones[2] + ".roll.02"))) + + if make_rocker: + rocker1 = copy_bone(self.obj, self.org_bones[5], make_mechanism_name(strip_org(self.org_bones[2] + ".rocker.01"))) + rocker2 = copy_bone(self.obj, self.org_bones[5], make_mechanism_name(strip_org(self.org_bones[2] + ".rocker.02"))) visfoot = copy_bone(self.obj, self.org_bones[2], "VIS-" + strip_org(insert_before_lr(self.org_bones[2], "_ik"))) vispole = copy_bone(self.obj, self.org_bones[1], "VIS-" + strip_org(insert_before_lr(self.org_bones[0], "_pole"))) @@ -176,6 +189,9 @@ class Rig: foot_roll_e = eb[foot_roll] roll1_e = eb[roll1] roll2_e = eb[roll2] + if make_rocker: + rocker1_e = eb[rocker1] + rocker2_e = eb[rocker2] visfoot_e = eb[visfoot] vispole_e = eb[vispole] @@ -213,6 +229,14 @@ class Rig: vispole_e.use_connect = False vispole_e.parent = None + if make_rocker: + rocker1_e.use_connect = False + rocker2_e.use_connect = False + + roll1_e.parent = rocker2_e + rocker2_e.parent = rocker1_e + rocker1_e.parent = foot_e + # Misc foot_e.use_local_location = False @@ -270,6 +294,14 @@ class Rig: visfoot_e.tail = visfoot_e.head + Vector((0, 0, v1.length / 32)) vispole_e.tail = vispole_e.head + Vector((0, 0, v1.length / 32)) + if make_rocker: + d = toe_e.y_axis.dot(rocker1_e.x_axis) + if d >= 0.0: + flip_bone(self.obj, rocker2) + else: + flip_bone(self.obj, rocker1) + + # Weird alignment issues. Fix. toe_parent_e.head = Vector(org_foot_e.head) toe_parent_e.tail = Vector(org_foot_e.tail) @@ -297,6 +329,9 @@ class Rig: foot_roll_p = pb[foot_roll] roll1_p = pb[roll1] roll2_p = pb[roll2] + if make_rocker: + rocker1_p = pb[rocker1] + rocker2_p = pb[rocker2] toe_p = pb[toe] toe_parent_p = pb[toe_parent] toe_parent_socket1_p = pb[toe_parent_socket1] @@ -314,12 +349,22 @@ class Rig: shin_p.lock_ik_x = True shin_p.lock_ik_y = True - # Foot roll control only rotates on x-axis. + # Foot roll control only rotates on x-axis, or x and y if rocker. foot_roll_p.rotation_mode = 'XYZ' - foot_roll_p.lock_rotation = False, True, True + if make_rocker: + foot_roll_p.lock_rotation = False, False, True + else: + foot_roll_p.lock_rotation = False, True, True foot_roll_p.lock_location = True, True, True foot_roll_p.lock_scale = True, True, True + # roll and rocker bones set to euler rotation + roll1_p.rotation_mode = 'XYZ' + roll2_p.rotation_mode = 'XYZ' + if make_rocker: + rocker1_p.rotation_mode = 'XYZ' + rocker2_p.rotation_mode = 'XYZ' + # Pole target only translates pole_p.lock_location = False, False, False pole_p.lock_rotation = True, True, True @@ -372,34 +417,47 @@ class Rig: mod.coefficients[0] = 1.0 mod.coefficients[1] = -1.0 - # Foot roll constraints - con = roll1_p.constraints.new('COPY_ROTATION') - con.name = "roll" - con.target = self.obj - con.subtarget = foot_roll - con.target_space = 'LOCAL' - con.owner_space = 'LOCAL' - - con = roll1_p.constraints.new('LIMIT_ROTATION') - con.name = "limit_roll" - con.use_limit_x = True - con.min_x = -180 - con.max_x = 0 - con.owner_space = 'LOCAL' - - con = roll2_p.constraints.new('COPY_ROTATION') - con.name = "roll" - con.target = self.obj - con.subtarget = foot_roll - con.target_space = 'LOCAL' - con.owner_space = 'LOCAL' - - con = roll2_p.constraints.new('LIMIT_ROTATION') - con.name = "limit_roll" - con.use_limit_x = True - con.min_x = 0 - con.max_x = 180 - con.owner_space = 'LOCAL' + # Foot roll drivers + fcurve = roll1_p.driver_add("rotation_euler", 0) + driver = fcurve.driver + var = driver.variables.new() + driver.type = 'SCRIPTED' + driver.expression = "min(0,var)" + var.name = "var" + var.targets[0].id_type = 'OBJECT' + var.targets[0].id = self.obj + var.targets[0].data_path = foot_roll_p.path_from_id() + '.rotation_euler[0]' + + fcurve = roll2_p.driver_add("rotation_euler", 0) + driver = fcurve.driver + var = driver.variables.new() + driver.type = 'SCRIPTED' + driver.expression = "max(0,var)" + var.name = "var" + var.targets[0].id_type = 'OBJECT' + var.targets[0].id = self.obj + var.targets[0].data_path = foot_roll_p.path_from_id() + '.rotation_euler[0]' + + if make_rocker: + fcurve = rocker1_p.driver_add("rotation_euler", 0) + driver = fcurve.driver + var = driver.variables.new() + driver.type = 'SCRIPTED' + driver.expression = "max(0,-var)" + var.name = "var" + var.targets[0].id_type = 'OBJECT' + var.targets[0].id = self.obj + var.targets[0].data_path = foot_roll_p.path_from_id() + '.rotation_euler[1]' + + fcurve = rocker2_p.driver_add("rotation_euler", 0) + driver = fcurve.driver + var = driver.variables.new() + driver.type = 'SCRIPTED' + driver.expression = "max(0,var)" + var.name = "var" + var.targets[0].id_type = 'OBJECT' + var.targets[0].id = self.obj + var.targets[0].data_path = foot_roll_p.path_from_id() + '.rotation_euler[1]' # Constrain org bones to controls con = pb[self.org_bones[0]].constraints.new('COPY_TRANSFORMS') diff --git a/rigify/utils.py b/rigify/utils.py index f0a19aac..f7a33c22 100644 --- a/rigify/utils.py +++ b/rigify/utils.py @@ -385,6 +385,15 @@ def connected_children_names(obj, bone_name): return names +def has_connected_children(bone): + """ Returns true/false whether a bone has connected children or not. + """ + t = False + for b in bone.children: + t = t or b.use_connect + return t + + def get_layers(layers): """ Does it's best to exctract a set of layers from any data thrown at it. """ -- cgit v1.2.3