def create_mch(self): bpy.ops.object.mode_set(mode='EDIT') edit_bones = self.obj.data.edit_bones super().create_mch() self.bones['tail_mch'] = {} org_chain = self.get_chain_bones(self.base_bone) if edit_bones[org_chain[0]].parent: bone_to_copy = edit_bones[org_chain[0]].parent.name else: bone_to_copy = self.orientation_bone mch_rot_tail = make_mechanism_name('ROT-' + strip_org(self.base_bone)) mch_rot_tail = copy_bone(self.obj, bone_to_copy, assign_name=mch_rot_tail) self.bones['tail_mch']['rot_tail_mch'] = mch_rot_tail main_chain = self.get_chain_bones(self.base_bone) flip_bone(self.obj, mch_rot_tail) edit_bones[mch_rot_tail].parent = None put_bone(self.obj, mch_rot_tail, edit_bones[main_chain[0]].head)
def create_mch(self): bpy.ops.object.mode_set(mode='EDIT') edit_bones = self.obj.data.edit_bones self.bones['eye_mch'] = dict() self.bones['eye_mch']['eyelid_top'] = [] self.bones['eye_mch']['eyelid_bottom'] = [] self.bones['eye_mch']['eye_master'] = '' self.bones['eye_mch']['eye_master_tip'] = '' main_bone_name = strip_org(self.bones['org'][0]) eye_mch_name = make_mechanism_name(main_bone_name) eye_mch_name = copy_bone(self.obj, self.bones['org'][0], eye_mch_name) self.bones['eye_mch']['eye_master'] = eye_mch_name eye_tip_mch_name = copy_bone(self.obj, self.orientation_bone, eye_mch_name) self.bones['eye_mch']['eye_master_tip'] = eye_tip_mch_name put_bone(self.obj, eye_tip_mch_name, edit_bones[eye_mch_name].tail) if self.orientation_bone == self.base_bone: align_bone_y_axis(self.obj, eye_tip_mch_name, Vector((0, 0, 1))) edit_bones[ eye_tip_mch_name].length = 0.25 * edit_bones[eye_mch_name].length # top lid top_lid_chain = self.get_chain_bones(self.lid_bones['top'][0]) for l_b in top_lid_chain: lid_m_name = copy_bone(self.obj, self.bones['org'][0], eye_mch_name) edit_bones[lid_m_name].tail = edit_bones[l_b].tail self.bones['eye_mch']['eyelid_top'].append(lid_m_name) # bottom lid bottom_lid_chain = self.get_chain_bones(self.lid_bones['bottom'][0]) for l_b in bottom_lid_chain: lid_m_name = copy_bone(self.obj, self.bones['org'][0], eye_mch_name) edit_bones[lid_m_name].tail = edit_bones[l_b].tail self.bones['eye_mch']['eyelid_bottom'].append(lid_m_name) # create mch for eye_follow driver if self.needs_driver: if self.paired_eye or self.is_clustered(): eye_follow_mch = self.get_common_name() else: eye_follow_mch = strip_org(self.base_bone) eye_follow_mch = make_mechanism_name(eye_follow_mch) eye_follow_mch += "_parent" if eye_follow_mch not in edit_bones: parent = edit_bones[self.base_bone].parent.name eye_follow_mch = copy_bone(self.obj, parent, eye_follow_mch) edit_bones[ eye_follow_mch].length = 0.25 * edit_bones[parent].length self.bones['eye_mch']['eyefollow'] = eye_follow_mch super().create_mch()
def create_pivot(self, pivot=None): """ Create the pivot control and mechanism bones """ org_bones = self.org_bones bpy.ops.object.mode_set(mode='EDIT') eb = self.obj.data.edit_bones if not pivot: pivot = int(len(org_bones) / 2) pivot_name = org_bones[pivot] if '.L' in pivot_name: prefix = strip_org(org_bones[pivot]).split('.')[0] + '.L' elif '.R' in pivot_name: prefix = strip_org(org_bones[pivot]).split('.')[0] + '.R' else: prefix = strip_org(org_bones[pivot]).split('.')[0] ctrl_name = get_bone_name(prefix, 'ctrl', 'pivot') ctrl_name = copy_bone(self.obj, pivot_name, ctrl_name) ctrl_eb = eb[ctrl_name] self.orient_bone(ctrl_eb, 'y', self.spine_length / 2.5) pivot_loc = eb[pivot_name].head + ( (eb[pivot_name].tail - eb[pivot_name].head) / 2) * (len(org_bones) % 2) put_bone(self.obj, ctrl_name, pivot_loc) v = eb[org_bones[-1]].tail - eb[org_bones[ 0]].head # Create a vector from head of first ORG to tail of last v.normalize() v_proj = eb[org_bones[0]].y_axis.dot( v) * v # projection of first ORG to v v_point = eb[org_bones[ 0]].y_axis - v_proj # a vector co-planar to first ORG and v directed out of the chain if v_point.magnitude < eb[org_bones[ 0]].y_axis.magnitude * 1e-03: # if v_point is too small it's not usable v_point = eb[org_bones[0]].x_axis if self.params.tweak_axis == 'auto': align_bone_y_axis(self.obj, ctrl_name, v) align_bone_z_axis(self.obj, ctrl_name, -v_point) elif self.params.tweak_axis == 'x': align_bone_y_axis(self.obj, ctrl_name, Vector((1, 0, 0))) align_bone_x_axis(self.obj, ctrl_name, Vector((0, 0, 1))) elif self.params.tweak_axis == 'y': align_bone_y_axis(self.obj, ctrl_name, Vector((0, 1, 0))) align_bone_x_axis(self.obj, ctrl_name, Vector((1, 0, 0))) elif self.params.tweak_axis == 'z': align_bone_y_axis(self.obj, ctrl_name, Vector((0, 0, 1))) align_bone_x_axis(self.obj, ctrl_name, Vector((1, 0, 0))) return {'ctrl': ctrl_name}
def create_mch(self): bpy.ops.object.mode_set(mode='EDIT') edit_bones = self.obj.data.edit_bones main_bone_name = strip_org(self.bones['org'][0]) mouth_lock_name = make_mechanism_name(main_bone_name + "_lock") mouth_lock = copy_bone(self.obj, self.main_mch, mouth_lock_name) self.bones['jaw_mch'] = dict() self.bones['jaw_mch']['mouth_lock'] = mouth_lock self.bones['jaw_mch']['jaw_masters'] = [] jaw_masters_number = 3 for i in range(0, jaw_masters_number): jaw_m_name = make_mechanism_name("jaw_master") jaw_m = copy_bone(self.obj, self.main_mch, jaw_m_name) div_len = (edit_bones[mouth_lock].length/(jaw_masters_number + 1)) edit_bones[jaw_m].length = (jaw_masters_number - i) * div_len edit_bones[jaw_m].use_connect = False self.bones['jaw_mch']['jaw_masters'].append(jaw_m) self.bones['mouth_mch'] = dict() org_top = self.mouth_bones['top'][0] top_mch_name = make_mechanism_name(strip_org(org_top)) top_mch = copy_bone(self.obj, org_top, top_mch_name) self.bones['mouth_mch']['top'] = [top_mch] edit_bones[top_mch].use_connect = False self.bones['mouth_mch']['corners'] = [] for org_name in self.mouth_bones['corners']: mch_name = make_mechanism_name(strip_org(org_name)) mch = copy_bone(self.obj, org_name, mch_name) self.bones['mouth_mch']['corners'].append(mch) edit_bones[mch].use_connect = False org_bottom = self.mouth_bones['bottom'][0] bottom_mch_name = make_mechanism_name(strip_org(org_bottom)) bottom_mch = copy_bone(self.obj, org_bottom, bottom_mch_name) self.bones['mouth_mch']['bottom'] = [bottom_mch] edit_bones[bottom_mch].use_connect = False mbs = self.flatten(self.bones['mouth_mch']) mouth_center = edit_bones[mbs[0]].head for b in mbs[1:]: mouth_center = mouth_center + edit_bones[b].head mouth_center = mouth_center / len(mbs) for b in self.flatten(self.bones['mouth_mch']): put_bone(self.obj, b, mouth_center) # create remaining subchain mch-s super().create_mch()
def create_mch(self): bpy.ops.object.mode_set(mode='EDIT') edit_bones = self.obj.data.edit_bones super().create_mch() self.bones['tongue_mch'] = {} self.bones['tongue_mch']['tongue_tip'] = [] for i, mch in enumerate(self.bones['mch'][strip_org(self.base_bone)][:-1]): if i == 0: edit_bones[mch].length = edit_bones[self.base_bone].length flip_bone(self.obj, mch) self.bones['tongue_mch']['tongue_tip'].append(mch) else: put_bone(self.obj, mch, edit_bones[self.base_bone].tail) edit_bones[mch].tail = edit_bones[self.base_bone].head self.bones['tongue_mch']['tongue_tip'].append(mch)
def create_controls(self): bpy.ops.object.mode_set(mode='EDIT') edit_bones = self.obj.data.edit_bones self.bones['jaw_ctrl'] = dict() jaw_ctrl_name = "jaw_master" jaw_ctrl = copy_bone(self.obj, self.main_mch, jaw_ctrl_name) self.bones['jaw_ctrl']['jaw'] = jaw_ctrl edit_bones[jaw_ctrl].use_connect = False self.bones['mouth_ctrl'] = dict() org_top = self.mouth_bones['top'][0] top_ctrl = copy_bone(self.obj, org_top, strip_org(org_top)) self.bones['mouth_ctrl']['top'] = [top_ctrl] edit_bones[top_ctrl].use_connect = False self.bones['mouth_ctrl']['corners'] = [] for org_name in self.mouth_bones['corners']: ctrl = copy_bone(self.obj, org_name, strip_org(org_name)) self.bones['mouth_ctrl']['corners'].append(ctrl) edit_bones[top_ctrl].use_connect = False org_bottom = self.mouth_bones['bottom'][0] bottom_ctrl = copy_bone(self.obj, org_bottom, strip_org(org_bottom)) self.bones['mouth_ctrl']['bottom'] = [bottom_ctrl] edit_bones[bottom_ctrl].use_connect = False mouth_center = (edit_bones[org_top].head + edit_bones[org_bottom].head) / 2 main_mouth_ctrl = copy_bone(self.obj, org_top, "main_mouth") self.bones['mouth_ctrl']['main'] = main_mouth_ctrl edit_bones[main_mouth_ctrl].use_connect = False put_bone(self.obj, main_mouth_ctrl, mouth_center) super().create_controls() ctrls = self.get_all_ctrls() for ctrl in ctrls: align_bone_y_axis(self.obj, ctrl, Vector((0, 0, 1)))
def make_ctrl_chain(self): """ Create all ctrls in chain :return: """ if not self.active: return [] bpy.ops.object.mode_set(mode='EDIT') edit_bones = self.obj.data.edit_bones chain = self._bones['org'] self._bones['ctrl'] = [] if self.chain_type == ChainType.TYPE_MCH_BASED: for chain_bone in chain: ctrl = strip_org(chain_bone) ctrl = copy_bone(self.obj, self.orientation_bone, assign_name=ctrl) put_bone(self.obj, ctrl, edit_bones[chain_bone].head) edit_bones[ctrl].length = edit_bones[ self.orientation_bone].length * self.CTRL_SCALE edit_bones[ctrl].parent = None edit_bones[ctrl].use_connect = False self._bones['ctrl'].append(ctrl) last_name = chain[-1] last_ctrl = copy_bone(self.obj, self.orientation_bone, assign_name=strip_org(last_name)) put_bone(self.obj, last_ctrl, edit_bones[last_name].tail) edit_bones[last_ctrl].length = edit_bones[ self.orientation_bone].length * self.CTRL_SCALE edit_bones[last_ctrl].parent = None edit_bones[last_ctrl].use_connect = False self._bones['ctrl'].append(last_ctrl) return self._bones['ctrl']
def create_controls(self): bpy.ops.object.mode_set(mode='EDIT') edit_bones = self.obj.data.edit_bones super().create_controls() self.bones['tweaks'] = {} self.bones['tail_ctrl'] = {} chain = strip_org(self.base_bone) ctrl_chain = self.bones['ctrl'][chain] self.bones['tweaks'][chain] = [] orgs = self.get_chain_bones(org(chain)) for org_bone, ctrl in zip(orgs, ctrl_chain): edit_bones[ctrl].length = edit_bones[org_bone].length align_bone_y_axis(self.obj, ctrl, edit_bones[org_bone].y_axis) tweak_name = 'tweak_' + ctrl tweak_name = copy_bone(self.obj, org_bone, assign_name=tweak_name) edit_bones[tweak_name].length = edit_bones[ self.orientation_bone].length * self.TWEAK_SCALE self.bones['tweaks'][chain].append(tweak_name) tweak_name = 'tweak_' + ctrl_chain[-1] tweak_name = copy_bone(self.obj, orgs[-1], assign_name=tweak_name) edit_bones[tweak_name].parent = None put_bone(self.obj, tweak_name, edit_bones[orgs[-1]].tail) edit_bones[tweak_name].length = edit_bones[ self.orientation_bone].length * self.TWEAK_SCALE self.bones['tweaks'][chain].append(tweak_name) edit_bones[ctrl_chain[-1]].head = edit_bones[orgs[0]].head edit_bones[ctrl_chain[-1]].tail = edit_bones[orgs[0]].tail tail_master = strip_org(self.base_bone) + '_master' edit_bones[ctrl_chain[-1]].name = tail_master self.bones['tail_ctrl']['tail_master'] = tail_master ctrl_chain[-1] = tail_master
def create_mch(self): bpy.ops.object.mode_set(mode='EDIT') edit_bones = self.obj.data.edit_bones mch_bone = make_mechanism_name(strip_org(self.base_bone)) mch_bone = copy_bone(self.obj, self.base_bone, mch_bone) self.bones['glue_mch'] = mch_bone MCH_LAYER = [n == 30 for n in range(0, 32)] edit_bones[mch_bone].layers = MCH_LAYER if self.glue_mode == 'bridge': self.bones['glue_mch'] = [mch_bone] b = self.base_bone put_bone( self.obj, mch_bone, edit_bones[b].head - (edit_bones[mch_bone].tail - edit_bones[mch_bone].head)) mch_bone = make_mechanism_name(strip_org(self.base_bone)) mch_bone = copy_bone(self.obj, self.base_bone, mch_bone) self.bones['glue_mch'].append(mch_bone) put_bone(self.obj, mch_bone, edit_bones[b].tail) edit_bones[mch_bone].layers = MCH_LAYER
def generate(self): """ Generate the rig. Do NOT modify any of the original bones, except for adding constraints. The main armature should be selected and active before this is called. """ # Generate base IK limb bone_list = self.ik_limb.generate() thigh = bone_list[0] shin = bone_list[1] foot = bone_list[2] foot_mch = bone_list[3] pole = bone_list[4] # vispole = bone_list[5] # visfoot = bone_list[6] # Build IK foot rig bpy.ops.object.mode_set(mode='EDIT') make_rocker = False if self.org_bones[5] is not None: make_rocker = True # Create the bones toe = copy_bone(self.obj, self.org_bones[3], strip_org(self.org_bones[3])) toe_parent = copy_bone( self.obj, self.org_bones[2], make_mechanism_name(strip_org(self.org_bones[3] + ".parent"))) toe_parent_socket1 = copy_bone( self.obj, self.org_bones[2], make_mechanism_name(strip_org(self.org_bones[3] + ".socket1"))) toe_parent_socket2 = copy_bone( self.obj, self.org_bones[2], make_mechanism_name(strip_org(self.org_bones[3] + ".socket2"))) foot_roll = copy_bone( self.obj, self.org_bones[4], strip_org(insert_before_lr(self.org_bones[2], "_roll.ik"))) roll1 = copy_bone( self.obj, self.org_bones[4], make_mechanism_name(strip_org(self.org_bones[2] + ".roll.01"))) roll2 = copy_bone( self.obj, self.org_bones[4], make_mechanism_name(strip_org(self.org_bones[2] + ".roll.02"))) if make_rocker: rocker1 = copy_bone( self.obj, self.org_bones[5], make_mechanism_name(strip_org(self.org_bones[2] + ".rocker.01"))) rocker2 = copy_bone( self.obj, self.org_bones[5], make_mechanism_name(strip_org(self.org_bones[2] + ".rocker.02"))) # Get edit bones eb = self.obj.data.edit_bones org_foot_e = eb[self.org_bones[2]] foot_e = eb[foot] foot_ik_target_e = eb[foot_mch] toe_e = eb[toe] toe_parent_e = eb[toe_parent] toe_parent_socket1_e = eb[toe_parent_socket1] toe_parent_socket2_e = eb[toe_parent_socket2] foot_roll_e = eb[foot_roll] roll1_e = eb[roll1] roll2_e = eb[roll2] if make_rocker: rocker1_e = eb[rocker1] rocker2_e = eb[rocker2] # Parenting foot_ik_target_e.use_connect = False foot_ik_target_e.parent = roll2_e toe_e.parent = toe_parent_e toe_parent_e.use_connect = False toe_parent_e.parent = toe_parent_socket1_e toe_parent_socket1_e.use_connect = False toe_parent_socket1_e.parent = roll1_e toe_parent_socket2_e.use_connect = False toe_parent_socket2_e.parent = eb[self.org_bones[2]] foot_roll_e.use_connect = False foot_roll_e.parent = foot_e roll1_e.use_connect = False roll1_e.parent = foot_e roll2_e.use_connect = False roll2_e.parent = roll1_e if make_rocker: rocker1_e.use_connect = False rocker2_e.use_connect = False roll1_e.parent = rocker2_e rocker2_e.parent = rocker1_e rocker1_e.parent = foot_e # Positioning vec = Vector(toe_e.vector) vec.normalize() foot_e.tail = foot_e.head + (vec * foot_e.length) foot_e.roll = toe_e.roll flip_bone(self.obj, toe_parent_socket1) flip_bone(self.obj, toe_parent_socket2) toe_parent_socket1_e.head = Vector(org_foot_e.tail) toe_parent_socket2_e.head = Vector(org_foot_e.tail) toe_parent_socket1_e.tail = Vector(org_foot_e.tail) + (Vector( (0, 0, 1)) * foot_e.length / 2) toe_parent_socket2_e.tail = Vector(org_foot_e.tail) + (Vector( (0, 0, 1)) * foot_e.length / 3) toe_parent_socket2_e.roll = toe_parent_socket1_e.roll tail = Vector(roll1_e.tail) roll1_e.tail = Vector(org_foot_e.tail) roll1_e.tail = Vector(org_foot_e.tail) roll1_e.head = tail roll2_e.head = Vector(org_foot_e.tail) foot_roll_e.head = Vector(org_foot_e.tail) put_bone(self.obj, foot_roll, roll1_e.head) foot_roll_e.length /= 2 roll_axis = roll1_e.vector.cross(org_foot_e.vector) align_bone_x_axis(self.obj, roll1, roll_axis) align_bone_x_axis(self.obj, roll2, roll_axis) foot_roll_e.roll = roll2_e.roll if make_rocker: d = toe_e.y_axis.dot(rocker1_e.x_axis) if d >= 0.0: flip_bone(self.obj, rocker2) else: flip_bone(self.obj, rocker1) # Object mode, get pose bones bpy.ops.object.mode_set(mode='OBJECT') pb = self.obj.pose.bones foot_p = pb[foot] foot_roll_p = pb[foot_roll] roll1_p = pb[roll1] roll2_p = pb[roll2] if make_rocker: rocker1_p = pb[rocker1] rocker2_p = pb[rocker2] toe_p = pb[toe] # toe_parent_p = pb[toe_parent] toe_parent_socket1_p = pb[toe_parent_socket1] # Foot roll control only rotates on x-axis, or x and y if rocker. foot_roll_p.rotation_mode = 'XYZ' if make_rocker: foot_roll_p.lock_rotation = False, False, True else: foot_roll_p.lock_rotation = False, True, True foot_roll_p.lock_location = True, True, True foot_roll_p.lock_scale = True, True, True # roll and rocker bones set to euler rotation roll1_p.rotation_mode = 'XYZ' roll2_p.rotation_mode = 'XYZ' if make_rocker: rocker1_p.rotation_mode = 'XYZ' rocker2_p.rotation_mode = 'XYZ' # toe_parent constraint con = toe_parent_socket1_p.constraints.new('COPY_LOCATION') con.name = "copy_location" con.target = self.obj con.subtarget = toe_parent_socket2 con = toe_parent_socket1_p.constraints.new('COPY_SCALE') con.name = "copy_scale" con.target = self.obj con.subtarget = toe_parent_socket2 con = toe_parent_socket1_p.constraints.new( 'COPY_TRANSFORMS') # drive with IK switch con.name = "fk" con.target = self.obj con.subtarget = toe_parent_socket2 fcurve = con.driver_add("influence") driver = fcurve.driver var = driver.variables.new() driver.type = 'AVERAGE' var.name = "var" var.targets[0].id_type = 'OBJECT' var.targets[0].id = self.obj var.targets[0].data_path = foot_p.path_from_id() + '["ikfk_switch"]' mod = fcurve.modifiers[0] mod.poly_order = 1 mod.coefficients[0] = 1.0 mod.coefficients[1] = -1.0 # Foot roll drivers fcurve = roll1_p.driver_add("rotation_euler", 0) driver = fcurve.driver var = driver.variables.new() driver.type = 'SCRIPTED' driver.expression = "min(0,var)" var.name = "var" var.targets[0].id_type = 'OBJECT' var.targets[0].id = self.obj var.targets[0].data_path = foot_roll_p.path_from_id( ) + '.rotation_euler[0]' fcurve = roll2_p.driver_add("rotation_euler", 0) driver = fcurve.driver var = driver.variables.new() driver.type = 'SCRIPTED' driver.expression = "max(0,var)" var.name = "var" var.targets[0].id_type = 'OBJECT' var.targets[0].id = self.obj var.targets[0].data_path = foot_roll_p.path_from_id( ) + '.rotation_euler[0]' if make_rocker: fcurve = rocker1_p.driver_add("rotation_euler", 0) driver = fcurve.driver var = driver.variables.new() driver.type = 'SCRIPTED' driver.expression = "max(0,-var)" var.name = "var" var.targets[0].id_type = 'OBJECT' var.targets[0].id = self.obj var.targets[0].data_path = foot_roll_p.path_from_id( ) + '.rotation_euler[1]' fcurve = rocker2_p.driver_add("rotation_euler", 0) driver = fcurve.driver var = driver.variables.new() driver.type = 'SCRIPTED' driver.expression = "max(0,var)" var.name = "var" var.targets[0].id_type = 'OBJECT' var.targets[0].id = self.obj var.targets[0].data_path = foot_roll_p.path_from_id( ) + '.rotation_euler[1]' # Constrain toe bone to toe control con = pb[self.org_bones[3]].constraints.new('COPY_TRANSFORMS') con.name = "copy_transforms" con.target = self.obj con.subtarget = toe # Set layers if specified if self.layers: foot_roll_p.bone.layers = self.layers toe_p.bone.layers = [ (i[0] or i[1]) for i in zip(toe_p.bone.layers, self.layers) ] # Both FK and IK layers # Create widgets create_circle_widget(self.obj, toe, radius=0.7, head_tail=0.5) ob = create_widget(self.obj, foot_roll) if ob is not None: verts = [ (0.3999999761581421, 0.766044557094574, 0.6427875757217407), (0.17668449878692627, 3.823702598992895e-08, 3.2084670920085046e-08), (-0.17668461799621582, 9.874240447516058e-08, 8.285470443070153e-08), (-0.39999961853027344, 0.7660449147224426, 0.6427879333496094), (0.3562471270561218, 0.6159579753875732, 0.5168500542640686), (-0.35624682903289795, 0.6159582138061523, 0.5168502926826477), (0.20492683351039886, 0.09688037633895874, 0.0812922865152359), (-0.20492687821388245, 0.0968804731965065, 0.08129236847162247) ] edges = [(1, 2), (0, 3), (0, 4), (3, 5), (1, 6), (4, 6), (2, 7), (5, 7)] mesh = ob.data mesh.from_pydata(verts, edges, []) mesh.update() mod = ob.modifiers.new("subsurf", 'SUBSURF') mod.levels = 2 ob = create_widget(self.obj, foot) if ob is not None: verts = [(0.7, 1.5, 0.0), (0.7, -0.25, 0.0), (-0.7, -0.25, 0.0), (-0.7, 1.5, 0.0), (0.7, 0.723, 0.0), (-0.7, 0.723, 0.0), (0.7, 0.0, 0.0), (-0.7, 0.0, 0.0)] edges = [(1, 2), (0, 3), (0, 4), (3, 5), (4, 6), (1, 6), (5, 7), (2, 7)] mesh = ob.data mesh.from_pydata(verts, edges, []) mesh.update() mod = ob.modifiers.new("subsurf", 'SUBSURF') mod.levels = 2 return [thigh, shin, foot, pole, foot_roll, foot_mch]
def generate(self): """ Generate the rig. Do NOT modify any of the original bones, except for adding constraints. The main armature should be selected and active before this is called. """ bpy.ops.object.mode_set(mode='EDIT') # Create upper arm bones if self.use_thigh_twist: thigh1 = copy_bone( self.obj, self.org_bones[0], make_deformer_name(strip_org(self.org_bones[0] + ".01"))) thigh2 = copy_bone( self.obj, self.org_bones[0], make_deformer_name(strip_org(self.org_bones[0] + ".02"))) utip = copy_bone( self.obj, self.org_bones[0], make_mechanism_name(strip_org(self.org_bones[0] + ".tip"))) else: thigh = copy_bone(self.obj, self.org_bones[0], make_deformer_name(strip_org(self.org_bones[0]))) # Create forearm bones if self.use_shin_twist: shin1 = copy_bone( self.obj, self.org_bones[1], make_deformer_name(strip_org(self.org_bones[1] + ".01"))) shin2 = copy_bone( self.obj, self.org_bones[1], make_deformer_name(strip_org(self.org_bones[1] + ".02"))) stip = copy_bone( self.obj, self.org_bones[1], make_mechanism_name(strip_org(self.org_bones[1] + ".tip"))) else: shin = copy_bone(self.obj, self.org_bones[1], make_deformer_name(strip_org(self.org_bones[1]))) # Create foot bone foot = copy_bone(self.obj, self.org_bones[2], make_deformer_name(strip_org(self.org_bones[2]))) # Create toe bone toe = copy_bone(self.obj, self.org_bones[3], make_deformer_name(strip_org(self.org_bones[3]))) # Get edit bones eb = self.obj.data.edit_bones org_thigh_e = eb[self.org_bones[0]] if self.use_thigh_twist: thigh1_e = eb[thigh1] thigh2_e = eb[thigh2] utip_e = eb[utip] else: thigh_e = eb[thigh] org_shin_e = eb[self.org_bones[1]] if self.use_shin_twist: shin1_e = eb[shin1] shin2_e = eb[shin2] stip_e = eb[stip] else: shin_e = eb[shin] org_foot_e = eb[self.org_bones[2]] foot_e = eb[foot] org_toe_e = eb[self.org_bones[3]] toe_e = eb[toe] # Parent and position thigh bones if self.use_thigh_twist: thigh1_e.use_connect = False thigh2_e.use_connect = False utip_e.use_connect = False thigh1_e.parent = org_thigh_e.parent thigh2_e.parent = org_thigh_e utip_e.parent = org_thigh_e center = Vector((org_thigh_e.head + org_thigh_e.tail) / 2) thigh1_e.tail = center thigh2_e.head = center put_bone(self.obj, utip, org_thigh_e.tail) utip_e.length = org_thigh_e.length / 8 else: thigh_e.use_connect = False thigh_e.parent = org_thigh_e # Parent and position shin bones if self.use_shin_twist: shin1_e.use_connect = False shin2_e.use_connect = False stip_e.use_connect = False shin1_e.parent = org_shin_e shin2_e.parent = org_shin_e stip_e.parent = org_shin_e center = Vector((org_shin_e.head + org_shin_e.tail) / 2) shin1_e.tail = center shin2_e.head = center put_bone(self.obj, stip, org_shin_e.tail) stip_e.length = org_shin_e.length / 8 # Align roll of shin2 with foot align_roll(self.obj, shin2, foot) else: shin_e.use_connect = False shin_e.parent = org_shin_e # Parent foot foot_e.use_connect = False foot_e.parent = org_foot_e # Parent toe toe_e.use_connect = False toe_e.parent = org_toe_e # Object mode, get pose bones bpy.ops.object.mode_set(mode='OBJECT') pb = self.obj.pose.bones if self.use_thigh_twist: thigh1_p = pb[thigh1] if self.use_shin_twist: shin2_p = pb[shin2] foot_p = pb[foot] # Thigh constraints if self.use_thigh_twist: con = thigh1_p.constraints.new('COPY_LOCATION') con.name = "copy_location" con.target = self.obj con.subtarget = self.org_bones[0] con = thigh1_p.constraints.new('COPY_SCALE') con.name = "copy_scale" con.target = self.obj con.subtarget = self.org_bones[0] con = thigh1_p.constraints.new('DAMPED_TRACK') con.name = "track_to" con.target = self.obj con.subtarget = utip # Shin constraints if self.use_shin_twist: con = shin2_p.constraints.new('COPY_ROTATION') con.name = "copy_rotation" con.target = self.obj con.subtarget = foot con = shin2_p.constraints.new('DAMPED_TRACK') con.name = "track_to" con.target = self.obj con.subtarget = stip
def gen_control(self): """ Generate the control rig. """ #--------------------------------- # Create the hip and rib controls bpy.ops.object.mode_set(mode='EDIT') # Copy org bones hip_control = copy_bone(self.obj, self.org_bones[0], strip_org(self.org_bones[0])) rib_control = copy_bone(self.obj, self.org_bones[-1], strip_org(self.org_bones[-1])) rib_mch = copy_bone( self.obj, self.org_bones[-1], make_mechanism_name(strip_org(self.org_bones[-1] + ".follow"))) hinge = copy_bone( self.obj, self.org_bones[0], make_mechanism_name(strip_org(self.org_bones[-1]) + ".hinge")) eb = self.obj.data.edit_bones hip_control_e = eb[hip_control] rib_control_e = eb[rib_control] rib_mch_e = eb[rib_mch] hinge_e = eb[hinge] # Parenting hip_control_e.use_connect = False rib_control_e.use_connect = False rib_mch_e.use_connect = False hinge_e.use_connect = False hinge_e.parent = None rib_control_e.parent = hinge_e rib_mch_e.parent = rib_control_e # Position flip_bone(self.obj, hip_control) flip_bone(self.obj, hinge) hinge_e.length /= 2 rib_mch_e.length /= 2 put_bone(self.obj, rib_control, hip_control_e.head) put_bone(self.obj, rib_mch, hip_control_e.head) bpy.ops.object.mode_set(mode='POSE') bpy.ops.object.mode_set(mode='EDIT') eb = self.obj.data.edit_bones # Switch to object mode bpy.ops.object.mode_set(mode='OBJECT') pb = self.obj.pose.bones hip_control_p = pb[hip_control] rib_control_p = pb[rib_control] hinge_p = pb[hinge] # No translation on rib control rib_control_p.lock_location = [True, True, True] # Hip does not use local location hip_control_p.bone.use_local_location = False # Custom hinge property prop = rna_idprop_ui_prop_get(rib_control_p, "isolate", create=True) rib_control_p["isolate"] = 1.0 prop["soft_min"] = prop["min"] = 0.0 prop["soft_max"] = prop["max"] = 1.0 # Constraints con = hinge_p.constraints.new('COPY_LOCATION') con.name = "copy_location" con.target = self.obj con.subtarget = hip_control con1 = hinge_p.constraints.new('COPY_ROTATION') con1.name = "isolate_off.01" con1.target = self.obj con1.subtarget = hip_control con2 = rib_control_p.constraints.new('COPY_SCALE') con2.name = "isolate_off.02" con2.target = self.obj con2.subtarget = hip_control con2.use_offset = True con2.target_space = 'LOCAL' con2.owner_space = 'LOCAL' # Drivers for "isolate_off" fcurve = con1.driver_add("influence") driver = fcurve.driver var = driver.variables.new() driver.type = 'AVERAGE' var.name = "var" var.targets[0].id_type = 'OBJECT' var.targets[0].id = self.obj var.targets[0].data_path = rib_control_p.path_from_id() + '["isolate"]' mod = fcurve.modifiers[0] mod.poly_order = 1 mod.coefficients[0] = 1.0 mod.coefficients[1] = -1.0 fcurve = con2.driver_add("influence") driver = fcurve.driver var = driver.variables.new() driver.type = 'AVERAGE' var.name = "var" var.targets[0].id_type = 'OBJECT' var.targets[0].id = self.obj var.targets[0].data_path = rib_control_p.path_from_id() + '["isolate"]' mod = fcurve.modifiers[0] mod.poly_order = 1 mod.coefficients[0] = 1.0 mod.coefficients[1] = -1.0 # Appearence hip_control_p.custom_shape_transform = pb[self.org_bones[0]] rib_control_p.custom_shape_transform = pb[self.org_bones[-1]] #------------------------- # Create flex spine chain # Create bones/parenting/positiong bpy.ops.object.mode_set(mode='EDIT') flex_bones = [] flex_helpers = [] prev_bone = None for b in self.org_bones: # Create bones bone = copy_bone(self.obj, b, make_mechanism_name(strip_org(b) + ".flex")) helper = copy_bone(self.obj, rib_mch, make_mechanism_name(strip_org(b) + ".flex_h")) flex_bones += [bone] flex_helpers += [helper] eb = self.obj.data.edit_bones bone_e = eb[bone] helper_e = eb[helper] # Parenting bone_e.use_connect = False helper_e.use_connect = False if prev_bone == None: helper_e.parent = eb[hip_control] bone_e.parent = helper_e # Position put_bone(self.obj, helper, bone_e.head) helper_e.length /= 4 prev_bone = bone # Constraints bpy.ops.object.mode_set(mode='OBJECT') pb = self.obj.pose.bones rib_control_p = pb[rib_control] rib_mch_p = pb[rib_mch] inc = 1.0 / (len(flex_helpers) - 1) inf = 1.0 / (len(flex_helpers) - 1) for b in zip(flex_helpers[1:], flex_bones[:-1], self.org_bones[1:]): bone_p = pb[b[0]] # Scale constraints con = bone_p.constraints.new('COPY_SCALE') con.name = "copy_scale1" con.target = self.obj con.subtarget = flex_helpers[0] con.influence = 1.0 con = bone_p.constraints.new('COPY_SCALE') con.name = "copy_scale2" con.target = self.obj con.subtarget = rib_mch con.influence = inf # Bend constraints con = bone_p.constraints.new('COPY_ROTATION') con.name = "bend1" con.target = self.obj con.subtarget = flex_helpers[0] con.influence = 1.0 con = bone_p.constraints.new('COPY_ROTATION') con.name = "bend2" con.target = self.obj con.subtarget = rib_mch con.influence = inf # If not the rib control if b[0] != flex_helpers[-1]: # Custom bend property prop_name = "bend_" + strip_org(b[2]) prop = rna_idprop_ui_prop_get(rib_control_p, prop_name, create=True) rib_control_p[prop_name] = inf prop["min"] = 0.0 prop["max"] = 1.0 prop["soft_min"] = 0.0 prop["soft_max"] = 1.0 # Bend driver fcurve = con.driver_add("influence") driver = fcurve.driver var = driver.variables.new() driver.type = 'AVERAGE' var.name = prop_name var.targets[0].id_type = 'OBJECT' var.targets[0].id = self.obj var.targets[0].data_path = rib_control_p.path_from_id( ) + '["' + prop_name + '"]' # Location constraint con = bone_p.constraints.new('COPY_LOCATION') con.name = "copy_location" con.target = self.obj con.subtarget = b[1] con.head_tail = 1.0 inf += inc #---------------------------- # Create reverse spine chain # Create bones/parenting/positioning bpy.ops.object.mode_set(mode='EDIT') rev_bones = [] prev_bone = None for b in zip(flex_bones, self.org_bones): # Create bones bone = copy_bone(self.obj, b[1], make_mechanism_name(strip_org(b[1]) + ".reverse")) rev_bones += [bone] eb = self.obj.data.edit_bones bone_e = eb[bone] # Parenting bone_e.use_connect = False bone_e.parent = eb[b[0]] # Position flip_bone(self.obj, bone) bone_e.tail = Vector(eb[b[0]].head) #bone_e.head = Vector(eb[b[0]].tail) if prev_bone == None: pass # Position base bone wherever you want, for now do nothing (i.e. position at hips) else: put_bone(self.obj, bone, eb[prev_bone].tail) prev_bone = bone # Constraints bpy.ops.object.mode_set(mode='OBJECT') pb = self.obj.pose.bones prev_bone = None for bone in rev_bones: bone_p = pb[bone] con = bone_p.constraints.new('COPY_LOCATION') con.name = "copy_location" con.target = self.obj if prev_bone == None: con.subtarget = hip_control # Position base bone wherever you want, for now hips else: con.subtarget = prev_bone con.head_tail = 1.0 prev_bone = bone #--------------------------------------------- # Constrain org bones to flex bone's rotation pb = self.obj.pose.bones for b in zip(self.org_bones, flex_bones): con = pb[b[0]].constraints.new('COPY_TRANSFORMS') con.name = "copy_rotation" con.target = self.obj con.subtarget = b[1] #--------------------------- # Create pivot slide system pb = self.obj.pose.bones bone_p = pb[self.org_bones[0]] rib_control_p = pb[rib_control] # Custom pivot_slide property prop = rna_idprop_ui_prop_get(rib_control_p, "pivot_slide", create=True) rib_control_p["pivot_slide"] = 1.0 / len(self.org_bones) prop["min"] = 0.0 prop["max"] = 1.0 prop["soft_min"] = 1.0 / len(self.org_bones) prop["soft_max"] = 1.0 - (1.0 / len(self.org_bones)) # Anchor constraint con = bone_p.constraints.new('COPY_LOCATION') con.name = "copy_location" con.target = self.obj con.subtarget = rev_bones[0] # Slide constraints i = 1 tot = len(rev_bones) for rb in rev_bones: con = bone_p.constraints.new('COPY_LOCATION') con.name = "slide." + str(i) con.target = self.obj con.subtarget = rb con.head_tail = 1.0 # Driver fcurve = con.driver_add("influence") driver = fcurve.driver var = driver.variables.new() driver.type = 'AVERAGE' var.name = "slide" var.targets[0].id_type = 'OBJECT' var.targets[0].id = self.obj var.targets[0].data_path = rib_control_p.path_from_id( ) + '["pivot_slide"]' mod = fcurve.modifiers[0] mod.poly_order = 1 mod.coefficients[0] = 1 - i mod.coefficients[1] = tot i += 1 # Create control widgets w1 = create_circle_widget(self.obj, hip_control, radius=1.0, head_tail=1.0) w2 = create_circle_widget(self.obj, rib_control, radius=1.0, head_tail=0.0) if w1 != None: obj_to_bone(w1, self.obj, self.org_bones[0]) if w2 != None: obj_to_bone(w2, self.obj, self.org_bones[-1]) # Return control names return hip_control, rib_control
def gen_control(self): """ Generate the control rig. """ #--------------------------------- # Create the neck and head controls bpy.ops.object.mode_set(mode='EDIT') # Create bones neck_ctrl = copy_bone(self.obj, self.org_bones[0], strip_org(self.org_bones[0])) neck_follow = copy_bone(self.obj, self.org_bones[-1], make_mechanism_name(strip_org(self.org_bones[0] + ".follow"))) neck_child = new_bone(self.obj, make_mechanism_name(strip_org(self.org_bones[0] + ".child"))) head_ctrl = copy_bone(self.obj, self.org_bones[-1], strip_org(self.org_bones[-1])) head_mch = new_bone(self.obj, make_mechanism_name(strip_org(self.org_bones[-1]))) if self.isolate: head_socket1 = copy_bone(self.obj, self.org_bones[-1], make_mechanism_name(strip_org(self.org_bones[-1] + ".socket1"))) head_socket2 = copy_bone(self.obj, self.org_bones[-1], make_mechanism_name(strip_org(self.org_bones[-1] + ".socket2"))) # Create neck chain bones neck = [] helpers = [] for name in self.org_bones: neck += [copy_bone(self.obj, name, make_mechanism_name(strip_org(name)))] helpers += [copy_bone(self.obj, neck_child, make_mechanism_name(strip_org(name + ".02")))] # Fetch edit bones eb = self.obj.data.edit_bones neck_ctrl_e = eb[neck_ctrl] neck_follow_e = eb[neck_follow] neck_child_e = eb[neck_child] head_ctrl_e = eb[head_ctrl] head_mch_e = eb[head_mch] if self.isolate: head_socket1_e = eb[head_socket1] head_socket2_e = eb[head_socket2] # Parenting head_ctrl_e.use_connect = False head_ctrl_e.parent = neck_ctrl_e.parent head_mch_e.use_connect = False head_mch_e.parent = head_ctrl_e if self.isolate: head_socket1_e.use_connect = False head_socket1_e.parent = neck_ctrl_e.parent head_socket2_e.use_connect = False head_socket2_e.parent = None head_ctrl_e.parent = head_socket2_e for (name1, name2) in zip(neck, helpers): eb[name1].use_connect = False eb[name1].parent = eb[name2] eb[name2].use_connect = False eb[name2].parent = neck_ctrl_e.parent neck_follow_e.use_connect = False neck_follow_e.parent = neck_ctrl_e.parent neck_child_e.use_connect = False neck_child_e.parent = neck_ctrl_e neck_ctrl_e.parent = neck_follow_e # Position put_bone(self.obj, neck_follow, neck_ctrl_e.head) put_bone(self.obj, neck_child, neck_ctrl_e.head) put_bone(self.obj, head_ctrl, neck_ctrl_e.head) put_bone(self.obj, head_mch, neck_ctrl_e.head) head_mch_e.length = head_ctrl_e.length / 2 neck_child_e.length = neck_ctrl_e.length / 2 if self.isolate: put_bone(self.obj, head_socket1, neck_ctrl_e.head) head_mch_e.length /= 2 put_bone(self.obj, head_socket2, neck_ctrl_e.head) head_mch_e.length /= 3 for (name1, name2) in zip(neck, helpers): put_bone(self.obj, name2, eb[name1].head) eb[name2].length = eb[name1].length / 2 # Switch to object mode bpy.ops.object.mode_set(mode='OBJECT') pb = self.obj.pose.bones neck_ctrl_p = pb[neck_ctrl] neck_follow_p = pb[neck_follow] # neck_child_p = pb[neck_child] # UNUSED head_ctrl_p = pb[head_ctrl] if self.isolate: # head_socket1_p = pb[head_socket1] # UNUSED head_socket2_p = pb[head_socket2] # Custom bone appearance neck_ctrl_p.custom_shape_transform = pb[self.org_bones[(len(self.org_bones) - 1) // 2]] head_ctrl_p.custom_shape_transform = pb[self.org_bones[-1]] # Custom properties prop = rna_idprop_ui_prop_get(head_ctrl_p, "inf_extent", create=True) head_ctrl_p["inf_extent"] = 0.5 prop["min"] = 0.0 prop["max"] = 1.0 prop["soft_min"] = 0.0 prop["soft_max"] = 1.0 prop = rna_idprop_ui_prop_get(head_ctrl_p, "neck_follow", create=True) head_ctrl_p["neck_follow"] = 1.0 prop["min"] = 0.0 prop["max"] = 2.0 prop["soft_min"] = 0.0 prop["soft_max"] = 1.0 if self.isolate: prop = rna_idprop_ui_prop_get(head_ctrl_p, "isolate", create=True) head_ctrl_p["isolate"] = 0.0 prop["min"] = 0.0 prop["max"] = 1.0 prop["soft_min"] = 0.0 prop["soft_max"] = 1.0 # Constraints # Neck follow con = neck_follow_p.constraints.new('COPY_ROTATION') con.name = "copy_rotation" con.target = self.obj con.subtarget = head_ctrl fcurve = con.driver_add("influence") driver = fcurve.driver var = driver.variables.new() driver.type = 'SCRIPTED' var.name = "follow" var.targets[0].id_type = 'OBJECT' var.targets[0].id = self.obj var.targets[0].data_path = head_ctrl_p.path_from_id() + '["neck_follow"]' driver.expression = "follow / 2" # Isolate if self.isolate: con = head_socket2_p.constraints.new('COPY_LOCATION') con.name = "copy_location" con.target = self.obj con.subtarget = head_socket1 con = head_socket2_p.constraints.new('COPY_TRANSFORMS') con.name = "copy_transforms" con.target = self.obj con.subtarget = head_socket1 fcurve = con.driver_add("influence") driver = fcurve.driver var = driver.variables.new() driver.type = 'SCRIPTED' var.name = "isolate" var.targets[0].id_type = 'OBJECT' var.targets[0].id = self.obj var.targets[0].data_path = head_ctrl_p.path_from_id() + '["isolate"]' driver.expression = "1.0 - isolate" # Neck chain first = True prev = None i = 0 l = len(neck) for (name1, name2, org_name) in zip(neck, helpers, self.org_bones): con = pb[org_name].constraints.new('COPY_TRANSFORMS') con.name = "copy_transforms" con.target = self.obj con.subtarget = name1 n_con = pb[name2].constraints.new('COPY_TRANSFORMS') n_con.name = "neck" n_con.target = self.obj n_con.subtarget = neck_child h_con = pb[name2].constraints.new('COPY_TRANSFORMS') h_con.name = "head" h_con.target = self.obj h_con.subtarget = head_mch con = pb[name2].constraints.new('COPY_LOCATION') con.name = "anchor" con.target = self.obj if first: con.subtarget = neck_ctrl else: con.subtarget = prev con.head_tail = 1.0 # Drivers n = (i + 1) / l # Neck influence fcurve = n_con.driver_add("influence") driver = fcurve.driver var = driver.variables.new() driver.type = 'SCRIPTED' var.name = "ext" var.targets[0].id_type = 'OBJECT' var.targets[0].id = self.obj var.targets[0].data_path = head_ctrl_p.path_from_id() + '["inf_extent"]' driver.expression = "1.0 if (%.4f > (1.0-ext) or (1.0-ext) == 0.0) else (%.4f / (1.0-ext))" % (n, n) # Head influence if (i + 1) == l: h_con.influence = 1.0 else: fcurve = h_con.driver_add("influence") driver = fcurve.driver var = driver.variables.new() driver.type = 'SCRIPTED' var.name = "ext" var.targets[0].id_type = 'OBJECT' var.targets[0].id = self.obj var.targets[0].data_path = head_ctrl_p.path_from_id() + '["inf_extent"]' driver.expression = "0.0 if (%.4f <= (1.0-ext)) else ((%.4f - (1.0-ext)) / ext)" % (n, n) first = False prev = name1 i += 1 # Create control widgets w1 = create_circle_widget(self.obj, neck_ctrl, radius=1.0, head_tail=0.5) w2 = create_circle_widget(self.obj, head_ctrl, radius=1.0, head_tail=0.5) if w1 != None: obj_to_bone(w1, self.obj, self.org_bones[(len(self.org_bones) - 1) // 2]) if w2 != None: obj_to_bone(w2, self.obj, self.org_bones[-1]) # Return control bones return (head_ctrl, neck_ctrl)
def gen_control(self): """ Generate the control rig. """ bpy.ops.object.mode_set(mode='EDIT') eb = self.obj.data.edit_bones #------------------------- # Get rest slide position a = self.pivot_rest * len(self.org_bones) i = floor(a) a -= i if i == len(self.org_bones): i -= 1 a = 1.0 pivot_rest_pos = eb[self.org_bones[i]].head.copy() pivot_rest_pos += eb[self.org_bones[i]].vector * a #---------------------- # Create controls # Create control bones controls = [] for i in self.control_indices: name = copy_bone(self.obj, self.org_bones[i], strip_org(self.org_bones[i])) controls += [name] # Create control parents control_parents = [] for i in self.control_indices[1:-1]: name = new_bone(self.obj, make_mechanism_name("par_" + strip_org(self.org_bones[i]))) control_parents += [name] # Create sub-control bones subcontrols = [] for i in self.control_indices: name = new_bone(self.obj, make_mechanism_name("sub_" + strip_org(self.org_bones[i]))) subcontrols += [name] # Create main control bone main_control = new_bone(self.obj, self.params.spine_main_control_name) # Create main control WGT bones main_wgt1 = new_bone(self.obj, make_mechanism_name(self.params.spine_main_control_name + ".01")) main_wgt2 = new_bone(self.obj, make_mechanism_name(self.params.spine_main_control_name + ".02")) eb = self.obj.data.edit_bones # Parent the main control eb[main_control].use_connect = False eb[main_control].parent = eb[self.org_bones[0]].parent # Parent the main WGTs eb[main_wgt1].use_connect = False eb[main_wgt1].parent = eb[main_control] eb[main_wgt2].use_connect = False eb[main_wgt2].parent = eb[main_wgt1] # Parent the controls and sub-controls for name, subname in zip(controls, subcontrols): eb[name].use_connect = False eb[name].parent = eb[main_control] eb[subname].use_connect = False eb[subname].parent = eb[name] # Parent the control parents for name, par_name in zip(controls[1:-1], control_parents): eb[par_name].use_connect = False eb[par_name].parent = eb[main_control] eb[name].parent = eb[par_name] # Position the main bone put_bone(self.obj, main_control, pivot_rest_pos) eb[main_control].length = sum([eb[b].length for b in self.org_bones]) / 2 # Position the main WGTs eb[main_wgt1].tail = (0.0, 0.0, sum([eb[b].length for b in self.org_bones]) / 4) eb[main_wgt2].length = sum([eb[b].length for b in self.org_bones]) / 4 put_bone(self.obj, main_wgt1, pivot_rest_pos) put_bone(self.obj, main_wgt2, pivot_rest_pos) # Position the controls and sub-controls pos = eb[controls[0]].head.copy() for name, subname in zip(controls, subcontrols): put_bone(self.obj, name, pivot_rest_pos) put_bone(self.obj, subname, pivot_rest_pos) eb[subname].length = eb[name].length / 3 # Position the control parents for name, par_name in zip(controls[1:-1], control_parents): put_bone(self.obj, par_name, pivot_rest_pos) eb[par_name].length = eb[name].length / 2 #----------------------------------------- # Control bone constraints and properties bpy.ops.object.mode_set(mode='OBJECT') pb = self.obj.pose.bones # Lock control locations for name in controls: bone = pb[name] bone.lock_location = True, True, True # Main control doesn't use local location pb[main_control].bone.use_local_location = False # Intermediate controls follow hips and spine for name, par_name, i in zip(controls[1:-1], control_parents, self.control_indices[1:-1]): bone = pb[par_name] # Custom bend_alpha property prop = rna_idprop_ui_prop_get(pb[name], "bend_alpha", create=True) pb[name]["bend_alpha"] = i / (len(self.org_bones) - 1) # set bend alpha prop["min"] = 0.0 prop["max"] = 1.0 prop["soft_min"] = 0.0 prop["soft_max"] = 1.0 # Custom auto_rotate prop = rna_idprop_ui_prop_get(pb[name], "auto_rotate", create=True) pb[name]["auto_rotate"] = 1.0 prop["min"] = 0.0 prop["max"] = 1.0 prop["soft_min"] = 0.0 prop["soft_max"] = 1.0 # Constraints con1 = bone.constraints.new('COPY_TRANSFORMS') con1.name = "copy_transforms" con1.target = self.obj con1.subtarget = subcontrols[0] con2 = bone.constraints.new('COPY_TRANSFORMS') con2.name = "copy_transforms" con2.target = self.obj con2.subtarget = subcontrols[-1] # Drivers fcurve = con1.driver_add("influence") driver = fcurve.driver driver.type = 'AVERAGE' var = driver.variables.new() var.name = "auto" var.targets[0].id_type = 'OBJECT' var.targets[0].id = self.obj var.targets[0].data_path = pb[name].path_from_id() + '["auto_rotate"]' fcurve = con2.driver_add("influence") driver = fcurve.driver driver.type = 'SCRIPTED' driver.expression = "alpha * auto" var = driver.variables.new() var.name = "alpha" var.targets[0].id_type = 'OBJECT' var.targets[0].id = self.obj var.targets[0].data_path = pb[name].path_from_id() + '["bend_alpha"]' var = driver.variables.new() var.name = "auto" var.targets[0].id_type = 'OBJECT' var.targets[0].id = self.obj var.targets[0].data_path = pb[name].path_from_id() + '["auto_rotate"]' #------------------------- # Create flex spine chain bpy.ops.object.mode_set(mode='EDIT') flex_bones = [] flex_subs = [] prev_bone = None for b in self.org_bones: # Create bones bone = copy_bone(self.obj, b, make_mechanism_name(strip_org(b) + ".flex")) sub = new_bone(self.obj, make_mechanism_name(strip_org(b) + ".flex_s")) flex_bones += [bone] flex_subs += [sub] eb = self.obj.data.edit_bones bone_e = eb[bone] sub_e = eb[sub] # Parenting bone_e.use_connect = False sub_e.use_connect = False if prev_bone is None: sub_e.parent = eb[controls[0]] else: sub_e.parent = eb[prev_bone] bone_e.parent = sub_e # Position put_bone(self.obj, sub, bone_e.head) sub_e.length = bone_e.length / 4 if prev_bone is not None: sub_e.use_connect = True prev_bone = bone #---------------------------- # Create reverse spine chain # Create bones/parenting/positioning bpy.ops.object.mode_set(mode='EDIT') rev_bones = [] prev_bone = None for b in zip(flex_bones, self.org_bones): # Create bones bone = copy_bone(self.obj, b[1], make_mechanism_name(strip_org(b[1]) + ".reverse")) rev_bones += [bone] eb = self.obj.data.edit_bones bone_e = eb[bone] # Parenting bone_e.use_connect = False bone_e.parent = eb[b[0]] # Position flip_bone(self.obj, bone) bone_e.tail = Vector(eb[b[0]].head) #bone_e.head = Vector(eb[b[0]].tail) if prev_bone is None: put_bone(self.obj, bone, pivot_rest_pos) else: put_bone(self.obj, bone, eb[prev_bone].tail) prev_bone = bone # Constraints bpy.ops.object.mode_set(mode='OBJECT') pb = self.obj.pose.bones prev_bone = None for bone in rev_bones: bone_p = pb[bone] con = bone_p.constraints.new('COPY_LOCATION') con.name = "copy_location" con.target = self.obj if prev_bone is None: con.subtarget = main_control else: con.subtarget = prev_bone con.head_tail = 1.0 prev_bone = bone #---------------------------------------- # Constrain original bones to flex spine bpy.ops.object.mode_set(mode='OBJECT') pb = self.obj.pose.bones for obone, fbone in zip(self.org_bones, flex_bones): con = pb[obone].constraints.new('COPY_TRANSFORMS') con.name = "copy_transforms" con.target = self.obj con.subtarget = fbone #--------------------------- # Create pivot slide system pb = self.obj.pose.bones bone_p = pb[self.org_bones[0]] main_control_p = pb[main_control] # Custom pivot_slide property prop = rna_idprop_ui_prop_get(main_control_p, "pivot_slide", create=True) main_control_p["pivot_slide"] = self.pivot_rest prop["min"] = 0.0 prop["max"] = 1.0 prop["soft_min"] = 1.0 / len(self.org_bones) prop["soft_max"] = 1.0 - (1.0 / len(self.org_bones)) # Anchor constraints con = bone_p.constraints.new('COPY_LOCATION') con.name = "copy_location" con.target = self.obj con.subtarget = rev_bones[0] con = pb[main_wgt1].constraints.new('COPY_ROTATION') con.name = "copy_rotation" con.target = self.obj con.subtarget = rev_bones[0] # Slide constraints i = 1 tot = len(rev_bones) for rb in rev_bones: con = bone_p.constraints.new('COPY_LOCATION') con.name = "slide." + str(i) con.target = self.obj con.subtarget = rb con.head_tail = 1.0 # Driver fcurve = con.driver_add("influence") driver = fcurve.driver var = driver.variables.new() driver.type = 'AVERAGE' var.name = "slide" var.targets[0].id_type = 'OBJECT' var.targets[0].id = self.obj var.targets[0].data_path = main_control_p.path_from_id() + '["pivot_slide"]' mod = fcurve.modifiers[0] mod.poly_order = 1 mod.coefficients[0] = 1 - i mod.coefficients[1] = tot # Main WGT con = pb[main_wgt1].constraints.new('COPY_ROTATION') con.name = "slide." + str(i) con.target = self.obj con.subtarget = rb # Driver fcurve = con.driver_add("influence") driver = fcurve.driver var = driver.variables.new() driver.type = 'AVERAGE' var.name = "slide" var.targets[0].id_type = 'OBJECT' var.targets[0].id = self.obj var.targets[0].data_path = main_control_p.path_from_id() + '["pivot_slide"]' mod = fcurve.modifiers[0] mod.poly_order = 1 mod.coefficients[0] = 1.5 - i mod.coefficients[1] = tot i += 1 #---------------------------------- # Constrain flex spine to controls bpy.ops.object.mode_set(mode='OBJECT') pb = self.obj.pose.bones # Constrain the bones that correspond exactly to the controls for i, name in zip(self.control_indices, subcontrols): con = pb[flex_subs[i]].constraints.new('COPY_TRANSFORMS') con.name = "copy_transforms" con.target = self.obj con.subtarget = name # Constrain the bones in-between the controls for i, j, name1, name2 in zip(self.control_indices, self.control_indices[1:], subcontrols, subcontrols[1:]): if (i + 1) < j: for n in range(i + 1, j): bone = pb[flex_subs[n]] # Custom bend_alpha property prop = rna_idprop_ui_prop_get(bone, "bend_alpha", create=True) bone["bend_alpha"] = (n - i) / (j - i) # set bend alpha prop["min"] = 0.0 prop["max"] = 1.0 prop["soft_min"] = 0.0 prop["soft_max"] = 1.0 con = bone.constraints.new('COPY_TRANSFORMS') con.name = "copy_transforms" con.target = self.obj con.subtarget = name1 con = bone.constraints.new('COPY_TRANSFORMS') con.name = "copy_transforms" con.target = self.obj con.subtarget = name2 # Driver fcurve = con.driver_add("influence") driver = fcurve.driver var = driver.variables.new() driver.type = 'AVERAGE' var.name = "alpha" var.targets[0].id_type = 'OBJECT' var.targets[0].id = self.obj var.targets[0].data_path = bone.path_from_id() + '["bend_alpha"]' #------------- # Final stuff bpy.ops.object.mode_set(mode='OBJECT') pb = self.obj.pose.bones # Control appearance # Main pb[main_control].custom_shape_transform = pb[main_wgt2] w = create_compass_widget(self.obj, main_control) if w != None: obj_to_bone(w, self.obj, main_wgt2) # Spines for name, i in zip(controls[1:-1], self.control_indices[1:-1]): pb[name].custom_shape_transform = pb[self.org_bones[i]] # Create control widgets w = create_circle_widget(self.obj, name, radius=1.0, head_tail=0.5, with_line=True) if w != None: obj_to_bone(w, self.obj, self.org_bones[i]) # Hips pb[controls[0]].custom_shape_transform = pb[self.org_bones[0]] # Create control widgets w = create_circle_widget(self.obj, controls[0], radius=1.0, head_tail=0.5, with_line=True) if w != None: obj_to_bone(w, self.obj, self.org_bones[0]) # Ribs pb[controls[-1]].custom_shape_transform = pb[self.org_bones[-1]] # Create control widgets w = create_circle_widget(self.obj, controls[-1], radius=1.0, head_tail=0.5, with_line=True) if w != None: obj_to_bone(w, self.obj, self.org_bones[-1]) # Layers pb[main_control].bone.layers = pb[self.org_bones[0]].bone.layers return [main_control] + controls
def generate(self): """ Generate the rig. Do NOT modify any of the original bones, except for adding constraints. The main armature should be selected and active before this is called. """ bpy.ops.object.mode_set(mode='EDIT') make_rocker = False if self.org_bones[5] is not None: make_rocker = True # Create the bones thigh = copy_bone( self.obj, self.org_bones[0], make_mechanism_name( strip_org(insert_before_lr(self.org_bones[0], "_ik")))) shin = copy_bone( self.obj, self.org_bones[1], make_mechanism_name( strip_org(insert_before_lr(self.org_bones[1], "_ik")))) foot = copy_bone(self.obj, self.org_bones[2], strip_org(insert_before_lr(self.org_bones[2], "_ik"))) foot_ik_target = copy_bone( self.obj, self.org_bones[2], make_mechanism_name( strip_org(insert_before_lr(self.org_bones[2], "_ik_target")))) pole = copy_bone( self.obj, self.org_bones[0], strip_org(insert_before_lr(self.org_bones[0], "_pole"))) toe = copy_bone(self.obj, self.org_bones[3], strip_org(self.org_bones[3])) toe_parent = copy_bone( self.obj, self.org_bones[2], make_mechanism_name(strip_org(self.org_bones[3] + ".parent"))) toe_parent_socket1 = copy_bone( self.obj, self.org_bones[2], make_mechanism_name(strip_org(self.org_bones[3] + ".socket1"))) toe_parent_socket2 = copy_bone( self.obj, self.org_bones[2], make_mechanism_name(strip_org(self.org_bones[3] + ".socket2"))) foot_roll = copy_bone( self.obj, self.org_bones[4], strip_org(insert_before_lr(self.org_bones[2], "_roll"))) roll1 = copy_bone( self.obj, self.org_bones[4], make_mechanism_name(strip_org(self.org_bones[2] + ".roll.01"))) roll2 = copy_bone( self.obj, self.org_bones[4], make_mechanism_name(strip_org(self.org_bones[2] + ".roll.02"))) if make_rocker: rocker1 = copy_bone( self.obj, self.org_bones[5], make_mechanism_name(strip_org(self.org_bones[2] + ".rocker.01"))) rocker2 = copy_bone( self.obj, self.org_bones[5], make_mechanism_name(strip_org(self.org_bones[2] + ".rocker.02"))) visfoot = copy_bone( self.obj, self.org_bones[2], "VIS-" + strip_org(insert_before_lr(self.org_bones[2], "_ik"))) vispole = copy_bone( self.obj, self.org_bones[1], "VIS-" + strip_org(insert_before_lr(self.org_bones[0], "_pole"))) # Get edit bones eb = self.obj.data.edit_bones org_foot_e = eb[self.org_bones[2]] thigh_e = eb[thigh] shin_e = eb[shin] foot_e = eb[foot] foot_ik_target_e = eb[foot_ik_target] pole_e = eb[pole] toe_e = eb[toe] toe_parent_e = eb[toe_parent] toe_parent_socket1_e = eb[toe_parent_socket1] toe_parent_socket2_e = eb[toe_parent_socket2] foot_roll_e = eb[foot_roll] roll1_e = eb[roll1] roll2_e = eb[roll2] if make_rocker: rocker1_e = eb[rocker1] rocker2_e = eb[rocker2] visfoot_e = eb[visfoot] vispole_e = eb[vispole] # Parenting shin_e.parent = thigh_e foot_e.use_connect = False foot_e.parent = None foot_ik_target_e.use_connect = False foot_ik_target_e.parent = roll2_e pole_e.use_connect = False pole_e.parent = foot_e toe_e.parent = toe_parent_e toe_parent_e.use_connect = False toe_parent_e.parent = toe_parent_socket1_e toe_parent_socket1_e.use_connect = False toe_parent_socket1_e.parent = roll1_e toe_parent_socket2_e.use_connect = False toe_parent_socket2_e.parent = eb[self.org_bones[2]] foot_roll_e.use_connect = False foot_roll_e.parent = foot_e roll1_e.use_connect = False roll1_e.parent = foot_e roll2_e.use_connect = False roll2_e.parent = roll1_e visfoot_e.use_connect = False visfoot_e.parent = None vispole_e.use_connect = False vispole_e.parent = None if make_rocker: rocker1_e.use_connect = False rocker2_e.use_connect = False roll1_e.parent = rocker2_e rocker2_e.parent = rocker1_e rocker1_e.parent = foot_e # Misc foot_e.use_local_location = False visfoot_e.hide_select = True vispole_e.hide_select = True # Positioning vec = Vector(toe_e.vector) vec.normalize() foot_e.tail = foot_e.head + (vec * foot_e.length) foot_e.roll = toe_e.roll v1 = shin_e.tail - thigh_e.head if 'X' in self.primary_rotation_axis or 'Y' in self.primary_rotation_axis: v2 = v1.cross(shin_e.x_axis) if (v2 * shin_e.z_axis) > 0.0: v2 *= -1.0 else: v2 = v1.cross(shin_e.z_axis) if (v2 * shin_e.x_axis) < 0.0: v2 *= -1.0 v2.normalize() v2 *= v1.length if '-' in self.primary_rotation_axis: v2 *= -1 pole_e.head = shin_e.head + v2 pole_e.tail = pole_e.head + (Vector((0, 1, 0)) * (v1.length / 8)) pole_e.roll = 0.0 flip_bone(self.obj, toe_parent_socket1) flip_bone(self.obj, toe_parent_socket2) toe_parent_socket1_e.head = Vector(org_foot_e.tail) toe_parent_socket2_e.head = Vector(org_foot_e.tail) toe_parent_socket1_e.tail = Vector(org_foot_e.tail) + (Vector( (0, 0, 1)) * foot_e.length / 2) toe_parent_socket2_e.tail = Vector(org_foot_e.tail) + (Vector( (0, 0, 1)) * foot_e.length / 3) toe_parent_socket2_e.roll = toe_parent_socket1_e.roll tail = Vector(roll1_e.tail) roll1_e.tail = Vector(org_foot_e.tail) roll1_e.tail = Vector(org_foot_e.tail) roll1_e.head = tail roll2_e.head = Vector(org_foot_e.tail) foot_roll_e.head = Vector(org_foot_e.tail) put_bone(self.obj, foot_roll, roll1_e.head) foot_roll_e.length /= 2 roll_axis = roll1_e.vector.cross(org_foot_e.vector) align_x_axis(self.obj, roll1, roll_axis) align_x_axis(self.obj, roll2, roll_axis) foot_roll_e.roll = roll2_e.roll visfoot_e.tail = visfoot_e.head + Vector((0, 0, v1.length / 32)) vispole_e.tail = vispole_e.head + Vector((0, 0, v1.length / 32)) if make_rocker: d = toe_e.y_axis.dot(rocker1_e.x_axis) if d >= 0.0: flip_bone(self.obj, rocker2) else: flip_bone(self.obj, rocker1) # Weird alignment issues. Fix. toe_parent_e.head = Vector(org_foot_e.head) toe_parent_e.tail = Vector(org_foot_e.tail) toe_parent_e.roll = org_foot_e.roll foot_e.head = Vector(org_foot_e.head) foot_ik_target_e.head = Vector(org_foot_e.head) foot_ik_target_e.tail = Vector(org_foot_e.tail) # Determine the pole offset value plane = (shin_e.tail - thigh_e.head).normalized() vec1 = thigh_e.x_axis.normalized() vec2 = (pole_e.head - thigh_e.head).normalized() pole_offset = angle_on_plane(plane, vec1, vec2) # Object mode, get pose bones bpy.ops.object.mode_set(mode='OBJECT') pb = self.obj.pose.bones # thigh_p = pb[thigh] # UNUSED shin_p = pb[shin] foot_p = pb[foot] pole_p = pb[pole] foot_roll_p = pb[foot_roll] roll1_p = pb[roll1] roll2_p = pb[roll2] if make_rocker: rocker1_p = pb[rocker1] rocker2_p = pb[rocker2] toe_p = pb[toe] toe_parent_p = pb[toe_parent] toe_parent_socket1_p = pb[toe_parent_socket1] visfoot_p = pb[visfoot] vispole_p = pb[vispole] # Set the knee to only bend on the primary axis. if 'X' in self.primary_rotation_axis: shin_p.lock_ik_y = True shin_p.lock_ik_z = True elif 'Y' in self.primary_rotation_axis: shin_p.lock_ik_x = True shin_p.lock_ik_z = True else: shin_p.lock_ik_x = True shin_p.lock_ik_y = True # Foot roll control only rotates on x-axis, or x and y if rocker. foot_roll_p.rotation_mode = 'XYZ' if make_rocker: foot_roll_p.lock_rotation = False, False, True else: foot_roll_p.lock_rotation = False, True, True foot_roll_p.lock_location = True, True, True foot_roll_p.lock_scale = True, True, True # roll and rocker bones set to euler rotation roll1_p.rotation_mode = 'XYZ' roll2_p.rotation_mode = 'XYZ' if make_rocker: rocker1_p.rotation_mode = 'XYZ' rocker2_p.rotation_mode = 'XYZ' # Pole target only translates pole_p.lock_location = False, False, False pole_p.lock_rotation = True, True, True pole_p.lock_rotation_w = True pole_p.lock_scale = True, True, True # Set up custom properties if self.switch == True: prop = rna_idprop_ui_prop_get(foot_p, "ikfk_switch", create=True) foot_p["ikfk_switch"] = 0.0 prop["soft_min"] = prop["min"] = 0.0 prop["soft_max"] = prop["max"] = 1.0 # Bend direction hint if self.bend_hint: con = shin_p.constraints.new('LIMIT_ROTATION') con.name = "bend_hint" con.owner_space = 'LOCAL' if self.primary_rotation_axis == 'X': con.use_limit_x = True con.min_x = pi / 10 con.max_x = pi / 10 elif self.primary_rotation_axis == '-X': con.use_limit_x = True con.min_x = -pi / 10 con.max_x = -pi / 10 elif self.primary_rotation_axis == 'Y': con.use_limit_y = True con.min_y = pi / 10 con.max_y = pi / 10 elif self.primary_rotation_axis == '-Y': con.use_limit_y = True con.min_y = -pi / 10 con.max_y = -pi / 10 elif self.primary_rotation_axis == 'Z': con.use_limit_z = True con.min_z = pi / 10 con.max_z = pi / 10 elif self.primary_rotation_axis == '-Z': con.use_limit_z = True con.min_z = -pi / 10 con.max_z = -pi / 10 # IK Constraint con = shin_p.constraints.new('IK') con.name = "ik" con.target = self.obj con.subtarget = foot_ik_target con.pole_target = self.obj con.pole_subtarget = pole con.pole_angle = pole_offset con.chain_count = 2 # toe_parent constraint con = toe_parent_socket1_p.constraints.new('COPY_LOCATION') con.name = "copy_location" con.target = self.obj con.subtarget = toe_parent_socket2 con = toe_parent_socket1_p.constraints.new('COPY_SCALE') con.name = "copy_scale" con.target = self.obj con.subtarget = toe_parent_socket2 con = toe_parent_socket1_p.constraints.new( 'COPY_TRANSFORMS') # drive with IK switch con.name = "fk" con.target = self.obj con.subtarget = toe_parent_socket2 fcurve = con.driver_add("influence") driver = fcurve.driver var = driver.variables.new() driver.type = 'AVERAGE' var.name = "var" var.targets[0].id_type = 'OBJECT' var.targets[0].id = self.obj var.targets[0].data_path = foot_p.path_from_id() + '["ikfk_switch"]' mod = fcurve.modifiers[0] mod.poly_order = 1 mod.coefficients[0] = 1.0 mod.coefficients[1] = -1.0 # Foot roll drivers fcurve = roll1_p.driver_add("rotation_euler", 0) driver = fcurve.driver var = driver.variables.new() driver.type = 'SCRIPTED' driver.expression = "min(0,var)" var.name = "var" var.targets[0].id_type = 'OBJECT' var.targets[0].id = self.obj var.targets[0].data_path = foot_roll_p.path_from_id( ) + '.rotation_euler[0]' fcurve = roll2_p.driver_add("rotation_euler", 0) driver = fcurve.driver var = driver.variables.new() driver.type = 'SCRIPTED' driver.expression = "max(0,var)" var.name = "var" var.targets[0].id_type = 'OBJECT' var.targets[0].id = self.obj var.targets[0].data_path = foot_roll_p.path_from_id( ) + '.rotation_euler[0]' if make_rocker: fcurve = rocker1_p.driver_add("rotation_euler", 0) driver = fcurve.driver var = driver.variables.new() driver.type = 'SCRIPTED' driver.expression = "max(0,-var)" var.name = "var" var.targets[0].id_type = 'OBJECT' var.targets[0].id = self.obj var.targets[0].data_path = foot_roll_p.path_from_id( ) + '.rotation_euler[1]' fcurve = rocker2_p.driver_add("rotation_euler", 0) driver = fcurve.driver var = driver.variables.new() driver.type = 'SCRIPTED' driver.expression = "max(0,var)" var.name = "var" var.targets[0].id_type = 'OBJECT' var.targets[0].id = self.obj var.targets[0].data_path = foot_roll_p.path_from_id( ) + '.rotation_euler[1]' # Constrain org bones to controls con = pb[self.org_bones[0]].constraints.new('COPY_TRANSFORMS') con.name = "ik" con.target = self.obj con.subtarget = thigh if self.switch == True: # IK/FK switch driver fcurve = con.driver_add("influence") driver = fcurve.driver var = driver.variables.new() driver.type = 'AVERAGE' var.name = "var" var.targets[0].id_type = 'OBJECT' var.targets[0].id = self.obj var.targets[0].data_path = foot_p.path_from_id( ) + '["ikfk_switch"]' con = pb[self.org_bones[1]].constraints.new('COPY_TRANSFORMS') con.name = "ik" con.target = self.obj con.subtarget = shin if self.switch == True: # IK/FK switch driver fcurve = con.driver_add("influence") driver = fcurve.driver var = driver.variables.new() driver.type = 'AVERAGE' var.name = "var" var.targets[0].id_type = 'OBJECT' var.targets[0].id = self.obj var.targets[0].data_path = foot_p.path_from_id( ) + '["ikfk_switch"]' con = pb[self.org_bones[2]].constraints.new('COPY_TRANSFORMS') con.name = "ik" con.target = self.obj con.subtarget = foot_ik_target if self.switch == True: # IK/FK switch driver fcurve = con.driver_add("influence") driver = fcurve.driver var = driver.variables.new() driver.type = 'AVERAGE' var.name = "var" var.targets[0].id_type = 'OBJECT' var.targets[0].id = self.obj var.targets[0].data_path = foot_p.path_from_id( ) + '["ikfk_switch"]' con = pb[self.org_bones[3]].constraints.new('COPY_TRANSFORMS') con.name = "copy_transforms" con.target = self.obj con.subtarget = toe # VIS foot constraints con = visfoot_p.constraints.new('COPY_LOCATION') con.name = "copy_loc" con.target = self.obj con.subtarget = self.org_bones[2] con = visfoot_p.constraints.new('STRETCH_TO') con.name = "stretch_to" con.target = self.obj con.subtarget = foot con.volume = 'NO_VOLUME' con.rest_length = visfoot_p.length # VIS pole constraints con = vispole_p.constraints.new('COPY_LOCATION') con.name = "copy_loc" con.target = self.obj con.subtarget = self.org_bones[1] con = vispole_p.constraints.new('STRETCH_TO') con.name = "stretch_to" con.target = self.obj con.subtarget = pole con.volume = 'NO_VOLUME' con.rest_length = vispole_p.length # Set layers if specified if self.layers: foot_p.bone.layers = self.layers pole_p.bone.layers = self.layers foot_roll_p.bone.layers = self.layers visfoot_p.bone.layers = self.layers vispole_p.bone.layers = self.layers toe_p.bone.layers = [ (i[0] or i[1]) for i in zip(toe_p.bone.layers, self.layers) ] # Both FK and IK layers # Create widgets create_line_widget(self.obj, vispole) create_line_widget(self.obj, visfoot) create_sphere_widget(self.obj, pole) create_circle_widget(self.obj, toe, radius=0.7, head_tail=0.5) ob = create_widget(self.obj, foot) if ob != None: verts = [(0.7, 1.5, 0.0), (0.7, -0.25, 0.0), (-0.7, -0.25, 0.0), (-0.7, 1.5, 0.0), (0.7, 0.723, 0.0), (-0.7, 0.723, 0.0), (0.7, 0.0, 0.0), (-0.7, 0.0, 0.0)] edges = [(1, 2), (0, 3), (0, 4), (3, 5), (4, 6), (1, 6), (5, 7), (2, 7)] mesh = ob.data mesh.from_pydata(verts, edges, []) mesh.update() mod = ob.modifiers.new("subsurf", 'SUBSURF') mod.levels = 2 ob = create_widget(self.obj, foot_roll) if ob != None: verts = [ (0.3999999761581421, 0.766044557094574, 0.6427875757217407), (0.17668449878692627, 3.823702598992895e-08, 3.2084670920085046e-08), (-0.17668461799621582, 9.874240447516058e-08, 8.285470443070153e-08), (-0.39999961853027344, 0.7660449147224426, 0.6427879333496094), (0.3562471270561218, 0.6159579753875732, 0.5168500542640686), (-0.35624682903289795, 0.6159582138061523, 0.5168502926826477), (0.20492683351039886, 0.09688037633895874, 0.0812922865152359), (-0.20492687821388245, 0.0968804731965065, 0.08129236847162247) ] edges = [(1, 2), (0, 3), (0, 4), (3, 5), (1, 6), (4, 6), (2, 7), (5, 7)] mesh = ob.data mesh.from_pydata(verts, edges, []) mesh.update() mod = ob.modifiers.new("subsurf", 'SUBSURF') mod.levels = 2 return [thigh, shin, foot, pole, foot_roll, foot_ik_target]
def generate(self): """ Generate the rig. Do NOT modify any of the original bones, except for adding constraints. The main armature should be selected and active before this is called. """ bpy.ops.object.mode_set(mode='EDIT') # Create upper arm bones if self.use_thigh_twist: thigh1 = copy_bone(self.obj, self.org_bones[0], make_deformer_name(strip_org(self.org_bones[0] + ".01"))) thigh2 = copy_bone(self.obj, self.org_bones[0], make_deformer_name(strip_org(self.org_bones[0] + ".02"))) utip = copy_bone(self.obj, self.org_bones[0], make_mechanism_name(strip_org(self.org_bones[0] + ".tip"))) else: thigh = copy_bone(self.obj, self.org_bones[0], make_deformer_name(strip_org(self.org_bones[0]))) # Create forearm bones if self.use_shin_twist: shin1 = copy_bone(self.obj, self.org_bones[1], make_deformer_name(strip_org(self.org_bones[1] + ".01"))) shin2 = copy_bone(self.obj, self.org_bones[1], make_deformer_name(strip_org(self.org_bones[1] + ".02"))) stip = copy_bone(self.obj, self.org_bones[1], make_mechanism_name(strip_org(self.org_bones[1] + ".tip"))) else: shin = copy_bone(self.obj, self.org_bones[1], make_deformer_name(strip_org(self.org_bones[1]))) # Create foot bone foot = copy_bone(self.obj, self.org_bones[2], make_deformer_name(strip_org(self.org_bones[2]))) # Create toe bone toe = copy_bone(self.obj, self.org_bones[3], make_deformer_name(strip_org(self.org_bones[3]))) # Get edit bones eb = self.obj.data.edit_bones org_thigh_e = eb[self.org_bones[0]] if self.use_thigh_twist: thigh1_e = eb[thigh1] thigh2_e = eb[thigh2] utip_e = eb[utip] else: thigh_e = eb[thigh] org_shin_e = eb[self.org_bones[1]] if self.use_shin_twist: shin1_e = eb[shin1] shin2_e = eb[shin2] stip_e = eb[stip] else: shin_e = eb[shin] org_foot_e = eb[self.org_bones[2]] foot_e = eb[foot] org_toe_e = eb[self.org_bones[3]] toe_e = eb[toe] # Parent and position thigh bones if self.use_thigh_twist: thigh1_e.use_connect = False thigh2_e.use_connect = False utip_e.use_connect = False thigh1_e.parent = org_thigh_e.parent thigh2_e.parent = org_thigh_e utip_e.parent = org_thigh_e center = Vector((org_thigh_e.head + org_thigh_e.tail) / 2) thigh1_e.tail = center thigh2_e.head = center put_bone(self.obj, utip, org_thigh_e.tail) utip_e.length = org_thigh_e.length / 8 else: thigh_e.use_connect = False thigh_e.parent = org_thigh_e # Parent and position shin bones if self.use_shin_twist: shin1_e.use_connect = False shin2_e.use_connect = False stip_e.use_connect = False shin1_e.parent = org_shin_e shin2_e.parent = org_shin_e stip_e.parent = org_shin_e center = Vector((org_shin_e.head + org_shin_e.tail) / 2) shin1_e.tail = center shin2_e.head = center put_bone(self.obj, stip, org_shin_e.tail) stip_e.length = org_shin_e.length / 8 # Align roll of shin2 with foot align_roll(self.obj, shin2, foot) else: shin_e.use_connect = False shin_e.parent = org_shin_e # Parent foot foot_e.use_connect = False foot_e.parent = org_foot_e # Parent toe toe_e.use_connect = False toe_e.parent = org_toe_e # Object mode, get pose bones bpy.ops.object.mode_set(mode='OBJECT') pb = self.obj.pose.bones if self.use_thigh_twist: thigh1_p = pb[thigh1] if self.use_shin_twist: shin2_p = pb[shin2] # foot_p = pb[foot] # UNUSED # Thigh constraints if self.use_thigh_twist: con = thigh1_p.constraints.new('COPY_LOCATION') con.name = "copy_location" con.target = self.obj con.subtarget = self.org_bones[0] con = thigh1_p.constraints.new('COPY_SCALE') con.name = "copy_scale" con.target = self.obj con.subtarget = self.org_bones[0] con = thigh1_p.constraints.new('DAMPED_TRACK') con.name = "track_to" con.target = self.obj con.subtarget = utip # Shin constraints if self.use_shin_twist: con = shin2_p.constraints.new('COPY_ROTATION') con.name = "copy_rotation" con.target = self.obj con.subtarget = foot con = shin2_p.constraints.new('DAMPED_TRACK') con.name = "track_to" con.target = self.obj con.subtarget = stip
def generate(self): """ Generate the rig. Do NOT modify any of the original bones, except for adding constraints. The main armature should be selected and active before this is called. """ bpy.ops.object.mode_set(mode='EDIT') make_rocker = False if self.org_bones[5] is not None: make_rocker = True # Create the bones thigh = copy_bone(self.obj, self.org_bones[0], make_mechanism_name(strip_org(insert_before_lr(self.org_bones[0], "_ik")))) shin = copy_bone(self.obj, self.org_bones[1], make_mechanism_name(strip_org(insert_before_lr(self.org_bones[1], "_ik")))) foot = copy_bone(self.obj, self.org_bones[2], strip_org(insert_before_lr(self.org_bones[2], "_ik"))) foot_ik_target = copy_bone(self.obj, self.org_bones[2], make_mechanism_name(strip_org(insert_before_lr(self.org_bones[2], "_ik_target")))) pole = copy_bone(self.obj, self.org_bones[0], strip_org(insert_before_lr(self.org_bones[0], "_pole"))) toe = copy_bone(self.obj, self.org_bones[3], strip_org(self.org_bones[3])) toe_parent = copy_bone(self.obj, self.org_bones[2], make_mechanism_name(strip_org(self.org_bones[3] + ".parent"))) toe_parent_socket1 = copy_bone(self.obj, self.org_bones[2], make_mechanism_name(strip_org(self.org_bones[3] + ".socket1"))) toe_parent_socket2 = copy_bone(self.obj, self.org_bones[2], make_mechanism_name(strip_org(self.org_bones[3] + ".socket2"))) foot_roll = copy_bone(self.obj, self.org_bones[4], strip_org(insert_before_lr(self.org_bones[2], "_roll"))) roll1 = copy_bone(self.obj, self.org_bones[4], make_mechanism_name(strip_org(self.org_bones[2] + ".roll.01"))) roll2 = copy_bone(self.obj, self.org_bones[4], make_mechanism_name(strip_org(self.org_bones[2] + ".roll.02"))) if make_rocker: rocker1 = copy_bone(self.obj, self.org_bones[5], make_mechanism_name(strip_org(self.org_bones[2] + ".rocker.01"))) rocker2 = copy_bone(self.obj, self.org_bones[5], make_mechanism_name(strip_org(self.org_bones[2] + ".rocker.02"))) visfoot = copy_bone(self.obj, self.org_bones[2], "VIS-" + strip_org(insert_before_lr(self.org_bones[2], "_ik"))) vispole = copy_bone(self.obj, self.org_bones[1], "VIS-" + strip_org(insert_before_lr(self.org_bones[0], "_pole"))) # Get edit bones eb = self.obj.data.edit_bones org_foot_e = eb[self.org_bones[2]] thigh_e = eb[thigh] shin_e = eb[shin] foot_e = eb[foot] foot_ik_target_e = eb[foot_ik_target] pole_e = eb[pole] toe_e = eb[toe] toe_parent_e = eb[toe_parent] toe_parent_socket1_e = eb[toe_parent_socket1] toe_parent_socket2_e = eb[toe_parent_socket2] foot_roll_e = eb[foot_roll] roll1_e = eb[roll1] roll2_e = eb[roll2] if make_rocker: rocker1_e = eb[rocker1] rocker2_e = eb[rocker2] visfoot_e = eb[visfoot] vispole_e = eb[vispole] # Parenting shin_e.parent = thigh_e foot_e.use_connect = False foot_e.parent = None foot_ik_target_e.use_connect = False foot_ik_target_e.parent = roll2_e pole_e.use_connect = False pole_e.parent = foot_e toe_e.parent = toe_parent_e toe_parent_e.use_connect = False toe_parent_e.parent = toe_parent_socket1_e toe_parent_socket1_e.use_connect = False toe_parent_socket1_e.parent = roll1_e toe_parent_socket2_e.use_connect = False toe_parent_socket2_e.parent = eb[self.org_bones[2]] foot_roll_e.use_connect = False foot_roll_e.parent = foot_e roll1_e.use_connect = False roll1_e.parent = foot_e roll2_e.use_connect = False roll2_e.parent = roll1_e visfoot_e.use_connect = False visfoot_e.parent = None vispole_e.use_connect = False vispole_e.parent = None if make_rocker: rocker1_e.use_connect = False rocker2_e.use_connect = False roll1_e.parent = rocker2_e rocker2_e.parent = rocker1_e rocker1_e.parent = foot_e # Misc foot_e.use_local_location = False visfoot_e.hide_select = True vispole_e.hide_select = True # Positioning vec = Vector(toe_e.vector) vec.normalize() foot_e.tail = foot_e.head + (vec * foot_e.length) foot_e.roll = toe_e.roll v1 = shin_e.tail - thigh_e.head if 'X' in self.primary_rotation_axis or 'Y' in self.primary_rotation_axis: v2 = v1.cross(shin_e.x_axis) if (v2 * shin_e.z_axis) > 0.0: v2 *= -1.0 else: v2 = v1.cross(shin_e.z_axis) if (v2 * shin_e.x_axis) < 0.0: v2 *= -1.0 v2.normalize() v2 *= v1.length if '-' in self.primary_rotation_axis: v2 *= -1 pole_e.head = shin_e.head + v2 pole_e.tail = pole_e.head + (Vector((0, 1, 0)) * (v1.length / 8)) pole_e.roll = 0.0 flip_bone(self.obj, toe_parent_socket1) flip_bone(self.obj, toe_parent_socket2) toe_parent_socket1_e.head = Vector(org_foot_e.tail) toe_parent_socket2_e.head = Vector(org_foot_e.tail) toe_parent_socket1_e.tail = Vector(org_foot_e.tail) + (Vector((0, 0, 1)) * foot_e.length / 2) toe_parent_socket2_e.tail = Vector(org_foot_e.tail) + (Vector((0, 0, 1)) * foot_e.length / 3) toe_parent_socket2_e.roll = toe_parent_socket1_e.roll tail = Vector(roll1_e.tail) roll1_e.tail = Vector(org_foot_e.tail) roll1_e.tail = Vector(org_foot_e.tail) roll1_e.head = tail roll2_e.head = Vector(org_foot_e.tail) foot_roll_e.head = Vector(org_foot_e.tail) put_bone(self.obj, foot_roll, roll1_e.head) foot_roll_e.length /= 2 roll_axis = roll1_e.vector.cross(org_foot_e.vector) align_x_axis(self.obj, roll1, roll_axis) align_x_axis(self.obj, roll2, roll_axis) foot_roll_e.roll = roll2_e.roll visfoot_e.tail = visfoot_e.head + Vector((0, 0, v1.length / 32)) vispole_e.tail = vispole_e.head + Vector((0, 0, v1.length / 32)) if make_rocker: d = toe_e.y_axis.dot(rocker1_e.x_axis) if d >= 0.0: flip_bone(self.obj, rocker2) else: flip_bone(self.obj, rocker1) # Weird alignment issues. Fix. toe_parent_e.head = Vector(org_foot_e.head) toe_parent_e.tail = Vector(org_foot_e.tail) toe_parent_e.roll = org_foot_e.roll foot_e.head = Vector(org_foot_e.head) foot_ik_target_e.head = Vector(org_foot_e.head) foot_ik_target_e.tail = Vector(org_foot_e.tail) # Determine the pole offset value plane = (shin_e.tail - thigh_e.head).normalized() vec1 = thigh_e.x_axis.normalized() vec2 = (pole_e.head - thigh_e.head).normalized() pole_offset = angle_on_plane(plane, vec1, vec2) # Object mode, get pose bones bpy.ops.object.mode_set(mode='OBJECT') pb = self.obj.pose.bones # thigh_p = pb[thigh] # UNUSED shin_p = pb[shin] foot_p = pb[foot] pole_p = pb[pole] foot_roll_p = pb[foot_roll] roll1_p = pb[roll1] roll2_p = pb[roll2] if make_rocker: rocker1_p = pb[rocker1] rocker2_p = pb[rocker2] toe_p = pb[toe] toe_parent_p = pb[toe_parent] toe_parent_socket1_p = pb[toe_parent_socket1] visfoot_p = pb[visfoot] vispole_p = pb[vispole] # Set the knee to only bend on the primary axis. if 'X' in self.primary_rotation_axis: shin_p.lock_ik_y = True shin_p.lock_ik_z = True elif 'Y' in self.primary_rotation_axis: shin_p.lock_ik_x = True shin_p.lock_ik_z = True else: shin_p.lock_ik_x = True shin_p.lock_ik_y = True # Foot roll control only rotates on x-axis, or x and y if rocker. foot_roll_p.rotation_mode = 'XYZ' if make_rocker: foot_roll_p.lock_rotation = False, False, True else: foot_roll_p.lock_rotation = False, True, True foot_roll_p.lock_location = True, True, True foot_roll_p.lock_scale = True, True, True # roll and rocker bones set to euler rotation roll1_p.rotation_mode = 'XYZ' roll2_p.rotation_mode = 'XYZ' if make_rocker: rocker1_p.rotation_mode = 'XYZ' rocker2_p.rotation_mode = 'XYZ' # Pole target only translates pole_p.lock_location = False, False, False pole_p.lock_rotation = True, True, True pole_p.lock_rotation_w = True pole_p.lock_scale = True, True, True # Set up custom properties if self.switch == True: prop = rna_idprop_ui_prop_get(foot_p, "ikfk_switch", create=True) foot_p["ikfk_switch"] = 0.0 prop["soft_min"] = prop["min"] = 0.0 prop["soft_max"] = prop["max"] = 1.0 # Bend direction hint if self.bend_hint: con = shin_p.constraints.new('LIMIT_ROTATION') con.name = "bend_hint" con.owner_space = 'LOCAL' if self.primary_rotation_axis == 'X': con.use_limit_x = True con.min_x = pi / 10 con.max_x = pi / 10 elif self.primary_rotation_axis == '-X': con.use_limit_x = True con.min_x = -pi / 10 con.max_x = -pi / 10 elif self.primary_rotation_axis == 'Y': con.use_limit_y = True con.min_y = pi / 10 con.max_y = pi / 10 elif self.primary_rotation_axis == '-Y': con.use_limit_y = True con.min_y = -pi / 10 con.max_y = -pi / 10 elif self.primary_rotation_axis == 'Z': con.use_limit_z = True con.min_z = pi / 10 con.max_z = pi / 10 elif self.primary_rotation_axis == '-Z': con.use_limit_z = True con.min_z = -pi / 10 con.max_z = -pi / 10 # IK Constraint con = shin_p.constraints.new('IK') con.name = "ik" con.target = self.obj con.subtarget = foot_ik_target con.pole_target = self.obj con.pole_subtarget = pole con.pole_angle = pole_offset con.chain_count = 2 # toe_parent constraint con = toe_parent_socket1_p.constraints.new('COPY_LOCATION') con.name = "copy_location" con.target = self.obj con.subtarget = toe_parent_socket2 con = toe_parent_socket1_p.constraints.new('COPY_SCALE') con.name = "copy_scale" con.target = self.obj con.subtarget = toe_parent_socket2 con = toe_parent_socket1_p.constraints.new('COPY_TRANSFORMS') # drive with IK switch con.name = "fk" con.target = self.obj con.subtarget = toe_parent_socket2 fcurve = con.driver_add("influence") driver = fcurve.driver var = driver.variables.new() driver.type = 'AVERAGE' var.name = "var" var.targets[0].id_type = 'OBJECT' var.targets[0].id = self.obj var.targets[0].data_path = foot_p.path_from_id() + '["ikfk_switch"]' mod = fcurve.modifiers[0] mod.poly_order = 1 mod.coefficients[0] = 1.0 mod.coefficients[1] = -1.0 # Foot roll drivers fcurve = roll1_p.driver_add("rotation_euler", 0) driver = fcurve.driver var = driver.variables.new() driver.type = 'SCRIPTED' driver.expression = "min(0,var)" var.name = "var" var.targets[0].id_type = 'OBJECT' var.targets[0].id = self.obj var.targets[0].data_path = foot_roll_p.path_from_id() + '.rotation_euler[0]' fcurve = roll2_p.driver_add("rotation_euler", 0) driver = fcurve.driver var = driver.variables.new() driver.type = 'SCRIPTED' driver.expression = "max(0,var)" var.name = "var" var.targets[0].id_type = 'OBJECT' var.targets[0].id = self.obj var.targets[0].data_path = foot_roll_p.path_from_id() + '.rotation_euler[0]' if make_rocker: fcurve = rocker1_p.driver_add("rotation_euler", 0) driver = fcurve.driver var = driver.variables.new() driver.type = 'SCRIPTED' driver.expression = "max(0,-var)" var.name = "var" var.targets[0].id_type = 'OBJECT' var.targets[0].id = self.obj var.targets[0].data_path = foot_roll_p.path_from_id() + '.rotation_euler[1]' fcurve = rocker2_p.driver_add("rotation_euler", 0) driver = fcurve.driver var = driver.variables.new() driver.type = 'SCRIPTED' driver.expression = "max(0,var)" var.name = "var" var.targets[0].id_type = 'OBJECT' var.targets[0].id = self.obj var.targets[0].data_path = foot_roll_p.path_from_id() + '.rotation_euler[1]' # Constrain org bones to controls con = pb[self.org_bones[0]].constraints.new('COPY_TRANSFORMS') con.name = "ik" con.target = self.obj con.subtarget = thigh if self.switch == True: # IK/FK switch driver fcurve = con.driver_add("influence") driver = fcurve.driver var = driver.variables.new() driver.type = 'AVERAGE' var.name = "var" var.targets[0].id_type = 'OBJECT' var.targets[0].id = self.obj var.targets[0].data_path = foot_p.path_from_id() + '["ikfk_switch"]' con = pb[self.org_bones[1]].constraints.new('COPY_TRANSFORMS') con.name = "ik" con.target = self.obj con.subtarget = shin if self.switch == True: # IK/FK switch driver fcurve = con.driver_add("influence") driver = fcurve.driver var = driver.variables.new() driver.type = 'AVERAGE' var.name = "var" var.targets[0].id_type = 'OBJECT' var.targets[0].id = self.obj var.targets[0].data_path = foot_p.path_from_id() + '["ikfk_switch"]' con = pb[self.org_bones[2]].constraints.new('COPY_TRANSFORMS') con.name = "ik" con.target = self.obj con.subtarget = foot_ik_target if self.switch == True: # IK/FK switch driver fcurve = con.driver_add("influence") driver = fcurve.driver var = driver.variables.new() driver.type = 'AVERAGE' var.name = "var" var.targets[0].id_type = 'OBJECT' var.targets[0].id = self.obj var.targets[0].data_path = foot_p.path_from_id() + '["ikfk_switch"]' con = pb[self.org_bones[3]].constraints.new('COPY_TRANSFORMS') con.name = "copy_transforms" con.target = self.obj con.subtarget = toe # VIS foot constraints con = visfoot_p.constraints.new('COPY_LOCATION') con.name = "copy_loc" con.target = self.obj con.subtarget = self.org_bones[2] con = visfoot_p.constraints.new('STRETCH_TO') con.name = "stretch_to" con.target = self.obj con.subtarget = foot con.volume = 'NO_VOLUME' con.rest_length = visfoot_p.length # VIS pole constraints con = vispole_p.constraints.new('COPY_LOCATION') con.name = "copy_loc" con.target = self.obj con.subtarget = self.org_bones[1] con = vispole_p.constraints.new('STRETCH_TO') con.name = "stretch_to" con.target = self.obj con.subtarget = pole con.volume = 'NO_VOLUME' con.rest_length = vispole_p.length # Set layers if specified if self.layers: foot_p.bone.layers = self.layers pole_p.bone.layers = self.layers foot_roll_p.bone.layers = self.layers visfoot_p.bone.layers = self.layers vispole_p.bone.layers = self.layers toe_p.bone.layers = [(i[0] or i[1]) for i in zip(toe_p.bone.layers, self.layers)] # Both FK and IK layers # Create widgets create_line_widget(self.obj, vispole) create_line_widget(self.obj, visfoot) create_sphere_widget(self.obj, pole) create_circle_widget(self.obj, toe, radius=0.7, head_tail=0.5) ob = create_widget(self.obj, foot) if ob != None: verts = [(0.7, 1.5, 0.0), (0.7, -0.25, 0.0), (-0.7, -0.25, 0.0), (-0.7, 1.5, 0.0), (0.7, 0.723, 0.0), (-0.7, 0.723, 0.0), (0.7, 0.0, 0.0), (-0.7, 0.0, 0.0)] edges = [(1, 2), (0, 3), (0, 4), (3, 5), (4, 6), (1, 6), (5, 7), (2, 7)] mesh = ob.data mesh.from_pydata(verts, edges, []) mesh.update() mod = ob.modifiers.new("subsurf", 'SUBSURF') mod.levels = 2 ob = create_widget(self.obj, foot_roll) if ob != None: verts = [(0.3999999761581421, 0.766044557094574, 0.6427875757217407), (0.17668449878692627, 3.823702598992895e-08, 3.2084670920085046e-08), (-0.17668461799621582, 9.874240447516058e-08, 8.285470443070153e-08), (-0.39999961853027344, 0.7660449147224426, 0.6427879333496094), (0.3562471270561218, 0.6159579753875732, 0.5168500542640686), (-0.35624682903289795, 0.6159582138061523, 0.5168502926826477), (0.20492683351039886, 0.09688037633895874, 0.0812922865152359), (-0.20492687821388245, 0.0968804731965065, 0.08129236847162247)] edges = [(1, 2), (0, 3), (0, 4), (3, 5), (1, 6), (4, 6), (2, 7), (5, 7)] mesh = ob.data mesh.from_pydata(verts, edges, []) mesh.update() mod = ob.modifiers.new("subsurf", 'SUBSURF') mod.levels = 2 return [thigh, shin, foot, pole, foot_roll, foot_ik_target]
def create_controls(self): bpy.ops.object.mode_set(mode='EDIT') edit_bones = self.obj.data.edit_bones self.bones['eye_ctrl'] = dict() if self.orientation_bone == self.base_bone: axis = Vector((0, 0, 1)) else: axis = edit_bones[self.orientation_bone].y_axis eye_ctrl_name = "master_" + strip_org(self.bones['org'][0]) eye_ctrl = copy_bone(self.obj, self.bones['org'][0], eye_ctrl_name) self.bones['eye_ctrl']['master_eye'] = eye_ctrl if self.params.make_control: eye_hook_name = strip_org(self.bones['org'][0]) + "_hook" eye_hook = copy_bone(self.obj, self.bones['org'][0], eye_hook_name) self.bones['eye_ctrl']['eye_hook'] = eye_hook eye_target_name = strip_org(self.bones['org'][0]) eye_target = copy_bone(self.obj, self.orientation_bone, eye_target_name) self.bones['eye_ctrl']['eye_target'] = eye_target position = edit_bones[eye_ctrl].tail + 5 * edit_bones[ eye_ctrl].length * edit_bones[eye_ctrl].y_axis put_bone(self.obj, eye_target, position) edit_bones[eye_target].length = 0.5 * edit_bones[self.base_bone].length align_bone_y_axis(self.obj, eye_target, Vector((0, 0, 1))) align_bone_z_axis(self.obj, eye_target, edit_bones[self.base_bone].y_axis) # make standard controls super().create_controls() # add extra lid ctrls top_chain = strip_org(self.lid_bones['top'][0]) bottom_chain = strip_org(self.lid_bones['bottom'][0]) if self.lid_len % 2 != 0: mid_index = int((self.lid_len + 1) / 2) top_lid_master = copy_bone(self.obj, self.bones['ctrl'][top_chain][0]) # edit_bones[top_lid_master].length *= 1.5 self.bones['eye_ctrl']['top_lid_master'] = top_lid_master mid_bone_1 = edit_bones[self.bones['ctrl'][top_chain][mid_index - 1]] mid_bone_2 = edit_bones[self.bones['ctrl'][top_chain][mid_index]] put_bone(self.obj, top_lid_master, (mid_bone_1.head + mid_bone_2.head) / 2) align_bone_y_axis(self.obj, top_lid_master, axis) bottom_lid_master = copy_bone(self.obj, self.bones['ctrl'][bottom_chain][0]) # edit_bones[bottom_lid_master].length *= 1.5 self.bones['eye_ctrl']['bottom_lid_master'] = bottom_lid_master mid_bone_1 = edit_bones[self.bones['ctrl'][bottom_chain][mid_index - 1]] mid_bone_2 = edit_bones[self.bones['ctrl'][bottom_chain] [mid_index]] put_bone(self.obj, bottom_lid_master, (mid_bone_1.head + mid_bone_2.head) / 2) align_bone_y_axis(self.obj, bottom_lid_master, axis) else: mid_index = int((self.lid_len) / 2) top_lid_master = self.bones['ctrl'][top_chain][mid_index] bottom_lid_master = self.bones['ctrl'][bottom_chain][mid_index] # edit_bones[top_lid_master].length *= 1.5 # edit_bones[bottom_lid_master].length *= 1.5 self.bones['eye_ctrl']['top_lid_master'] = top_lid_master self.bones['eye_ctrl']['bottom_lid_master'] = bottom_lid_master # create eyes master if eye has company create_common_ctrl = False if self.paired_eye and strip_org(self.paired_eye) in edit_bones: other_eye = strip_org(self.paired_eye) position = (edit_bones[eye_target].head + edit_bones[other_eye].head) / 2 y_direction = edit_bones[eye_target].y_axis z_direction = edit_bones[eye_target].z_axis + edit_bones[ other_eye].z_axis create_common_ctrl = True elif self.is_clustered(): [position, y_direction, z_direction] = self.get_cluster_data() if position and y_direction: create_common_ctrl = True if create_common_ctrl: common_ctrl = self.get_common_name() + '_common' common_ctrl = copy_bone(self.obj, eye_target, common_ctrl) self.bones['eye_ctrl']['common'] = common_ctrl put_bone(self.obj, common_ctrl, position) align_bone_y_axis(self.obj, common_ctrl, y_direction) align_bone_z_axis(self.obj, common_ctrl, z_direction) for ctrl in self.bones['ctrl'][top_chain]: align_bone_y_axis(self.obj, ctrl, axis) for ctrl in self.bones['ctrl'][bottom_chain]: align_bone_y_axis(self.obj, ctrl, axis)
def gen_control(self): """ Generate the control rig. """ bpy.ops.object.mode_set(mode='EDIT') eb = self.obj.data.edit_bones #------------------------- # Get rest slide position a = self.pivot_rest * len(self.org_bones) i = floor(a) a -= i if i == len(self.org_bones): i -= 1 a = 1.0 pivot_rest_pos = eb[self.org_bones[i]].head.copy() pivot_rest_pos += eb[self.org_bones[i]].vector * a #---------------------- # Create controls # Create control bones controls = [] for i in self.control_indices: name = copy_bone(self.obj, self.org_bones[i], strip_org(self.org_bones[i])) controls += [name] # Create control parents control_parents = [] for i in self.control_indices[1:-1]: name = new_bone( self.obj, make_mechanism_name("par_" + strip_org(self.org_bones[i]))) control_parents += [name] # Create sub-control bones subcontrols = [] for i in self.control_indices: name = new_bone( self.obj, make_mechanism_name("sub_" + strip_org(self.org_bones[i]))) subcontrols += [name] # Create main control bone main_control = new_bone(self.obj, self.params.spine_main_control_name) # Create main control WGT bones main_wgt1 = new_bone( self.obj, make_mechanism_name(self.params.spine_main_control_name + ".01")) main_wgt2 = new_bone( self.obj, make_mechanism_name(self.params.spine_main_control_name + ".02")) eb = self.obj.data.edit_bones # Parent the main control eb[main_control].use_connect = False eb[main_control].parent = eb[self.org_bones[0]].parent # Parent the main WGTs eb[main_wgt1].use_connect = False eb[main_wgt1].parent = eb[main_control] eb[main_wgt2].use_connect = False eb[main_wgt2].parent = eb[main_wgt1] # Parent the controls and sub-controls for name, subname in zip(controls, subcontrols): eb[name].use_connect = False eb[name].parent = eb[main_control] eb[subname].use_connect = False eb[subname].parent = eb[name] # Parent the control parents for name, par_name in zip(controls[1:-1], control_parents): eb[par_name].use_connect = False eb[par_name].parent = eb[main_control] eb[name].parent = eb[par_name] # Position the main bone put_bone(self.obj, main_control, pivot_rest_pos) eb[main_control].length = sum([eb[b].length for b in self.org_bones]) / 2 # Position the main WGTs eb[main_wgt1].tail = (0.0, 0.0, sum([eb[b].length for b in self.org_bones]) / 4) eb[main_wgt2].length = sum([eb[b].length for b in self.org_bones]) / 4 put_bone(self.obj, main_wgt1, pivot_rest_pos) put_bone(self.obj, main_wgt2, pivot_rest_pos) # Position the controls and sub-controls pos = eb[controls[0]].head.copy() for name, subname in zip(controls, subcontrols): put_bone(self.obj, name, pivot_rest_pos) put_bone(self.obj, subname, pivot_rest_pos) eb[subname].length = eb[name].length / 3 # Position the control parents for name, par_name in zip(controls[1:-1], control_parents): put_bone(self.obj, par_name, pivot_rest_pos) eb[par_name].length = eb[name].length / 2 #----------------------------------------- # Control bone constraints and properties bpy.ops.object.mode_set(mode='OBJECT') pb = self.obj.pose.bones # Lock control locations for name in controls: bone = pb[name] bone.lock_location = True, True, True # Main control doesn't use local location pb[main_control].bone.use_local_location = False # Intermediate controls follow hips and spine for name, par_name, i in zip(controls[1:-1], control_parents, self.control_indices[1:-1]): bone = pb[par_name] # Custom bend_alpha property prop = rna_idprop_ui_prop_get(pb[name], "bend_alpha", create=True) pb[name]["bend_alpha"] = i / (len(self.org_bones) - 1 ) # set bend alpha prop["min"] = 0.0 prop["max"] = 1.0 prop["soft_min"] = 0.0 prop["soft_max"] = 1.0 # Custom auto_rotate prop = rna_idprop_ui_prop_get(pb[name], "auto_rotate", create=True) pb[name]["auto_rotate"] = 1.0 prop["min"] = 0.0 prop["max"] = 1.0 prop["soft_min"] = 0.0 prop["soft_max"] = 1.0 # Constraints con1 = bone.constraints.new('COPY_TRANSFORMS') con1.name = "copy_transforms" con1.target = self.obj con1.subtarget = subcontrols[0] con2 = bone.constraints.new('COPY_TRANSFORMS') con2.name = "copy_transforms" con2.target = self.obj con2.subtarget = subcontrols[-1] # Drivers fcurve = con1.driver_add("influence") driver = fcurve.driver driver.type = 'AVERAGE' var = driver.variables.new() var.name = "auto" var.targets[0].id_type = 'OBJECT' var.targets[0].id = self.obj var.targets[0].data_path = pb[name].path_from_id( ) + '["auto_rotate"]' fcurve = con2.driver_add("influence") driver = fcurve.driver driver.type = 'SCRIPTED' driver.expression = "alpha * auto" var = driver.variables.new() var.name = "alpha" var.targets[0].id_type = 'OBJECT' var.targets[0].id = self.obj var.targets[0].data_path = pb[name].path_from_id( ) + '["bend_alpha"]' var = driver.variables.new() var.name = "auto" var.targets[0].id_type = 'OBJECT' var.targets[0].id = self.obj var.targets[0].data_path = pb[name].path_from_id( ) + '["auto_rotate"]' #------------------------- # Create flex spine chain bpy.ops.object.mode_set(mode='EDIT') flex_bones = [] flex_subs = [] prev_bone = None for b in self.org_bones: # Create bones bone = copy_bone(self.obj, b, make_mechanism_name(strip_org(b) + ".flex")) sub = new_bone(self.obj, make_mechanism_name(strip_org(b) + ".flex_s")) flex_bones += [bone] flex_subs += [sub] eb = self.obj.data.edit_bones bone_e = eb[bone] sub_e = eb[sub] # Parenting bone_e.use_connect = False sub_e.use_connect = False if prev_bone is None: sub_e.parent = eb[controls[0]] else: sub_e.parent = eb[prev_bone] bone_e.parent = sub_e # Position put_bone(self.obj, sub, bone_e.head) sub_e.length = bone_e.length / 4 if prev_bone is not None: sub_e.use_connect = True prev_bone = bone #---------------------------- # Create reverse spine chain # Create bones/parenting/positioning bpy.ops.object.mode_set(mode='EDIT') rev_bones = [] prev_bone = None for b in zip(flex_bones, self.org_bones): # Create bones bone = copy_bone(self.obj, b[1], make_mechanism_name(strip_org(b[1]) + ".reverse")) rev_bones += [bone] eb = self.obj.data.edit_bones bone_e = eb[bone] # Parenting bone_e.use_connect = False bone_e.parent = eb[b[0]] # Position flip_bone(self.obj, bone) bone_e.tail = Vector(eb[b[0]].head) #bone_e.head = Vector(eb[b[0]].tail) if prev_bone is None: put_bone(self.obj, bone, pivot_rest_pos) else: put_bone(self.obj, bone, eb[prev_bone].tail) prev_bone = bone # Constraints bpy.ops.object.mode_set(mode='OBJECT') pb = self.obj.pose.bones prev_bone = None for bone in rev_bones: bone_p = pb[bone] con = bone_p.constraints.new('COPY_LOCATION') con.name = "copy_location" con.target = self.obj if prev_bone is None: con.subtarget = main_control else: con.subtarget = prev_bone con.head_tail = 1.0 prev_bone = bone #---------------------------------------- # Constrain original bones to flex spine bpy.ops.object.mode_set(mode='OBJECT') pb = self.obj.pose.bones for obone, fbone in zip(self.org_bones, flex_bones): con = pb[obone].constraints.new('COPY_TRANSFORMS') con.name = "copy_transforms" con.target = self.obj con.subtarget = fbone #--------------------------- # Create pivot slide system pb = self.obj.pose.bones bone_p = pb[self.org_bones[0]] main_control_p = pb[main_control] # Custom pivot_slide property prop = rna_idprop_ui_prop_get(main_control_p, "pivot_slide", create=True) main_control_p["pivot_slide"] = self.pivot_rest prop["min"] = 0.0 prop["max"] = 1.0 prop["soft_min"] = 1.0 / len(self.org_bones) prop["soft_max"] = 1.0 - (1.0 / len(self.org_bones)) # Anchor constraints con = bone_p.constraints.new('COPY_LOCATION') con.name = "copy_location" con.target = self.obj con.subtarget = rev_bones[0] con = pb[main_wgt1].constraints.new('COPY_ROTATION') con.name = "copy_rotation" con.target = self.obj con.subtarget = rev_bones[0] # Slide constraints i = 1 tot = len(rev_bones) for rb in rev_bones: con = bone_p.constraints.new('COPY_LOCATION') con.name = "slide." + str(i) con.target = self.obj con.subtarget = rb con.head_tail = 1.0 # Driver fcurve = con.driver_add("influence") driver = fcurve.driver var = driver.variables.new() driver.type = 'AVERAGE' var.name = "slide" var.targets[0].id_type = 'OBJECT' var.targets[0].id = self.obj var.targets[0].data_path = main_control_p.path_from_id( ) + '["pivot_slide"]' mod = fcurve.modifiers[0] mod.poly_order = 1 mod.coefficients[0] = 1 - i mod.coefficients[1] = tot # Main WGT con = pb[main_wgt1].constraints.new('COPY_ROTATION') con.name = "slide." + str(i) con.target = self.obj con.subtarget = rb # Driver fcurve = con.driver_add("influence") driver = fcurve.driver var = driver.variables.new() driver.type = 'AVERAGE' var.name = "slide" var.targets[0].id_type = 'OBJECT' var.targets[0].id = self.obj var.targets[0].data_path = main_control_p.path_from_id( ) + '["pivot_slide"]' mod = fcurve.modifiers[0] mod.poly_order = 1 mod.coefficients[0] = 1.5 - i mod.coefficients[1] = tot i += 1 #---------------------------------- # Constrain flex spine to controls bpy.ops.object.mode_set(mode='OBJECT') pb = self.obj.pose.bones # Constrain the bones that correspond exactly to the controls for i, name in zip(self.control_indices, subcontrols): con = pb[flex_subs[i]].constraints.new('COPY_TRANSFORMS') con.name = "copy_transforms" con.target = self.obj con.subtarget = name # Constrain the bones in-between the controls for i, j, name1, name2 in zip(self.control_indices, self.control_indices[1:], subcontrols, subcontrols[1:]): if (i + 1) < j: for n in range(i + 1, j): bone = pb[flex_subs[n]] # Custom bend_alpha property prop = rna_idprop_ui_prop_get(bone, "bend_alpha", create=True) bone["bend_alpha"] = (n - i) / (j - i) # set bend alpha prop["min"] = 0.0 prop["max"] = 1.0 prop["soft_min"] = 0.0 prop["soft_max"] = 1.0 con = bone.constraints.new('COPY_TRANSFORMS') con.name = "copy_transforms" con.target = self.obj con.subtarget = name1 con = bone.constraints.new('COPY_TRANSFORMS') con.name = "copy_transforms" con.target = self.obj con.subtarget = name2 # Driver fcurve = con.driver_add("influence") driver = fcurve.driver var = driver.variables.new() driver.type = 'AVERAGE' var.name = "alpha" var.targets[0].id_type = 'OBJECT' var.targets[0].id = self.obj var.targets[0].data_path = bone.path_from_id( ) + '["bend_alpha"]' #------------- # Final stuff bpy.ops.object.mode_set(mode='OBJECT') pb = self.obj.pose.bones # Control appearance # Main pb[main_control].custom_shape_transform = pb[main_wgt2] w = create_compass_widget(self.obj, main_control) if w != None: obj_to_bone(w, self.obj, main_wgt2) # Spines for name, i in zip(controls[1:-1], self.control_indices[1:-1]): pb[name].custom_shape_transform = pb[self.org_bones[i]] # Create control widgets w = create_circle_widget(self.obj, name, radius=1.0, head_tail=0.5, with_line=True) if w != None: obj_to_bone(w, self.obj, self.org_bones[i]) # Hips pb[controls[0]].custom_shape_transform = pb[self.org_bones[0]] # Create control widgets w = create_circle_widget(self.obj, controls[0], radius=1.0, head_tail=0.5, with_line=True) if w != None: obj_to_bone(w, self.obj, self.org_bones[0]) # Ribs pb[controls[-1]].custom_shape_transform = pb[self.org_bones[-1]] # Create control widgets w = create_circle_widget(self.obj, controls[-1], radius=1.0, head_tail=0.5, with_line=True) if w != None: obj_to_bone(w, self.obj, self.org_bones[-1]) # Layers pb[main_control].bone.layers = pb[self.org_bones[0]].bone.layers return [main_control] + controls
def generate(self): """ Generate the rig. Do NOT modify any of the original bones, except for adding constraints. The main armature should be selected and active before this is called. """ bpy.ops.object.mode_set(mode='EDIT') # Create upper arm bones if self.use_upper_arm_twist: uarm1 = copy_bone( self.obj, self.org_bones[0], make_deformer_name(strip_org(self.org_bones[0] + ".01"))) uarm2 = copy_bone( self.obj, self.org_bones[0], make_deformer_name(strip_org(self.org_bones[0] + ".02"))) utip = copy_bone( self.obj, self.org_bones[0], make_mechanism_name(strip_org(self.org_bones[0] + ".tip"))) else: uarm = copy_bone(self.obj, self.org_bones[0], make_deformer_name(strip_org(self.org_bones[0]))) # Create forearm bones if self.use_forearm_twist: farm1 = copy_bone( self.obj, self.org_bones[1], make_deformer_name(strip_org(self.org_bones[1] + ".01"))) farm2 = copy_bone( self.obj, self.org_bones[1], make_deformer_name(strip_org(self.org_bones[1] + ".02"))) ftip = copy_bone( self.obj, self.org_bones[1], make_mechanism_name(strip_org(self.org_bones[1] + ".tip"))) else: farm = copy_bone(self.obj, self.org_bones[1], make_deformer_name(strip_org(self.org_bones[1]))) # Create hand bone hand = copy_bone(self.obj, self.org_bones[2], make_deformer_name(strip_org(self.org_bones[2]))) # Get edit bones eb = self.obj.data.edit_bones org_uarm_e = eb[self.org_bones[0]] if self.use_upper_arm_twist: uarm1_e = eb[uarm1] uarm2_e = eb[uarm2] utip_e = eb[utip] else: uarm_e = eb[uarm] org_farm_e = eb[self.org_bones[1]] if self.use_forearm_twist: farm1_e = eb[farm1] farm2_e = eb[farm2] ftip_e = eb[ftip] else: farm_e = eb[farm] org_hand_e = eb[self.org_bones[2]] hand_e = eb[hand] # Parent and position upper arm bones if self.use_upper_arm_twist: uarm1_e.use_connect = False uarm2_e.use_connect = False utip_e.use_connect = False uarm1_e.parent = org_uarm_e.parent uarm2_e.parent = org_uarm_e utip_e.parent = org_uarm_e center = Vector((org_uarm_e.head + org_uarm_e.tail) / 2) uarm1_e.tail = center uarm2_e.head = center put_bone(self.obj, utip, org_uarm_e.tail) utip_e.length = org_uarm_e.length / 8 else: uarm_e.use_connect = False uarm_e.parent = org_uarm_e # Parent and position forearm bones if self.use_forearm_twist: farm1_e.use_connect = False farm2_e.use_connect = False ftip_e.use_connect = False farm1_e.parent = org_farm_e farm2_e.parent = org_farm_e ftip_e.parent = org_farm_e center = Vector((org_farm_e.head + org_farm_e.tail) / 2) farm1_e.tail = center farm2_e.head = center put_bone(self.obj, ftip, org_farm_e.tail) ftip_e.length = org_farm_e.length / 8 # Align roll of farm2 with hand align_roll(self.obj, farm2, hand) else: farm_e.use_connect = False farm_e.parent = org_farm_e # Parent hand hand_e.use_connect = False hand_e.parent = org_hand_e # Object mode, get pose bones bpy.ops.object.mode_set(mode='OBJECT') pb = self.obj.pose.bones if self.use_upper_arm_twist: uarm1_p = pb[uarm1] if self.use_forearm_twist: farm2_p = pb[farm2] # hand_p = pb[hand] # UNUSED # Upper arm constraints if self.use_upper_arm_twist: con = uarm1_p.constraints.new('COPY_LOCATION') con.name = "copy_location" con.target = self.obj con.subtarget = self.org_bones[0] con = uarm1_p.constraints.new('COPY_SCALE') con.name = "copy_scale" con.target = self.obj con.subtarget = self.org_bones[0] con = uarm1_p.constraints.new('DAMPED_TRACK') con.name = "track_to" con.target = self.obj con.subtarget = utip # Forearm constraints if self.use_forearm_twist: con = farm2_p.constraints.new('COPY_ROTATION') con.name = "copy_rotation" con.target = self.obj con.subtarget = hand con = farm2_p.constraints.new('DAMPED_TRACK') con.name = "track_to" con.target = self.obj con.subtarget = ftip
def generate(self): """ Generate the rig. Do NOT modify any of the original bones, except for adding constraints. The main armature should be selected and active before this is called. """ bpy.ops.object.mode_set(mode='EDIT') # Create upper arm bones if self.use_upper_arm_twist: uarm1 = copy_bone(self.obj, self.org_bones[0], make_deformer_name(strip_org(self.org_bones[0] + ".01"))) uarm2 = copy_bone(self.obj, self.org_bones[0], make_deformer_name(strip_org(self.org_bones[0] + ".02"))) utip = copy_bone(self.obj, self.org_bones[0], make_mechanism_name(strip_org(self.org_bones[0] + ".tip"))) else: uarm = copy_bone(self.obj, self.org_bones[0], make_deformer_name(strip_org(self.org_bones[0]))) # Create forearm bones if self.use_forearm_twist: farm1 = copy_bone(self.obj, self.org_bones[1], make_deformer_name(strip_org(self.org_bones[1] + ".01"))) farm2 = copy_bone(self.obj, self.org_bones[1], make_deformer_name(strip_org(self.org_bones[1] + ".02"))) ftip = copy_bone(self.obj, self.org_bones[1], make_mechanism_name(strip_org(self.org_bones[1] + ".tip"))) else: farm = copy_bone(self.obj, self.org_bones[1], make_deformer_name(strip_org(self.org_bones[1]))) # Create hand bone hand = copy_bone(self.obj, self.org_bones[2], make_deformer_name(strip_org(self.org_bones[2]))) # Get edit bones eb = self.obj.data.edit_bones org_uarm_e = eb[self.org_bones[0]] if self.use_upper_arm_twist: uarm1_e = eb[uarm1] uarm2_e = eb[uarm2] utip_e = eb[utip] else: uarm_e = eb[uarm] org_farm_e = eb[self.org_bones[1]] if self.use_forearm_twist: farm1_e = eb[farm1] farm2_e = eb[farm2] ftip_e = eb[ftip] else: farm_e = eb[farm] org_hand_e = eb[self.org_bones[2]] hand_e = eb[hand] # Parent and position upper arm bones if self.use_upper_arm_twist: uarm1_e.use_connect = False uarm2_e.use_connect = False utip_e.use_connect = False uarm1_e.parent = org_uarm_e.parent uarm2_e.parent = org_uarm_e utip_e.parent = org_uarm_e center = Vector((org_uarm_e.head + org_uarm_e.tail) / 2) uarm1_e.tail = center uarm2_e.head = center put_bone(self.obj, utip, org_uarm_e.tail) utip_e.length = org_uarm_e.length / 8 else: uarm_e.use_connect = False uarm_e.parent = org_uarm_e # Parent and position forearm bones if self.use_forearm_twist: farm1_e.use_connect = False farm2_e.use_connect = False ftip_e.use_connect = False farm1_e.parent = org_farm_e farm2_e.parent = org_farm_e ftip_e.parent = org_farm_e center = Vector((org_farm_e.head + org_farm_e.tail) / 2) farm1_e.tail = center farm2_e.head = center put_bone(self.obj, ftip, org_farm_e.tail) ftip_e.length = org_farm_e.length / 8 # Align roll of farm2 with hand align_roll(self.obj, farm2, hand) else: farm_e.use_connect = False farm_e.parent = org_farm_e # Parent hand hand_e.use_connect = False hand_e.parent = org_hand_e # Object mode, get pose bones bpy.ops.object.mode_set(mode='OBJECT') pb = self.obj.pose.bones if self.use_upper_arm_twist: uarm1_p = pb[uarm1] if self.use_forearm_twist: farm2_p = pb[farm2] # hand_p = pb[hand] # UNUSED # Upper arm constraints if self.use_upper_arm_twist: con = uarm1_p.constraints.new('COPY_LOCATION') con.name = "copy_location" con.target = self.obj con.subtarget = self.org_bones[0] con = uarm1_p.constraints.new('COPY_SCALE') con.name = "copy_scale" con.target = self.obj con.subtarget = self.org_bones[0] con = uarm1_p.constraints.new('DAMPED_TRACK') con.name = "track_to" con.target = self.obj con.subtarget = utip # Forearm constraints if self.use_forearm_twist: con = farm2_p.constraints.new('COPY_ROTATION') con.name = "copy_rotation" con.target = self.obj con.subtarget = hand con = farm2_p.constraints.new('DAMPED_TRACK') con.name = "track_to" con.target = self.obj con.subtarget = ftip
def create_chain(self): org_bones = self.org_bones bpy.ops.object.mode_set(mode='EDIT') eb = self.obj.data.edit_bones twk, mch, mch_ctrl, ctrl = [], [], [], [] suffix = '' if '.L' in org_bones[0]: suffix = '.L' elif '.R' in org_bones[0]: suffix = '.R' mch_auto = '' if not self.SINGLE_BONE: mch_name = copy_bone( self.obj, org(org_bones[0]), 'MCH-AUTO-' + strip_org(org_bones[0]).split('.')[0] + suffix) eb[mch_name].head = eb[org_bones[0]].head eb[mch_name].tail = eb[org_bones[-1]].tail mch_auto = mch_name # Intermediary bones for b in org_bones: # All if self.SINGLE_BONE: mch_name = copy_bone(self.obj, org(b), make_mechanism_name(strip_org(b))) eb[mch_name].length /= 4 put_bone(self.obj, mch_name, eb[b].head - (eb[mch_name].tail - eb[mch_name].head)) align_bone_z_axis(self.obj, mch_name, eb[b].z_axis) mch += [mch_name] mch_name = copy_bone(self.obj, org(b), make_mechanism_name(strip_org(b))) eb[mch_name].length /= 4 put_bone(self.obj, mch_name, eb[b].tail) mch += [mch_name] break else: mch_name = copy_bone(self.obj, org(b), make_mechanism_name(strip_org(b))) eb[mch_name].length /= 4 mch += [mch_name] if b == org_bones[-1]: # Add extra mch_name = copy_bone(self.obj, org(b), make_mechanism_name(strip_org(b))) eb[mch_name].length /= 4 put_bone(self.obj, mch_name, eb[b].tail) mch += [mch_name] # Tweak & Ctrl bones v = eb[org_bones[-1]].tail - eb[org_bones[ 0]].head # Create a vector from head of first ORG to tail of last v.normalize() v_proj = eb[org_bones[0]].y_axis.dot( v) * v # projection of first ORG to v v_point = eb[org_bones[ 0]].y_axis - v_proj # a vector co-planar to first ORG and v directed out of the chain if v_point.magnitude < eb[org_bones[0]].y_axis.magnitude * 1e-03: v_point = eb[org_bones[0]].x_axis for b in org_bones: # All suffix = '' if '.L' in b: suffix = '.L' elif '.R' in b: suffix = '.R' if b == org_bones[0]: name = get_bone_name(b.split('.')[0] + suffix, 'ctrl', 'ctrl') if self.params.use_parent_ctrls: name = make_mechanism_name(name) name = copy_bone(self.obj, org(b), name) align_bone_x_axis(self.obj, name, eb[org(b)].x_axis) ctrl += [name] else: name = 'tweak_' + strip_org(b) name = copy_bone(self.obj, org(b), name) twk += [name] self.orient_bone(eb[name], 'y', eb[name].length / 2) if self.params.tweak_axis == 'auto': align_bone_y_axis(self.obj, name, v) align_bone_z_axis(self.obj, name, -v_point) # invert? elif self.params.tweak_axis == 'x': align_bone_y_axis(self.obj, name, Vector((1, 0, 0))) align_bone_x_axis(self.obj, name, Vector((0, 0, 1))) elif self.params.tweak_axis == 'y': align_bone_y_axis(self.obj, name, Vector((0, 1, 0))) align_bone_x_axis(self.obj, name, Vector((1, 0, 0))) elif self.params.tweak_axis == 'z': align_bone_y_axis(self.obj, name, Vector((0, 0, 1))) align_bone_x_axis(self.obj, name, Vector((1, 0, 0))) if b == org_bones[-1]: # Add extra ctrl_name = get_bone_name( b.split('.')[0] + suffix, 'ctrl', 'ctrl') if self.params.use_parent_ctrls: ctrl_name = make_mechanism_name(ctrl_name) ctrl_name = copy_bone(self.obj, org(b), ctrl_name) self.orient_bone(eb[ctrl_name], 'y', eb[ctrl_name].length / 2) if self.params.conv_bone: align_bone_y_axis(self.obj, ctrl_name, eb[org(self.params.conv_bone)].y_axis) align_bone_x_axis(self.obj, ctrl_name, eb[org(self.params.conv_bone)].x_axis) align_bone_z_axis(self.obj, ctrl_name, eb[org(self.params.conv_bone)].z_axis) else: if twk: lastname = twk[-1] else: lastname = ctrl[-1] align_bone_y_axis(self.obj, ctrl_name, eb[lastname].y_axis) align_bone_x_axis(self.obj, ctrl_name, eb[lastname].x_axis) put_bone(self.obj, ctrl_name, eb[b].tail) ctrl += [ctrl_name] conv_twk = '' # Convergence tweak if self.params.conv_bone: conv_twk = 'tweak_' + strip_org(self.params.conv_bone) if not (conv_twk in eb.keys()): conv_twk = copy_bone(self.obj, org(self.params.conv_bone), conv_twk) for b in org_bones: if self.SINGLE_BONE: break # Mch controls suffix = '' if '.L' in b: suffix = '.L' elif '.R' in b: suffix = '.R' mch_ctrl_name = "MCH-CTRL-" + strip_org(b).split('.')[0] + suffix mch_ctrl_name = copy_bone(self.obj, twk[0] if twk else ctrl[0], mch_ctrl_name) eb[mch_ctrl_name].length /= 6 put_bone(self.obj, mch_ctrl_name, eb[b].head) mch_ctrl += [mch_ctrl_name] if b == org_bones[-1]: # Add extra mch_ctrl_name = "MCH-CTRL-" + strip_org(b).split( '.')[0] + suffix mch_ctrl_name = copy_bone(self.obj, twk[0] if twk else ctrl[0], mch_ctrl_name) eb[mch_ctrl_name].length /= 6 put_bone(self.obj, mch_ctrl_name, eb[b].tail) mch_ctrl += [mch_ctrl_name] return { 'mch': mch, 'mch_ctrl': mch_ctrl, 'mch_auto': mch_auto, 'tweak': twk, 'ctrl': ctrl, 'conv': conv_twk }