diff options
Diffstat (limited to 'rigify/rigs/limbs/paw.py')
-rw-r--r-- | rigify/rigs/limbs/paw.py | 246 |
1 files changed, 169 insertions, 77 deletions
diff --git a/rigify/rigs/limbs/paw.py b/rigify/rigs/limbs/paw.py index c01f2f0d..8c79503e 100644 --- a/rigify/rigs/limbs/paw.py +++ b/rigify/rigs/limbs/paw.py @@ -7,6 +7,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_z_axis from rna_prop_ui import rna_idprop_ui_prop_get from ..widgets import create_ikarrow_widget, create_gear_widget from ..widgets import create_foot_widget, create_ballsocket_widget @@ -18,13 +19,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: @@ -42,6 +44,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: @@ -54,6 +57,50 @@ 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 + + org_thigh = eb[org_bones[0]] + org_shin = eb[org_bones[1]] + org_foot = eb[org_bones[2]] + org_toe = eb[org_bones[3]] + + 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, chain_rot_axis) + align_bone_x_axis(self.obj, org_toe.name, chain_rot_axis) + def create_parent(self): org_bones = self.org_bones @@ -308,11 +355,11 @@ class Rig: # Rubber hose drivers pb = self.obj.pose.bones - for i,t in enumerate( tweaks[1:-1] ): + for i, t in enumerate(tweaks[1:-1]): # Create custom property on tweak bone to control rubber hose name = 'rubber_tweak' - if i == trunc( len( tweaks[1:-1] ) / 2 ): + if not (i+1) % self.segments: pb[t][name] = 0.0 else: pb[t][name] = 1.0 @@ -385,17 +432,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 @@ -445,21 +500,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): @@ -528,8 +590,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 @@ -575,7 +637,7 @@ class Rig: # Create IK paw control ctrl = get_bone_name(org_bones[2], 'ctrl', 'ik') - ctrl = copy_bone(self.obj, org_bones[2], ctrl) + ctrl = copy_bone(self.obj, org_bones[3], ctrl) # clear parent (so that rigify will parent to root) eb[ctrl].parent = None @@ -612,7 +674,12 @@ 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 ) + heel = copy_bone(self.obj, org_bones[2], heel) + + 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) # clear parent eb[ heel ].parent = None @@ -628,9 +695,35 @@ class Rig: eb[ bones['ik']['mch_target'] ].use_connect = False # Reset control position and orientation - l = eb[ctrl].length - orient_bone(self, eb[ctrl], 'y', reverse=True) - eb[ctrl].length = eb[org_bones[-1]].length + if self.rot_axis == 'automatic' or self.auto_align_extremity: + orient_bone(self, eb[ctrl], 'y', reverse=True) + else: + flip_bone(self.obj, ctrl) + eb[ctrl].tail[2] = eb[ctrl].head[2] + eb[ctrl].roll = 0 + v = eb[org_bones[-1]].tail - eb[org_bones[-2]].head + eb[ctrl].length = Vector((v[0], v[1], 0)).length + + # make mch toe bone + toes_mch = get_bone_name(org_bones[3], 'mch') + toes_mch = copy_bone(self.obj, org_bones[3], toes_mch) + + eb[toes_mch].use_connect = False + eb[toes_mch].parent = eb[ctrl] + + eb[toes_mch].length /= 4 + + # make mch toe parent bone + toes_mch_parent = get_bone_name(org_bones[3], 'mch', 'parent') + toes_mch_parent = copy_bone(self.obj, org_bones[3], toes_mch_parent) + + eb[toes_mch_parent].use_connect = False + eb[toes_mch_parent].parent = eb[org_bones[2]] + + eb[toes_mch_parent].length /= 2 + + eb[org_bones[3]].use_connect = False + eb[org_bones[3]].parent = eb[toes_mch_parent] # Set up constraints @@ -714,8 +807,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 @@ -723,7 +816,8 @@ class Rig: create_foot_widget(self.obj, ctrl, bone_transform_name=None) # Create heel ctrl locks - pb[ heel ].lock_location = True, True, True + pb[heel].lock_location = True, True, True + pb[heel].lock_scale = True, True, True # Add ballsocket widget to heel create_ballsocket_widget(self.obj, heel, bone_transform_name=None) @@ -736,24 +830,21 @@ class Rig: toes = get_bone_name( org_bones[3], 'ctrl' ) toes = copy_bone( self.obj, org_bones[3], toes ) - eb[ toes ].use_connect = False - eb[ toes ].parent = eb[ org_bones[3] ] - - # Create toes mch bone - toes_mch = get_bone_name( org_bones[3], 'mch' ) - toes_mch = copy_bone( self.obj, org_bones[3], toes_mch ) - - eb[ toes_mch ].use_connect = False - eb[ toes_mch ].parent = eb[ ctrl ] - - eb[ toes_mch ].length /= 4 + eb[toes].use_connect = False + eb[toes].parent = eb[toes_mch_parent] # Constrain 4th ORG to toes MCH bone - make_constraint( self, org_bones[3], { + make_constraint( self, toes_mch_parent, { 'constraint' : 'COPY_TRANSFORMS', 'subtarget' : toes_mch }) + # Constrain 4th ORG to toes MCH bone + make_constraint(self, org_bones[3], { + 'constraint': 'COPY_TRANSFORMS', + 'subtarget': toes + }) + make_constraint( self, bones['def'][-1], { 'constraint' : 'DAMPED_TRACK', 'subtarget' : toes, @@ -766,9 +857,8 @@ class Rig: }) # Find IK/FK switch property - pb = self.obj.pose.bones - #prop = rna_idprop_ui_prop_get( pb[ bones['parent'] ], 'IK/FK' ) - prop = rna_idprop_ui_prop_get(pb[bones['fk']['ctrl'][-1]], 'IK/FK') + pb = self.obj.pose.bones + 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' @@ -777,8 +867,8 @@ class Rig: pb[b].rotation_mode = 'ZXY' # Add driver to limit scale constraint influence - b = org_bones[3] - drv = pb[b].constraints[-1].driver_add("influence").driver + b = toes_mch_parent + drv = pb[b].constraints[-1].driver_add("influence").driver drv.type = 'AVERAGE' var = drv.variables.new() @@ -790,15 +880,15 @@ 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 # Create toe circle widget create_circle_widget(self.obj, toes, radius=0.4, head_tail=0.5) - bones['ik']['ctrl']['terminal'] += [ toes ] + bones['ik']['ctrl']['terminal'] += [toes] bones['ik']['ctrl']['terminal'] += [ heel, ctrl ] @@ -915,11 +1005,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() @@ -931,8 +1021,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 @@ -949,8 +1039,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 @@ -993,10 +1083,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 @@ -1033,6 +1123,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 @@ -1062,7 +1155,8 @@ class Rig: controls_string = ", ".join(["'" + x + "'" for x in controls]) script = create_script(bones, 'paw') - 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] @@ -1072,26 +1166,22 @@ def add_parameters(params): RigifyParameters PropertyGroup """ - # items = [ - # ('arm', 'Arm', ''), - # ('leg', 'Leg', ''), - # ('paw', 'Paw', '') - # ] - # params.limb_type = bpy.props.EnumProperty( - # items = items, - # name = "Limb Type", - # default = 'paw' - # ) - 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( @@ -1138,12 +1228,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 Claw" + r.prop(params, "auto_align_extremity", text=text) + r = layout.row() r.prop(params, "segments") |