def __init__(self, obj, bone, params): """ Gather and validate data about the rig. Store any data or references to data that will be needed later on. In particular, store references to bones that will be needed, and store names of bones that will be needed. Do NOT change any data in the scene. This is a gathering phase only. """ self.obj = obj self.params = params # Get the chain of 3 connected bones self.org_bones = [bone] + connected_children_names(self.obj, bone)[:2] if len(self.org_bones) != 3: raise MetarigError( "RIGIFY ERROR: Bone '%s': input to rig type must be a chain of 3 bones" % (strip_org(bone))) # Get (optional) parent if self.obj.data.bones[bone].parent is None: self.org_parent = None else: self.org_parent = self.obj.data.bones[bone].parent.name # Get the rig parameters if "layers" in params: self.layers = get_layers(params["layers"]) else: self.layers = None self.primary_rotation_axis = params.primary_rotation_axis
def __init__(self, obj, bone, params): """ Gather and validate data about the rig. Store any data or references to data that will be needed later on. In particular, store references to bones that will be needed, and store names of bones that will be needed. Do NOT change any data in the scene. This is a gathering phase only. """ self.obj = obj self.params = params # Get the chain of 3 connected bones self.org_bones = [bone] + connected_children_names(self.obj, bone)[:2] if len(self.org_bones) != 3: raise MetarigError("RIGIFY ERROR: Bone '%s': input to rig type must be a chain of 3 bones" % (strip_org(bone))) # Get (optional) parent if self.obj.data.bones[bone].parent is None: self.org_parent = None else: self.org_parent = self.obj.data.bones[bone].parent.name # Get the rig parameters if "layers" in params: self.layers = get_layers(params["layers"]) else: self.layers = None self.primary_rotation_axis = params.primary_rotation_axis
def __init__(self, obj, bone, params): """ Gather and validate data about the rig. Store any data or references to data that will be needed later on. In particular, store references to bones that will be needed, and store names of bones that will be needed. Do NOT change any data in the scene. This is a gathering phase only. """ self.obj = obj # Get the chain of 3 connected bones self.org_bones = [bone] + connected_children_names(self.obj, bone)[:2] if len(self.org_bones) != 3: raise MetarigError( "RIGIFY ERROR: Bone '%s': input to rig type must be a chain of at least 3 bones" % (strip_org(bone))) # Get params if "layers" in params: layers = get_layers(params["layers"]) else: layers = None primary_rotation_axis = params.primary_rotation_axis_cessen # Arm is based on common limb self.fk_limb = limb_common.FKLimb(obj, self.org_bones[0], self.org_bones[1], self.org_bones[2], primary_rotation_axis, layers)
def __init__(self, obj, bone, params): """ Gather and validate data about the rig. Store any data or references to data that will be needed later on. In particular, store references to bones that will be needed, and store names of bones that will be needed. Do NOT change any data in the scene. This is a gathering phase only. """ self.obj = obj self.params = params # Get the chain of 2 connected bones leg_bones = [bone] + connected_children_names(self.obj, bone)[:2] if len(leg_bones) != 2: raise MetarigError("RIGIFY ERROR: Bone '%s': incorrect bone configuration for rig type" % (strip_org(bone))) # Get the foot and heel foot = None heel = None for b in self.obj.data.bones[leg_bones[1]].children: if b.use_connect is True: if len(b.children) >= 1 and has_connected_children(b): foot = b.name else: heel = b.name if foot is None or heel is None: raise MetarigError("RIGIFY ERROR: Bone '%s': incorrect bone configuration for rig type" % (strip_org(bone))) # Get the toe toe = None for b in self.obj.data.bones[foot].children: if b.use_connect is True: toe = b.name # Get the toe if toe is None: raise MetarigError("RIGIFY ERROR: Bone '%s': incorrect bone configuration for rig type" % (strip_org(bone))) self.org_bones = leg_bones + [foot, toe, heel] # Get (optional) parent if self.obj.data.bones[bone].parent is None: self.org_parent = None else: self.org_parent = self.obj.data.bones[bone].parent.name # Get rig parameters if "layers" in params: self.layers = get_layers(params["layers"]) else: self.layers = None self.primary_rotation_axis = params.primary_rotation_axis
def __init__(self, obj, bone, params): """ Gather and validate data about the rig. Store any data or references to data that will be needed later on. In particular, store references to bones that will be needed, and store names of bones that will be needed. Do NOT change any data in the scene. This is a gathering phase only. """ self.obj = obj self.params = params # Get the chain of 2 connected bones leg_bones = [bone] + connected_children_names(self.obj, bone)[:2] if len(leg_bones) != 2: raise MetarigError("RIGIFY ERROR: Bone '%s': incorrect bone configuration for rig type." % (strip_org(bone))) # Get the foot and heel foot = None 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: foot = b.name if foot == None or heel == None: raise MetarigError("RIGIFY ERROR: Bone '%s': incorrect bone configuration for rig type." % (strip_org(bone))) # Get the toe toe = None for b in self.obj.data.bones[foot].children: if b.use_connect == True: toe = b.name # Get the toe 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] # Get (optional) parent if self.obj.data.bones[bone].parent == None: self.org_parent = None else: self.org_parent = self.obj.data.bones[bone].parent.name # Get rig parameters if "layers" in params: self.layers = get_layers(params["layers"]) else: self.layers = None self.primary_rotation_axis = params.primary_rotation_axis
def generate(self): ui_script = "" for s, limb in self.sides.items(): side_org_bones, ik_limb, fk_limb = limb (ulimb_ik, ulimb_str, flimb_ik, flimb_str, joint_str, elimb_ik, elimb_str) = ik_limb.generate() ulimb_fk, flimb_fk, elimb_fk = fk_limb.generate() bpy.ops.object.mode_set(mode='EDIT') eb = self.obj.data.edit_bones # Foot rig foot_fr = copy_bone( self.obj, self.org_bones[2], pantin_utils.strip_LR_numbers( make_mechanism_name(strip_org(self.org_bones[2]))) + '.fr' + s) foot_tgt = copy_bone( self.obj, self.org_bones[2], pantin_utils.strip_LR_numbers( make_mechanism_name(strip_org(self.org_bones[2]))) + '.tgt' + s) heel_fr = copy_bone( self.obj, self.org_bones[3], pantin_utils.strip_LR_numbers( make_mechanism_name(strip_org(self.org_bones[3]))) + '.fr' + s) toe_fr = copy_bone( self.obj, self.org_bones[4], pantin_utils.strip_LR_numbers( make_mechanism_name(strip_org(self.org_bones[4]))) + '.fr' + s) toe_ik_ctl = copy_bone( self.obj, self.org_bones[4], pantin_utils.strip_LR_numbers(strip_org(self.org_bones[4])) + '.IK' + s) toe_fk_ctl = copy_bone( self.obj, self.org_bones[4], pantin_utils.strip_LR_numbers(strip_org(self.org_bones[4])) + '.FK' + s) toe_pos = copy_bone( self.obj, self.org_bones[4], pantin_utils.strip_LR_numbers( make_mechanism_name(strip_org(self.org_bones[4]))) + '.pos' + s) roll_fr = new_bone(self.obj, "Foot roll" + s) # Position eb[roll_fr].head = (eb[elimb_str].head + Vector( (-1, 0, 0)) * eb[elimb_str].length * 2) eb[roll_fr].tail = (eb[elimb_str].head + Vector( (-1, 0, 1)) * eb[elimb_str].length * 2) eb[roll_fr].layers = eb[elimb_ik].layers # IK foot horizontal and starting at heel eb[elimb_ik].head = eb[heel_fr].tail eb[elimb_ik].tail.z = eb[heel_fr].tail.z align_bone_x_axis(self.obj, elimb_ik, Vector((0, 0, 1))) align_bone_x_axis(self.obj, roll_fr, Vector((-1, 0, 0))) align_bone_x_axis(self.obj, foot_fr, Vector((-1, 0, 0))) align_bone_x_axis(self.obj, heel_fr, Vector((-1, 0, 0))) align_bone_x_axis(self.obj, toe_fr, Vector((-1, 0, 0))) # Parenting eb[foot_fr].parent = None eb[heel_fr].parent = None eb[toe_fr].parent = None flip_bone(self.obj, foot_fr) flip_bone(self.obj, heel_fr) flip_bone(self.obj, toe_fr) eb[foot_fr].use_connect = True eb[foot_fr].parent = eb[toe_fr] eb[foot_tgt].use_connect = True eb[foot_tgt].parent = eb[foot_fr] eb[toe_fr].use_connect = False eb[toe_fr].parent = eb[heel_fr] eb[toe_ik_ctl].use_connect = True eb[toe_ik_ctl].parent = eb[toe_fr] eb[toe_fk_ctl].use_connect = True eb[toe_fk_ctl].parent = eb[elimb_fk] eb[toe_pos].use_connect = False eb[toe_pos].parent = eb[elimb_str] eb[heel_fr].use_connect = False eb[heel_fr].parent = eb[elimb_ik] eb[roll_fr].use_connect = False eb[roll_fr].parent = eb[elimb_ik] if self.params.do_stretch: eb[elimb_str].use_connect = False # Def bones if s == '.L': Z_index = -self.params.Z_index else: Z_index = self.params.Z_index side_org_bones = side_org_bones[:3] + side_org_bones[ -1:] # Ignore heel for i, b in enumerate(side_org_bones): def_bone_name = pantin_utils.strip_LR_numbers(strip_org(b)) def_bone = pantin_utils.create_deformation( self.obj, b, member_index=Z_index, bone_index=i, new_name=def_bone_name + s) # Set layers if specified active_layer = pantin_utils.layers_to_index(eb[ulimb_ik].layers) right_offset = self.params.right_offset if self.params.duplicate_lr else 0 if s == '.R': for b in (ulimb_ik, joint_str, elimb_ik, roll_fr, toe_ik_ctl): eb[b].layers = get_layers(active_layer + right_offset) for b in (ulimb_fk, flimb_fk, elimb_fk, toe_fk_ctl): eb[b].layers = get_layers(active_layer + self.params.fk_offset + right_offset) elif s == '.L': for b in (ulimb_fk, flimb_fk, elimb_fk, toe_fk_ctl): eb[b].layers = get_layers(active_layer + self.params.fk_offset) bpy.ops.object.mode_set(mode='OBJECT') pb = self.obj.pose.bones # Bone settings pb[roll_fr].rotation_mode = 'XZY' pb[roll_fr].lock_location = [True] * 3 pb[roll_fr].lock_rotation = [True, True, False] pb[roll_fr].lock_scale = [True] * 3 pb[foot_fr].rotation_mode = 'XZY' # Widgets # IK global_scale = self.obj.dimensions[2] member_factor = 0.06 if s == '.R': side_factor = 1.2 else: side_factor = 1.0 widget_size = global_scale * member_factor * side_factor pantin_utils.create_aligned_circle_widget(self.obj, ulimb_ik, number_verts=3, radius=widget_size) pantin_utils.create_aligned_circle_widget(self.obj, joint_str, radius=widget_size) # FK widget_size = 0.5 for bone in (ulimb_fk, flimb_fk, elimb_fk, toe_fk_ctl): pantin_utils.create_capsule_widget(self.obj, bone, length=widget_size, width=widget_size * 0.2, head_tail=0.5, horizontal=False, overshoot=True) # Default follow value pb[ulimb_fk]["follow"] = 0.0 # Foot WGT down = pb[heel_fr].head.z left = pb[heel_fr].head.x - (side_factor - 1) * pb[heel_fr].length right = pb[foot_fr].head.x up = pb[foot_fr].tail.z + (side_factor - 1) * pb[heel_fr].length foot_verts = ((left, down), (left, up), (right, down + (up - down) * 2 / 3), (right, down)) pantin_utils.create_aligned_polygon_widget(self.obj, elimb_ik, foot_verts) # Toe WGT left = right right = pb[toe_fr].head.x + (side_factor - 1) * pb[heel_fr].length up = down + (up - down) * 2 / 3 # TODO investigate why moving an edit bones # screws up widgets' matrices (foot_ik has moved) toe_verts = ((left, down), (left, up), (right, down + (up - down) * 2 / 3), (right, down)) pantin_utils.create_aligned_polygon_widget(self.obj, toe_ik_ctl, toe_verts) pantin_utils.create_aligned_crescent_widget(self.obj, roll_fr, radius=side_factor * pb[roll_fr].length / 2) # Constraints foot_fr_p = pb[foot_fr] heel_fr_p = pb[heel_fr] toe_fr_p = pb[toe_fr] roll_fr_p = pb[roll_fr] hor_vector = Vector((1, 0, 0)) foot_rotation = (foot_fr_p.vector.rotation_difference( hor_vector).to_euler('XZY')) toe_rotation = toe_fr_p.vector.rotation_difference( hor_vector).to_euler('XZY') foot_vertical_rot = foot_rotation[1] - pi / 2 toe_vertical_rot = toe_rotation[1] - pi / 2 con = foot_fr_p.constraints.new('TRANSFORM') con.name = "roll" con.target = self.obj con.subtarget = roll_fr con.map_from = 'ROTATION' con.map_to = 'ROTATION' con.from_min_z_rot = radians(0.0) con.from_max_z_rot = radians(60.0) con.to_min_z_rot = radians(0.0) con.to_max_z_rot = foot_vertical_rot con.target_space = 'LOCAL' con.owner_space = 'LOCAL' con = heel_fr_p.constraints.new('TRANSFORM') con.name = "roll" con.target = self.obj con.subtarget = roll_fr con.map_from = 'ROTATION' con.map_to = 'ROTATION' con.from_min_z_rot = radians(-60.0) con.from_max_z_rot = 0.0 con.to_min_z_rot = radians(-60.0) con.to_max_z_rot = 0.0 con.target_space = 'LOCAL' con.owner_space = 'LOCAL' con = toe_fr_p.constraints.new('TRANSFORM') con.name = "roll" con.target = self.obj con.subtarget = roll_fr con.map_from = 'ROTATION' con.map_to = 'ROTATION' con.from_min_z_rot = radians(60.0) con.from_max_z_rot = radians(90.0) con.to_min_z_rot = radians(0.0) con.to_max_z_rot = toe_vertical_rot con.target_space = 'LOCAL' con.owner_space = 'LOCAL' # Compensate foot for heel con = foot_fr_p.constraints.new('TRANSFORM') con.name = "roll_compensate" con.target = self.obj con.subtarget = roll_fr con.map_from = 'ROTATION' con.map_to = 'ROTATION' con.from_min_z_rot = radians(60.0) con.from_max_z_rot = radians(90.0) con.to_min_z_rot = radians(0.0) con.to_max_z_rot = -toe_vertical_rot con.target_space = 'LOCAL' con.owner_space = 'LOCAL' # Roll limits con = roll_fr_p.constraints.new('LIMIT_ROTATION') con.name = "limit rotation" con.use_limit_z = True con.min_z = radians(-60.0) con.max_z = radians(90.0) con.owner_space = 'LOCAL' # Edit IK to follow the rolled foot instead of ik control con = pb[flimb_ik].constraints["ik"] con.subtarget = foot_tgt con = pb[elimb_str].constraints["copy rotation"] con.subtarget = foot_tgt con = pb[toe_pos].constraints.new('COPY_ROTATION') con.name = "copy rotation" con.target = self.obj con.subtarget = toe_ik_ctl #con.invert_x = True con.target_space = 'POSE' con.owner_space = 'POSE' # Optional stretch to the foot if self.params.do_stretch: con1 = pb[flimb_str].constraints.new('STRETCH_TO') con1.name = "stretch to foot" con1.target = self.obj con1.subtarget = foot_tgt con1.volume = 'NO_VOLUME' con1.rest_length = pb[flimb_str].length con1.keep_axis = 'PLANE_Z' con2 = pb[elimb_str].constraints.new('COPY_LOCATION') con2.name = "copy foot location" con2.target = self.obj con2.subtarget = foot_tgt con2.target_space = 'POSE' con2.owner_space = 'POSE' # Set up custom properties prop = rna_idprop_ui_prop_get(pb[elimb_ik], "foot_stretch", create=True) pb[elimb_ik]["foot_stretch"] = 1 # int(self.foot_stretch) prop["soft_min"] = 0 prop["soft_max"] = 1 prop["min"] = 0 prop["max"] = 1 # Drivers for c in (con1, con2): driver = self.obj.driver_add(c.path_from_id("influence")) driver.driver.expression = 'foot_stretch' var_fs = driver.driver.variables.new() var_fs.type = 'SINGLE_PROP' var_fs.name = 'foot_stretch' var_fs.targets[0].id_type = 'OBJECT' var_fs.targets[0].id = self.obj var_fs.targets[0].data_path = ( pb[elimb_ik].path_from_id() + '["foot_stretch"]') for org, ctrl in zip( side_org_bones, [ulimb_str, flimb_str, elimb_str, toe_ik_ctl]): con = pb[org].constraints.new('COPY_TRANSFORMS') con.name = "copy_ik" con.target = self.obj con.subtarget = ctrl for org, ctrl in zip(side_org_bones, [ulimb_fk, flimb_fk, elimb_fk, toe_fk_ctl]): con = pb[org].constraints.new('COPY_TRANSFORMS') con.name = "copy_fk" con.target = self.obj con.subtarget = ctrl # Drivers driver = self.obj.driver_add(con.path_from_id("influence")) driver.driver.expression = 'fk' var_fk = driver.driver.variables.new() var_fk.type = 'SINGLE_PROP' var_fk.name = 'fk' var_fk.targets[0].id_type = 'OBJECT' var_fk.targets[0].id = self.obj var_fk.targets[ 0].data_path = 'pose.bones["{}"]["IK_FK"]'.format(elimb_ik) ui_script += UI_PANTIN_LIMB_SCRIPT % ( '"{}", "{}", "{}", "{}"'.format( ulimb_ik, joint_str, elimb_ik, toe_ik_ctl), '"{}", "{}", "{}", "{}"'.format( ulimb_fk, flimb_fk, elimb_fk, toe_fk_ctl)) if self.params.do_stretch: ui_script += """ layout.prop(pose_bones[ik_leg[2]], \ '["foot_stretch"]', \ text="Foot stretch (" + ik_leg[2] + ")", slider=True) """ return { 'script': [ui_script], 'imports': UI_IMPORTS, 'utilities': PANTIN_UTILS + [UTILITIES_PANTIN_LIMBS], 'register': PANTIN_REGISTER + REGISTER_PANTIN_LIMBS, 'register_props': REGISTER_PANTIN_PROPS, }
def generate(self): ui_script = "" for s, limb in self.sides.items(): side_org_bones, ik_limb, fk_limb = limb (ulimb_ik, ulimb_str, flimb_ik, flimb_str, joint_str, elimb_ik, elimb_str) = (ik_limb.generate()) (ulimb_fk, flimb_fk, elimb_fk) = (fk_limb.generate()) bpy.ops.object.mode_set(mode='EDIT') # Def bones eb = self.obj.data.edit_bones if s == '.L': Z_index = -self.params.Z_index else: Z_index = self.params.Z_index for i, b in enumerate(side_org_bones): def_bone_name = pantin_utils.strip_LR_numbers(strip_org(b)) def_bone = pantin_utils.create_deformation( self.obj, b, member_index=Z_index, bone_index=i, new_name=def_bone_name + s) # Set layers if specified active_layer = pantin_utils.layers_to_index(eb[ulimb_ik].layers) right_offset = self.params.right_offset if self.params.duplicate_lr else 0 if s == '.R': for b in (ulimb_ik, joint_str, elimb_ik): eb[b].layers = get_layers(active_layer + right_offset) for b in (ulimb_fk, flimb_fk, elimb_fk): eb[b].layers = get_layers(active_layer + self.params.fk_offset + right_offset) elif s == '.L': for b in (ulimb_fk, flimb_fk, elimb_fk): eb[b].layers = get_layers(active_layer + self.params.fk_offset) bpy.ops.object.mode_set(mode='OBJECT') pb = self.obj.pose.bones # Widgets # IK global_scale = self.obj.dimensions[2] member_factor = 0.06 if s == '.R': side_factor = 1.2 else: side_factor = 1.0 widget_size = global_scale * member_factor * side_factor pantin_utils.create_aligned_circle_widget(self.obj, ulimb_ik, number_verts=3, radius=widget_size) pantin_utils.create_aligned_circle_widget(self.obj, joint_str, radius=widget_size * 0.7) pantin_utils.create_aligned_circle_widget(self.obj, elimb_ik, radius=widget_size) # FK widget_size = 0.5 for bone in (ulimb_fk, flimb_fk, elimb_fk): pantin_utils.create_capsule_widget(self.obj, bone, length=widget_size, width=widget_size * 0.2, head_tail=0.5, horizontal=False, overshoot=True) # Constraints for org, ctrl in zip(side_org_bones, [ulimb_str, flimb_str, elimb_str]): con = pb[org].constraints.new('COPY_TRANSFORMS') con.name = "copy_ik" con.target = self.obj con.subtarget = ctrl for org, ctrl in zip(side_org_bones, [ulimb_fk, flimb_fk, elimb_fk]): con = pb[org].constraints.new('COPY_TRANSFORMS') con.name = "copy_fk" con.target = self.obj con.subtarget = ctrl # Drivers driver = self.obj.driver_add(con.path_from_id("influence")) driver.driver.expression = 'fk' var_fk = driver.driver.variables.new() var_fk.type = 'SINGLE_PROP' var_fk.name = 'fk' var_fk.targets[0].id_type = 'OBJECT' var_fk.targets[0].id = self.obj var_fk.targets[ 0].data_path = 'pose.bones["{}"]["IK_FK"]'.format(elimb_ik) ui_script += UI_PANTIN_LIMB_SCRIPT % ('"{}", "{}", "{}"'.format( ulimb_ik, joint_str, elimb_ik), '"{}", "{}", "{}"'.format( ulimb_fk, flimb_fk, elimb_fk)) return { 'script': [ui_script], 'imports': UI_IMPORTS, 'utilities': PANTIN_UTILS + [UTILITIES_PANTIN_LIMBS], 'register': PANTIN_REGISTER + REGISTER_PANTIN_LIMBS, 'register_props': REGISTER_PANTIN_PROPS, }