diff --git a/rigify/generate.py b/rigify/generate.py index f86d5eb9bde1d806e4e5683e4db582f8e6ca9a74..66971a7e29578a7a7e974b8c83478d473112a7fe 100644 --- a/rigify/generate.py +++ b/rigify/generate.py @@ -39,6 +39,7 @@ ORG_LAYER = [n == 31 for n in range(0, 32)] # Armature layer that original bone MCH_LAYER = [n == 30 for n in range(0, 32)] # Armature layer that mechanism bones should be moved to. DEF_LAYER = [n == 29 for n in range(0, 32)] # Armature layer that deformation bones should be moved to. ROOT_LAYER = [n == 28 for n in range(0, 32)] # Armature layer that root bone should be moved to. +WGT_LAYERS = [x == 19 for x in range(0, 20)] # Widgets go on the last scene layer. class Timer: @@ -252,8 +253,11 @@ def generate_rig(context, metarig): # Create the root bone. bpy.ops.object.mode_set(mode='EDIT') root_bone = new_bone(obj, ROOT_NAME) + spread = get_xy_spread(metarig.data.bones) or metarig.data.bones[0].length + spread = float('%.3g' % spread) + scale = spread/0.589 obj.data.edit_bones[root_bone].head = (0, 0, 0) - obj.data.edit_bones[root_bone].tail = (0, 1, 0) + obj.data.edit_bones[root_bone].tail = (0, scale, 0) obj.data.edit_bones[root_bone].roll = 0 bpy.ops.object.mode_set(mode='OBJECT') obj.data.bones[root_bone].layers = ROOT_LAYER @@ -273,6 +277,7 @@ def generate_rig(context, metarig): mesh = bpy.data.meshes.new(wgts_group_name) wgts_obj = bpy.data.objects.new(wgts_group_name, mesh) scene.objects.link(wgts_obj) + wgts_obj.layers = WGT_LAYERS t.tick("Create main WGTS: ") #---------------------------------- @@ -443,6 +448,19 @@ def generate_rig(context, metarig): # Create Bone Groups create_bone_groups(obj, metarig) + # Add rig_ui to logic + skip = False + ctrls = obj.game.controllers + for c in ctrls: + if 'Python' in c.name and c.text.name == 'rig_ui.py': + skip = True + break + if not skip: + bpy.ops.logic.controller_add(type='PYTHON', object=obj.name) + ctrl = obj.game.controllers[-1] + ctrl.text = bpy.data.texts['rig_ui.py'] + + t.tick("The rest: ") #---------------------------------- # Deconfigure @@ -549,6 +567,16 @@ def get_bone_rigs(obj, bone_name, halt_on_missing=False): return rigs +def get_xy_spread(bones): + x_max = 0 + y_max = 0 + for b in bones: + x_max = max((x_max, abs(b.head[0]), abs(b.tail[0]))) + y_max = max((y_max, abs(b.head[1]), abs(b.tail[1]))) + + return max((x_max, y_max)) + + def param_matches_type(param_name, rig_type): """ Returns True if the parameter name is consistent with the rig type. """ diff --git a/rigify/legacy/utils.py b/rigify/legacy/utils.py index 65838b7d751c85cb9d10b41b436d6bb0c9b9f51b..c718f146069756292d4fe5daef7118afcb298d7d 100644 --- a/rigify/legacy/utils.py +++ b/rigify/legacy/utils.py @@ -151,7 +151,7 @@ def copy_bone_simple(obj, bone_name, assign_name=''): edit_bone_1 = obj.data.edit_bones[bone_name] edit_bone_2 = obj.data.edit_bones.new(assign_name) bone_name_1 = bone_name - bone_name_2 = edit_bone_2.name + bone_name_2 = edit_bone_2.name # Copy edit bone attributes edit_bone_2.layers = list(edit_bone_1.layers) diff --git a/rigify/metarigs/human.py b/rigify/metarigs/human.py index 4c13644141e46b1c3f1550e48a3fb908063d6530..c641fdbf9991d7177e0c108ee5ff23c59f3a3408 100644 --- a/rigify/metarigs/human.py +++ b/rigify/metarigs/human.py @@ -1191,10 +1191,7 @@ def create(obj): pbone.lock_scale = (False, False, False) pbone.rotation_mode = 'QUATERNION' pbone.bone.layers = [False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] - try: - pbone.rigify_parameters.chain_bone_controls = "1, 2, 3" - except AttributeError: - pass + try: pbone.rigify_parameters.neck_pos = 5 except AttributeError: diff --git a/rigify/rigs/limbs/arm.py b/rigify/rigs/limbs/arm.py index 1a560c46a5e3605f7b8e540c8da85a2477b14181..e7e08c418664c73414bd77a8f49a7f949ca73bfd 100644 --- a/rigify/rigs/limbs/arm.py +++ b/rigify/rigs/limbs/arm.py @@ -1,17 +1,17 @@ import bpy, re from ..widgets import create_hand_widget, create_gear_widget -from .ui import create_script -from .limb_utils import * -from mathutils import Vector -from ...utils import copy_bone, flip_bone, put_bone, create_cube_widget -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 -from rna_prop_ui import rna_idprop_ui_prop_get -from ..widgets import create_ikarrow_widget -from math import trunc, pi +from .ui import create_script +from .limb_utils import * +from mathutils import Vector +from ...utils import copy_bone, flip_bone, put_bone, create_cube_widget +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 +from math import trunc, pi extra_script = """ controls = [%s] @@ -19,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: @@ -43,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: @@ -55,6 +57,36 @@ 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_uarm = eb[org_bones[0]] + org_farm = eb[org_bones[1]] + org_hand = eb[org_bones[2]] + + if self.rot_axis != 'automatic': + if self.auto_align_extremity: + z_ground_projection = Vector((org_hand.z_axis[0], org_hand.z_axis[1], 0)) + align_bone_z_axis(self.obj, org_hand.name, z_ground_projection.normalized()) + return + + # Orient uarm farm bones + chain_y_axis = org_uarm.y_axis + org_farm.y_axis + chain_rot_axis = org_uarm.y_axis.cross(chain_y_axis).normalized() # ik-plane normal axis (rotation) + + align_bone_x_axis(self.obj, org_uarm.name, chain_rot_axis) + align_bone_x_axis(self.obj, org_farm.name, chain_rot_axis) + + # Orient hand + align_bone_x_axis(self.obj, org_hand.name, chain_rot_axis) + def create_parent(self): org_bones = self.org_bones @@ -350,9 +382,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 ) @@ -370,9 +402,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') @@ -381,17 +413,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 @@ -441,21 +481,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): @@ -521,8 +568,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 @@ -567,8 +614,8 @@ class Rig: 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 # Parent eb[ bones['ik']['mch_target'] ].parent = eb[ ctrl ] @@ -939,6 +986,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 @@ -968,7 +1018,8 @@ class Rig: controls_string = ", ".join(["'" + x + "'" for x in controls]) script = create_script(bones, 'arm') - 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] @@ -979,14 +1030,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.BoolProperty( + name='auto_align_extremity', + default=False, + description="Auto Align Extremity Bone" ) params.segments = bpy.props.IntProperty( @@ -1033,12 +1091,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 Hand" + r.prop(params, "auto_align_extremity", text=text) + r = layout.row() r.prop(params, "segments") diff --git a/rigify/rigs/limbs/leg.py b/rigify/rigs/limbs/leg.py index e60f2c683a4902d31f18453033874924c60a4505..c1cd1f06fd28c4fc695ab6b0a0cb93fe909c03b1 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") diff --git a/rigify/rigs/limbs/paw.py b/rigify/rigs/limbs/paw.py index c01f2f0db828e94fd479d78e0a920a6e28274821..8c79503ecc3de1dd853da7c6469c909685b0e325 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") diff --git a/rigify/rigs/limbs/rear_paw.py b/rigify/rigs/limbs/rear_paw.py index 462143f65e95a9508caf165c4726ebb07033a3e3..015ede83f4eb3bd8b96714e576e0813773645f0d 100644 --- a/rigify/rigs/limbs/rear_paw.py +++ b/rigify/rigs/limbs/rear_paw.py @@ -4,8 +4,8 @@ from .paw import Rig as pawRig from .paw import parameters_ui from .paw import add_parameters -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(pawRig): diff --git a/rigify/rigs/limbs/super_limb.py b/rigify/rigs/limbs/super_limb.py index 8400ea248119f194da93aab552fa9de87dafb54c..08bb026836365d0841fc939b91019b227d975c83 100644 --- a/rigify/rigs/limbs/super_limb.py +++ b/rigify/rigs/limbs/super_limb.py @@ -34,6 +34,7 @@ def add_parameters(params): ('leg', 'Leg', ''), ('paw', 'Paw', '') ] + params.limb_type = bpy.props.EnumProperty( items = items, name = "Limb Type", @@ -41,14 +42,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( @@ -97,10 +105,16 @@ def parameters_ui(layout, params): 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() + etremities = {'arm': 'Hand', 'leg': 'Foot', 'paw': 'Claw'} + text = "Auto align " + etremities[params.limb_type] + r.prop(params, "auto_align_extremity", text=text) + r = layout.row() r.prop(params, "segments") diff --git a/rigify/rigs/limbs/ui.py b/rigify/rigs/limbs/ui.py index 948b57199337e2fce45d961c740e0444c5e5b86a..aca798b0286bd53231fb82be301c87b293392c3a 100644 --- a/rigify/rigs/limbs/ui.py +++ b/rigify/rigs/limbs/ui.py @@ -126,7 +126,7 @@ def create_script( bones, limb_type=None): bones['main_parent'], bones['fk']['ctrl'][-1], pole, - 'IK/FK', + 'IK_FK', 'rubber_tweak', 'IK_Stretch', 'pole_vector', @@ -142,7 +142,7 @@ def create_script( bones, limb_type=None): bones['main_parent'], bones['fk']['ctrl'][-1], pole, - 'IK/FK', + 'IK_FK', 'rubber_tweak', 'IK_Stretch', 'pole_vector', @@ -158,7 +158,7 @@ def create_script( bones, limb_type=None): bones['main_parent'], bones['fk']['ctrl'][-1], pole, - 'IK/FK', + 'IK_FK', 'rubber_tweak', 'IK_Stretch', 'pole_vector', diff --git a/rigify/rigs/spines/super_spine.py b/rigify/rigs/spines/super_spine.py index 832a506a211930eaad14475f6714aa4fe3e0aa78..a79a3e891dd0ea7f2727f986a944f0a59e8fcb6a 100644 --- a/rigify/rigs/spines/super_spine.py +++ b/rigify/rigs/spines/super_spine.py @@ -1181,10 +1181,7 @@ def create_sample(obj): pbone.lock_rotation_w = False pbone.lock_scale = (False, False, False) pbone.rotation_mode = 'QUATERNION' - try: - pbone.rigify_parameters.chain_bone_controls = "1, 2, 3" - except AttributeError: - pass + try: pbone.rigify_parameters.neck_pos = 5 except AttributeError: diff --git a/rigify/rigs/widgets.py b/rigify/rigs/widgets.py index 0d3e9305a4d2e6604221a04fe8456f597dbfb950..b7e71195e8971e2e99c36eaaebf50f0a21a79c24 100644 --- a/rigify/rigs/widgets.py +++ b/rigify/rigs/widgets.py @@ -1,6 +1,7 @@ import bpy import importlib import importlib +from mathutils import Matrix from ..utils import create_widget WGT_LAYERS = [x == 19 for x in range(0, 20)] # Widgets go on the last scene layer. @@ -97,7 +98,7 @@ def create_face_widget(rig, bone_name, size=1.0, bone_transform_name=None): return None -def create_ikarrow_widget(rig, bone_name, size=1.0, bone_transform_name=None): +def create_ikarrow_widget(rig, bone_name, size=1.0, bone_transform_name=None, roll=0): obj = create_widget(rig, bone_name, bone_transform_name) if obj is not None: verts = [(0.10000000149011612*size, 0.0*size, -0.30000001192092896*size), (0.10000000149011612*size, 0.699999988079071*size, -0.30000001192092896*size), (-0.10000000149011612*size, 0.0*size, -0.30000001192092896*size), (-0.10000000149011612*size, 0.699999988079071*size, -0.30000001192092896*size), (0.20000000298023224*size, 0.699999988079071*size, -0.30000001192092896*size), (0.0*size, 1.0*size, -0.30000001192092896*size), (-0.20000000298023224*size, 0.699999988079071*size, -0.30000001192092896*size), (0.10000000149011612*size, 0.0*size, 0.30000001192092896*size), (0.10000000149011612*size, 0.699999988079071*size, 0.30000001192092896*size), (-0.10000000149011612*size, 0.0*size, 0.30000001192092896*size), (-0.10000000149011612*size, 0.699999988079071*size, 0.30000001192092896*size), (0.20000000298023224*size, 0.699999988079071*size, 0.30000001192092896*size), (0.0*size, 1.0*size, 0.30000001192092896*size), (-0.20000000298023224*size, 0.699999988079071*size, 0.30000001192092896*size), ] @@ -107,6 +108,10 @@ def create_ikarrow_widget(rig, bone_name, size=1.0, bone_transform_name=None): mesh = obj.data mesh.from_pydata(verts, edges, faces) mesh.update() + + if roll != 0: + rot_mat = Matrix.Rotation(roll, 4, 'Y') + mesh.transform(rot_mat) return obj else: return None diff --git a/rigify/ui.py b/rigify/ui.py index c75470421d7889544adb55bf478230abbef63899..8c2bfbc671f431c0298b299d50b058d516e2da6d 100644 --- a/rigify/ui.py +++ b/rigify/ui.py @@ -597,6 +597,7 @@ class Generate(bpy.types.Operator): bl_idname = "pose.rigify_generate" bl_label = "Rigify Generate Rig" bl_options = {'UNDO'} + bl_description = 'Generates a rig from the active metarig armature' def execute(self, context): import importlib diff --git a/rigify/utils.py b/rigify/utils.py index 09f5ee9d03e10a8a3ec2ead5eff96c5bc4d5c2a2..5a60b550254426685028b067427e6b00825b6509 100644 --- a/rigify/utils.py +++ b/rigify/utils.py @@ -137,6 +137,7 @@ def insert_before_lr(name, text): #======================= # Bone manipulation #======================= + def new_bone(obj, bone_name): """ Adds a new bone to the given armature object. Returns the resulting bone's name. @@ -457,6 +458,7 @@ def create_cube_widget(rig, bone_name, radius=0.5, bone_transform_name=None): mesh.from_pydata(verts, edges, []) mesh.update() + def create_chain_widget(rig, bone_name, radius=0.5, invert=False, bone_transform_name=None): """Creates a basic chain widget """ @@ -473,6 +475,7 @@ def create_chain_widget(rig, bone_name, radius=0.5, invert=False, bone_transform mesh.from_pydata(verts, edges, []) mesh.update() + def create_sphere_widget(rig, bone_name, bone_transform_name=None): """ Creates a basic sphere widget, three pependicular overlapping circles. """ @@ -835,7 +838,7 @@ def write_metarig(obj, layers=False, func_name="create"): code.append(" pbone.bone.layers = %s" % str(list(pbone.bone.layers))) # Rig type parameters for param_name in pbone.rigify_parameters.keys(): - param = getattr(pbone.rigify_parameters, param_name) + param = getattr(pbone.rigify_parameters, param_name, '') if str(type(param)) == "<class 'bpy_prop_array'>": param = list(param) if type(param) == str: