diff options
author | Lucio Rossi <lucio.rossi75@gmail.com> | 2017-06-01 16:24:01 +0300 |
---|---|---|
committer | Lucio Rossi <lucio.rossi75@gmail.com> | 2017-06-01 16:24:17 +0300 |
commit | 5b1b7b94893a3a873b3d511d8859ab75301f31c6 (patch) | |
tree | fb617c630a19da304dc3249976452753fea60403 /rigify/rigs/limbs/leg.py | |
parent | 21158cf1554e7a224c5ac519143f7cc900ee3c51 (diff) |
Rigify 0.5 general maintenance and bug fixing
Diffstat (limited to 'rigify/rigs/limbs/leg.py')
-rw-r--r-- | rigify/rigs/limbs/leg.py | 344 |
1 files changed, 249 insertions, 95 deletions
diff --git a/rigify/rigs/limbs/leg.py b/rigify/rigs/limbs/leg.py index e60f2c68..c1cd1f06 100644 --- a/rigify/rigs/limbs/leg.py +++ b/rigify/rigs/limbs/leg.py @@ -9,7 +9,7 @@ from ...utils import strip_org, make_deformer_name, create_widget from ...utils import create_circle_widget, create_sphere_widget, create_line_widget from ...utils import MetarigError, make_mechanism_name, org from ...utils import create_limb_widget, connected_children_names -from ...utils import align_bone_y_axis, align_bone_x_axis, align_bone_roll +from ...utils import align_bone_y_axis, align_bone_x_axis, align_bone_z_axis from rna_prop_ui import rna_idprop_ui_prop_get from ..widgets import create_ikarrow_widget from math import trunc, pi @@ -20,13 +20,14 @@ ctrl = '%s' if is_selected( controls ): layout.prop( pose_bones[ ctrl ], '["%s"]') - layout.prop( pose_bones[ ctrl ], '["%s"]') + if '%s' in pose_bones[ctrl].keys(): + layout.prop( pose_bones[ ctrl ], '["%s"]', slider = True ) if '%s' in pose_bones[ctrl].keys(): layout.prop( pose_bones[ ctrl ], '["%s"]', slider = True ) """ -IMPLEMENTATION = True # Include and set True if Rig is just an implementation for a wrapper class - # add_parameters and parameters_ui are unused for implementation classes +IMPLEMENTATION = True # Include and set True if Rig is just an implementation for a wrapper class + # add_parameters and parameters_ui are unused for implementation classes class Rig: @@ -44,6 +45,7 @@ class Rig: self.bbones = params.bbones self.limb_type = params.limb_type self.rot_axis = params.rotation_axis + self.auto_align_extremity = params.auto_align_extremity # Assign values to tweak/FK layers props if opted by user if params.tweak_extra_layers: @@ -56,6 +58,62 @@ class Rig: else: self.fk_layers = None + def orient_org_bones(self): + + bpy.ops.object.mode_set(mode='EDIT') + eb = self.obj.data.edit_bones + + thigh = self.org_bones[0] + org_bones = list( + [thigh] + connected_children_names(self.obj, thigh) + ) # All the provided orgs + + # Get heel bone + heel = '' + for b in self.obj.data.bones[org_bones[2]].children: + if not b.use_connect and not b.children: + heel = b.name + if heel: + org_bones.append(heel) + + org_thigh = eb[org_bones[0]] + org_shin = eb[org_bones[1]] + org_foot = eb[org_bones[2]] + org_toe = eb[org_bones[3]] + org_heel = eb[org_bones[4]] + + foot_projection_on_xy = Vector((org_foot.y_axis[0], org_foot.y_axis[1], 0)) + foot_x = foot_projection_on_xy.cross(Vector((0, 0, -1))).normalized() + + if self.rot_axis != 'automatic': + + # Orient foot and toe + if self.auto_align_extremity: + if self.rot_axis == 'x': + align_bone_x_axis(self.obj, org_foot.name, foot_x) + align_bone_x_axis(self.obj, org_toe.name, -foot_x) + elif self.rot_axis == 'z': + align_bone_z_axis(self.obj, org_foot.name, foot_x) + align_bone_z_axis(self.obj, org_toe.name, -foot_x) + else: + raise MetarigError(message='IK on %s has forbidden rotation axis (Y)' % self.org_bones[0]) + + return + + # Orient thigh and shin bones + chain_y_axis = org_thigh.y_axis + org_shin.y_axis + chain_rot_axis = org_thigh.y_axis.cross(chain_y_axis).normalized() # ik-plane normal axis (rotation) + + align_bone_x_axis(self.obj, org_thigh.name, chain_rot_axis) + align_bone_x_axis(self.obj, org_shin.name, chain_rot_axis) + + # Orient foot and toe + align_bone_x_axis(self.obj, org_foot.name, foot_x) + align_bone_x_axis(self.obj, org_toe.name, -foot_x) + + # Orient heel + align_bone_z_axis(self.obj, org_heel.name, Vector((0, 0, 1))) + def create_parent(self): org_bones = self.org_bones @@ -351,9 +409,9 @@ class Rig: bpy.ops.object.mode_set(mode ='EDIT') eb = self.obj.data.edit_bones - ctrl = get_bone_name( org_bones[0], 'ctrl', 'ik' ) - mch_ik = get_bone_name( org_bones[0], 'mch', 'ik' ) - mch_target = get_bone_name( org_bones[0], 'mch', 'ik_target' ) + ctrl = get_bone_name(org_bones[0], 'ctrl', 'ik') + mch_ik = get_bone_name(org_bones[0], 'mch', 'ik') + mch_target = get_bone_name(org_bones[0], 'mch', 'ik_target') for o, ik in zip( org_bones, [ ctrl, mch_ik, mch_target ] ): bone = copy_bone( self.obj, o, ik ) @@ -371,9 +429,9 @@ class Rig: eb[ mch_str ].tail = eb[ org_bones[-1] ].head # Parenting - eb[ ctrl ].parent = eb[ parent ] - eb[ mch_str ].parent = eb[ parent ] - eb[ mch_ik ].parent = eb[ ctrl ] + eb[ctrl].parent = eb[parent] + eb[mch_str].parent = eb[parent] + eb[mch_ik].parent = eb[ctrl] # Make standard pole target bone pole_name = get_bone_name(org_bones[0], 'ctrl', 'ik_target') @@ -382,17 +440,25 @@ class Rig: lo_vector = eb[org_bones[1]].tail - eb[org_bones[1]].head tot_vector = eb[org_bones[0]].head - eb[org_bones[1]].tail tot_vector.normalize() - elbow_vector = lo_vector.dot(tot_vector)*tot_vector - lo_vector # elbow_vec as regression of lo on tot + elbow_vector = lo_vector.dot(tot_vector)*tot_vector - lo_vector # elbow_vec as rejection of lo on tot elbow_vector.normalize() elbow_vector *= (eb[org_bones[1]].tail - eb[org_bones[0]].head).length - z_vector = eb[org_bones[0]].z_axis + eb[org_bones[1]].z_axis - alfa = elbow_vector.angle(z_vector) + + if self.rot_axis == 'x' or self.rot_axis == 'automatic': + z_vector = eb[org_bones[0]].z_axis + eb[org_bones[1]].z_axis + alfa = elbow_vector.angle(z_vector) + elif self.rot_axis == 'z': + x_vector = eb[org_bones[0]].x_axis + eb[org_bones[1]].x_axis + alfa = elbow_vector.angle(x_vector) if alfa > pi/2: pole_angle = -pi/2 else: pole_angle = pi/2 + if self.rot_axis == 'z': + pole_angle = 0 + eb[pole_target].head = eb[org_bones[0]].tail + elbow_vector eb[pole_target].tail = eb[pole_target].head - elbow_vector/8 eb[pole_target].roll = 0.0 @@ -442,21 +508,28 @@ class Rig: pb[ ctrl ].ik_stretch = 0.1 # IK constraint Rotation locks - for axis in ['x','y','z']: - if axis != self.rot_axis: - setattr( pb[ mch_ik ], 'lock_ik_' + axis, True ) + if self.rot_axis == 'z': + pb[mch_ik].lock_ik_x = True + pb[mch_ik].lock_ik_y = True + else: + pb[mch_ik].lock_ik_y = True + pb[mch_ik].lock_ik_z = True # Locks and Widget - pb[ ctrl ].lock_rotation = True, False, True - create_ikarrow_widget( self.obj, ctrl, bone_transform_name=None ) + pb[ctrl].lock_rotation = True, False, True + if self.rot_axis == 'x' or self.rot_axis == 'automatic': + roll = 0 + else: + roll = pi/2 + create_ikarrow_widget(self.obj, ctrl, bone_transform_name=None, roll=roll) create_sphere_widget(self.obj, pole_target, bone_transform_name=None) create_line_widget(self.obj, vispole) return {'ctrl': {'limb': ctrl, 'ik_target': pole_target}, - 'mch_ik': mch_ik, - 'mch_target': mch_target, - 'mch_str': mch_str, - 'visuals': {'vispole': vispole} + 'mch_ik': mch_ik, + 'mch_target': mch_target, + 'mch_str': mch_str, + 'visuals': {'vispole': vispole} } def create_fk(self, parent): @@ -522,8 +595,8 @@ class Rig: pb_parent = pb[parent] # Create ik/fk switch property - pb_parent['IK/FK'] = 0.0 - prop = rna_idprop_ui_prop_get(pb_parent, 'IK/FK', create=True) + pb_parent['IK_FK'] = 0.0 + prop = rna_idprop_ui_prop_get(pb_parent, 'IK_FK', create=True) prop["min"] = 0.0 prop["max"] = 1.0 prop["soft_min"] = 0.0 @@ -578,12 +651,12 @@ class Rig: pole_target = get_bone_name(org_bones[0], 'ctrl', 'ik_target') # Create IK leg control - ctrl = get_bone_name( org_bones[2], 'ctrl', 'ik' ) - ctrl = copy_bone( self.obj, org_bones[2], ctrl ) + ctrl = get_bone_name(org_bones[2], 'ctrl', 'ik') + ctrl = copy_bone(self.obj, org_bones[2], ctrl) # clear parent (so that rigify will parent to root) - eb[ ctrl ].parent = None - eb[ ctrl ].use_connect = False + eb[ctrl].parent = None + eb[ctrl].use_connect = False # MCH for ik control ctrl_socket = copy_bone(self.obj, org_bones[2], get_bone_name( org_bones[2], 'mch', 'ik_socket')) @@ -616,18 +689,27 @@ class Rig: # Create heel ctrl bone heel = get_bone_name(org_bones[2], 'ctrl', 'heel_ik') - heel = copy_bone( self.obj, org_bones[2], heel ) - # orient_bone( self, eb[ heel ], 'y', 0.5 ) + heel = copy_bone(self.obj, org_bones[2], heel) + ax = eb[org_bones[2]].head - eb[org_bones[2]].tail ax[2] = 0 align_bone_y_axis(self.obj, heel, ax) - align_bone_x_axis(self.obj, heel, eb[org_bones[2]].x_axis) + if self.rot_axis == 'x' or self.rot_axis == 'automatic': + align_bone_x_axis(self.obj, heel, eb[org_bones[2]].x_axis) + elif self.rot_axis == 'z': + align_bone_z_axis(self.obj, heel, eb[org_bones[2]].z_axis) eb[heel].length = eb[org_bones[2]].length / 2 # Reset control position and orientation - l = eb[ctrl].length - orient_bone(self, eb[ctrl], 'y', reverse=True) - eb[ctrl].length = l + if self.rot_axis == 'automatic' or self.auto_align_extremity: + l = eb[ctrl].length + orient_bone(self, eb[ctrl], 'y', reverse=True) + eb[ctrl].length = l + else: + flip_bone(self.obj, ctrl) + eb[ctrl].tail[2] = eb[ctrl].head[2] + eb[ctrl].roll = 0 + # Parent eb[ heel ].use_connect = False @@ -640,32 +722,35 @@ class Rig: # Get the tmp heel (floating unconnected without children) tmp_heel = "" - for b in self.obj.data.bones[ org_bones[2] ].children: + for b in self.obj.data.bones[org_bones[2]].children: if not b.use_connect and not b.children: tmp_heel = b.name # roll1 MCH bone - roll1_mch = get_bone_name( tmp_heel, 'mch', 'roll' ) - roll1_mch = copy_bone( self.obj, org_bones[2], roll1_mch ) + roll1_mch = get_bone_name(tmp_heel, 'mch', 'roll') + roll1_mch = copy_bone(self.obj, org_bones[2], roll1_mch) # clear parent - eb[ roll1_mch ].use_connect = False - eb[ roll1_mch ].parent = None + eb[roll1_mch].use_connect = False + eb[roll1_mch].parent = None - flip_bone( self.obj, roll1_mch ) - align_bone_x_axis(self.obj, roll1_mch, eb[org_bones[2]].x_axis) + flip_bone(self.obj, roll1_mch) + if self.rot_axis == 'x' or self.rot_axis == 'automatic': + align_bone_x_axis(self.obj, roll1_mch, eb[org_bones[2]].x_axis) + elif self.rot_axis == 'z': + align_bone_z_axis(self.obj, roll1_mch, eb[org_bones[2]].z_axis) # Create 2nd roll mch, and two rock mch bones - roll2_mch = get_bone_name( tmp_heel, 'mch', 'roll' ) - roll2_mch = copy_bone( self.obj, org_bones[3], roll2_mch ) + roll2_mch = get_bone_name(tmp_heel, 'mch', 'roll') + roll2_mch = copy_bone(self.obj, org_bones[3], roll2_mch) - eb[ roll2_mch ].use_connect = False - eb[ roll2_mch ].parent = None + eb[roll2_mch].use_connect = False + eb[roll2_mch].parent = None put_bone( self.obj, roll2_mch, - ( eb[ tmp_heel ].head + eb[ tmp_heel ].tail ) / 2 + (eb[tmp_heel].head + eb[tmp_heel].tail) / 2 ) eb[ roll2_mch ].length /= 4 @@ -697,6 +782,22 @@ class Rig: eb[ rock1_mch ].parent = eb[ rock2_mch ] eb[ rock2_mch ].parent = eb[ ctrl ] + # make mch toe bone + toe = '' + foot = eb[self.org_bones[-1]] + for c in foot.children: + if 'org' in c.name.lower() and c.head == foot.tail: + toe = c.name + if not toe: + raise MetarigError.message("Wrong metarig: can't find ORG-<toe>") + + toe_mch = get_bone_name(toe, 'mch') + toe_mch = copy_bone(self.obj, toe, toe_mch) + eb[toe_mch].length /= 3 + eb[toe_mch].parent = eb[self.org_bones[2]] + eb[toe].use_connect = False + eb[toe].parent = eb[toe_mch] + # Constrain rock and roll MCH bones make_constraint( self, roll1_mch, { 'constraint' : 'COPY_ROTATION', @@ -704,32 +805,61 @@ class Rig: 'owner_space' : 'LOCAL', 'target_space' : 'LOCAL' }) - make_constraint( self, roll1_mch, { - 'constraint' : 'LIMIT_ROTATION', - 'use_limit_x' : True, - 'max_x' : math.radians(360), - 'owner_space' : 'LOCAL' - }) - make_constraint( self, roll2_mch, { - 'constraint' : 'COPY_ROTATION', - 'subtarget' : heel, - 'use_y' : False, - 'use_z' : False, - 'invert_x' : True, - 'owner_space' : 'LOCAL', - 'target_space' : 'LOCAL' - }) - make_constraint( self, roll2_mch, { - 'constraint' : 'LIMIT_ROTATION', - 'use_limit_x' : True, - 'max_x' : math.radians(360), - 'owner_space' : 'LOCAL' - }) + + if self.rot_axis == 'x'or self.rot_axis == 'automatic': + make_constraint(self, roll1_mch, { + 'constraint': 'LIMIT_ROTATION', + 'use_limit_x': True, + 'max_x': math.radians(360), + 'owner_space': 'LOCAL' + }) + make_constraint(self, roll2_mch, { + 'constraint': 'COPY_ROTATION', + 'subtarget': heel, + 'use_y': False, + 'use_z': False, + 'invert_x': True, + 'owner_space': 'LOCAL', + 'target_space': 'LOCAL' + }) + make_constraint(self, roll2_mch, { + 'constraint': 'LIMIT_ROTATION', + 'use_limit_x': True, + 'max_x': math.radians(360), + 'owner_space': 'LOCAL' + }) + + elif self.rot_axis == 'z': + make_constraint(self, roll1_mch, { + 'constraint': 'LIMIT_ROTATION', + 'use_limit_z': True, + 'max_z': math.radians(360), + 'owner_space': 'LOCAL' + }) + make_constraint(self, roll2_mch, { + 'constraint': 'COPY_ROTATION', + 'subtarget': heel, + 'use_y': False, + 'use_x': False, + 'invert_z': True, + 'owner_space': 'LOCAL', + 'target_space': 'LOCAL' + }) + make_constraint(self, roll2_mch, { + 'constraint': 'LIMIT_ROTATION', + 'use_limit_z': True, + 'max_z': math.radians(360), + 'owner_space': 'LOCAL' + }) pb = self.obj.pose.bones - for i,b in enumerate([ rock1_mch, rock2_mch ]): - head_tail = pb[b].head - pb[tmp_heel].head - if '.L' in b: + if self.rot_axis == 'x'or self.rot_axis == 'automatic': + ik_rot_axis = pb[org_bones[0]].x_axis + elif self.rot_axis == 'z': + ik_rot_axis = pb[org_bones[0]].z_axis + heel_x_orientation = pb[tmp_heel].y_axis.dot(ik_rot_axis) + for i, b in enumerate([rock1_mch, rock2_mch]): + if heel_x_orientation > 0: if not i: min_y = 0 max_y = math.radians(360) @@ -761,8 +891,8 @@ class Rig: 'owner_space' : 'LOCAL' }) - # Constrain 4th ORG to roll2 MCH bone - make_constraint( self, org_bones[3], { + # Cns toe_mch to MCH roll2 + make_constraint( self, toe_mch, { 'constraint' : 'COPY_TRANSFORMS', 'subtarget' : roll2_mch }) @@ -857,7 +987,10 @@ class Rig: # Create heel ctrl locks pb[heel].lock_location = True, True, True - pb[heel].lock_rotation = False, False, True + if self.rot_axis == 'x'or self.rot_axis == 'automatic': + pb[heel].lock_rotation = False, False, True + elif self.rot_axis == 'z': + pb[heel].lock_rotation = True, False, False pb[heel].lock_scale = True, True, True # Add ballsocket widget to heel @@ -872,7 +1005,14 @@ class Rig: toes = copy_bone(self.obj, org_bones[3], toes) eb[toes].use_connect = False - eb[toes].parent = eb[org_bones[3]] + eb[toes].parent = eb[toe_mch] + + # Constrain 4th ORG to toes + make_constraint(self, org_bones[3], { + 'constraint': 'COPY_TRANSFORMS', + # 'subtarget' : roll2_mch + 'subtarget': toes + }) # Constrain toes def bones make_constraint(self, bones['def'][-2], { @@ -890,7 +1030,7 @@ class Rig: # Find IK/FK switch property pb = self.obj.pose.bones - prop = rna_idprop_ui_prop_get( pb[bones['fk']['ctrl'][-1]], 'IK/FK' ) + prop = rna_idprop_ui_prop_get( pb[bones['fk']['ctrl'][-1]], 'IK_FK' ) # Modify rotation mode for ik and tweak controls pb[bones['ik']['ctrl']['limb']].rotation_mode = 'ZXY' @@ -899,7 +1039,7 @@ class Rig: pb[b].rotation_mode = 'ZXY' # Add driver to limit scale constraint influence - b = org_bones[3] + b = toe_mch drv = pb[b].constraints[-1].driver_add("influence").driver drv.type = 'AVERAGE' @@ -923,6 +1063,7 @@ class Rig: bones['ik']['ctrl']['terminal'] += [toes] bones['ik']['ctrl']['terminal'] += [ heel, ctrl ] + if leg_parent: bones['ik']['mch_foot'] = [ctrl_socket, ctrl_pole_socket, ctrl_root, ctrl_parent] else: @@ -1036,11 +1177,11 @@ class Rig: owner[prop] = True rna_prop = rna_idprop_ui_prop_get(owner, prop, create=True) - rna_prop["min"] = False - rna_prop["max"] = True + rna_prop["min"] = False + rna_prop["max"] = True rna_prop["description"] = prop - drv = ctrl.constraints[ 0 ].driver_add("mute").driver + drv = ctrl.constraints[0].driver_add("mute").driver drv.type = 'AVERAGE' var = drv.variables.new() @@ -1052,8 +1193,8 @@ class Rig: drv_modifier = self.obj.animation_data.drivers[-1].modifiers[0] - drv_modifier.mode = 'POLYNOMIAL' - drv_modifier.poly_order = 1 + drv_modifier.mode = 'POLYNOMIAL' + drv_modifier.poly_order = 1 drv_modifier.coefficients[0] = 1.0 drv_modifier.coefficients[1] = -1.0 @@ -1070,8 +1211,8 @@ class Rig: drv_modifier = self.obj.animation_data.drivers[-1].modifiers[0] - drv_modifier.mode = 'POLYNOMIAL' - drv_modifier.poly_order = 1 + drv_modifier.mode = 'POLYNOMIAL' + drv_modifier.poly_order = 1 drv_modifier.coefficients[0] = 1.0 drv_modifier.coefficients[1] = -1.0 @@ -1114,10 +1255,10 @@ class Rig: if len(ctrl.constraints) > 1: owner[prop] = 0.0 rna_prop = rna_idprop_ui_prop_get(owner, prop, create=True) - rna_prop["min"] = 0.0 - rna_prop["max"] = 1.0 - rna_prop["soft_min"] = 0.0 - rna_prop["soft_max"] = 1.0 + rna_prop["min"] = 0.0 + rna_prop["max"] = 1.0 + rna_prop["soft_min"] = 0.0 + rna_prop["soft_max"] = 1.0 rna_prop["description"] = prop drv = ctrl.constraints[1].driver_add("influence").driver @@ -1154,6 +1295,9 @@ class Rig: bpy.ops.object.mode_set(mode='EDIT') eb = self.obj.data.edit_bones + # Adjust org-bones rotation + self.orient_org_bones() + # Clear parents for org bones for bone in self.org_bones[1:]: eb[bone].use_connect = False @@ -1183,7 +1327,8 @@ class Rig: controls_string = ", ".join(["'" + x + "'" for x in controls]) script = create_script(bones, 'leg') - script += extra_script % (controls_string, bones['main_parent'], 'IK_follow', 'pole_follow', 'root/parent', 'root/parent') + script += extra_script % (controls_string, bones['main_parent'], 'IK_follow', + 'pole_follow', 'pole_follow', 'root/parent', 'root/parent') return [script] @@ -1194,14 +1339,21 @@ def add_parameters(params): """ items = [ - ('x', 'X', ''), - ('y', 'Y', ''), - ('z', 'Z', '') + ('x', 'X manual', ''), + ('z', 'Z manual', ''), + ('automatic', 'Automatic', '') ] + params.rotation_axis = bpy.props.EnumProperty( items = items, name = "Rotation Axis", - default = 'x' + default = 'automatic' + ) + + params.auto_align_extremity = bpy.props.BoolProperty( + name='auto_align_extremity', + default=False, + description="Auto Align Extremity Bone" ) params.segments = bpy.props.IntProperty( @@ -1248,12 +1400,14 @@ def add_parameters(params): def parameters_ui(layout, params): """ Create the ui for the rig parameters.""" - # r = layout.row() - # r.prop(params, "limb_type") - r = layout.row() r.prop(params, "rotation_axis") + if 'auto' not in params.rotation_axis.lower(): + r = layout.row() + text = "Auto align Foot" + r.prop(params, "auto_align_extremity", text=text) + r = layout.row() r.prop(params, "segments") |