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 = self.lip_len + 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) # 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 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_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 make_mch_chain(self): """ Create all MCHs needed on a single chain :return: :rtype: list """ 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['mch'] = [] if self.chain_type == ChainType.TYPE_MCH_BASED: for chain_bone in chain: mch = make_mechanism_name(strip_org(chain_bone)) mch = copy_bone(self.obj, chain_bone, assign_name=mch) edit_bones[mch].parent = None edit_bones[mch].use_connect = False edit_bones[mch].length *= self.MCH_SCALE self._bones['mch'].append(mch) return self._bones['mch']
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 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') eb = self.obj.data.edit_bones org_delta = self.org_bones["delta"] org_delta_e = eb[self.org_bones["delta"]] # org_child = self.org_bones["child"] # UNUSED org_child_e = eb[self.org_bones["child"]] # Calculate the matrix for achieving the delta child_mat = org_delta_e.matrix.invert() * org_child_e.matrix mat = org_delta_e.matrix * child_mat.invert() # Create the delta bones. delta_e = eb[copy_bone(self.obj, self.org_bones["delta"])] delta_e.name = make_mechanism_name(self.org_names[0]) delta = delta_e.name # Set the delta to the matrix's transforms set_mat(self.obj, delta, mat) bpy.ops.object.mode_set(mode='OBJECT') # Constrain org_delta to delta con = self.obj.pose.bones[org_delta].constraints.new('COPY_TRANSFORMS') con.name = "delta" con.target = self.obj con.subtarget = delta
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') eb = self.obj.data.edit_bones org_delta = self.org_bones["delta"] org_delta_e = eb[self.org_bones["delta"]] org_child = self.org_bones["child"] org_child_e = eb[self.org_bones["child"]] # Calculate the matrix for achieving the delta child_mat = org_delta_e.matrix.invert() * org_child_e.matrix mat = org_delta_e.matrix * child_mat.invert() # Create the delta bones. delta_e = eb[copy_bone(self.obj, self.org_bones["delta"])] delta_e.name = make_mechanism_name(self.org_names[0]) delta = delta_e.name # Set the delta to the matrix's transforms set_mat(self.obj, delta, mat) bpy.ops.object.mode_set(mode='OBJECT') # Constrain org_delta to delta con = self.obj.pose.bones[org_delta].constraints.new('COPY_TRANSFORMS') con.name = "delta" con.target = self.obj con.subtarget = delta
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 the control bones uarm = copy_bone(self.obj, self.org_bones[0], strip_org(self.org_bones[0])) farm = copy_bone(self.obj, self.org_bones[1], strip_org(self.org_bones[1])) hand = copy_bone(self.obj, self.org_bones[2], strip_org(self.org_bones[2])) # Create the hinge bones if self.org_parent != None: hinge = copy_bone(self.obj, self.org_parent, make_mechanism_name(uarm + ".hinge")) socket1 = copy_bone(self.obj, uarm, make_mechanism_name(uarm + ".socket1")) socket2 = copy_bone(self.obj, uarm, make_mechanism_name(uarm + ".socket2")) # Get edit bones eb = self.obj.data.edit_bones uarm_e = eb[uarm] farm_e = eb[farm] hand_e = eb[hand] if self.org_parent != None: hinge_e = eb[hinge] socket1_e = eb[socket1] socket2_e = eb[socket2] # Parenting farm_e.parent = uarm_e hand_e.parent = farm_e if self.org_parent != None: hinge_e.use_connect = False socket1_e.use_connect = False socket2_e.use_connect = False uarm_e.parent = hinge_e hinge_e.parent = socket2_e socket2_e.parent = None # Positioning if self.org_parent != None: center = (hinge_e.head + hinge_e.tail) / 2 hinge_e.head = center socket1_e.length /= 4 socket2_e.length /= 3 # Object mode, get pose bones bpy.ops.object.mode_set(mode='OBJECT') pb = self.obj.pose.bones uarm_p = pb[uarm] farm_p = pb[farm] hand_p = pb[hand] if self.org_parent != None: hinge_p = pb[hinge] if self.org_parent != None: # socket1_p = pb[socket1] # UNUSED socket2_p = pb[socket2] # Set the elbow to only bend on the x-axis. farm_p.rotation_mode = 'XYZ' if 'X' in self.primary_rotation_axis: farm_p.lock_rotation = (False, True, True) elif 'Y' in self.primary_rotation_axis: farm_p.lock_rotation = (True, False, True) else: farm_p.lock_rotation = (True, True, False) # Hinge transforms are locked, for auto-ik if self.org_parent != None: hinge_p.lock_location = True, True, True hinge_p.lock_rotation = True, True, True hinge_p.lock_rotation_w = True hinge_p.lock_scale = True, True, True # Set up custom properties if self.org_parent != None: prop = rna_idprop_ui_prop_get(uarm_p, "isolate", create=True) uarm_p["isolate"] = 0.0 prop["soft_min"] = prop["min"] = 0.0 prop["soft_max"] = prop["max"] = 1.0 # Hinge constraints / drivers if self.org_parent != None: con = socket2_p.constraints.new('COPY_LOCATION') con.name = "copy_location" con.target = self.obj con.subtarget = socket1 con = socket2_p.constraints.new('COPY_TRANSFORMS') con.name = "isolate_off" con.target = self.obj con.subtarget = socket1 # 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 = uarm_p.path_from_id() + '["isolate"]' mod = fcurve.modifiers[0] mod.poly_order = 1 mod.coefficients[0] = 1.0 mod.coefficients[1] = -1.0 # Constrain org bones to controls con = pb[self.org_bones[0]].constraints.new('COPY_TRANSFORMS') con.name = "fk" con.target = self.obj con.subtarget = uarm con = pb[self.org_bones[1]].constraints.new('COPY_TRANSFORMS') con.name = "fk" con.target = self.obj con.subtarget = farm con = pb[self.org_bones[2]].constraints.new('COPY_TRANSFORMS') con.name = "fk" con.target = self.obj con.subtarget = hand # Set layers if specified if self.layers: uarm_p.bone.layers = self.layers farm_p.bone.layers = self.layers hand_p.bone.layers = self.layers # Create control widgets create_limb_widget(self.obj, uarm) create_limb_widget(self.obj, farm) ob = create_widget(self.obj, hand) 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 return [uarm, farm, hand]
def generate(self): bpy.ops.object.mode_set(mode='EDIT') eb = self.obj.data.edit_bones # Create the control bones ulimb_ik = copy_bone( self.obj, self.org_bones[0], pantin_utils.strip_LR_numbers(strip_org(self.org_bones[0])) + '.IK' + self.side_suffix) flimb_ik = copy_bone( self.obj, self.org_bones[1], make_mechanism_name( pantin_utils.strip_LR_numbers(strip_org(self.org_bones[1])) + '.IK' + self.side_suffix)) elimb_ik = copy_bone( self.obj, self.org_bones[2], pantin_utils.strip_LR_numbers(strip_org(self.org_bones[2])) + '.IK' + self.side_suffix) ulimb_str = copy_bone( self.obj, self.org_bones[0], make_mechanism_name( pantin_utils.strip_LR_numbers(strip_org(self.org_bones[0])) + ".stretch.ik" + self.side_suffix)) flimb_str = copy_bone( self.obj, self.org_bones[1], make_mechanism_name( pantin_utils.strip_LR_numbers(strip_org(self.org_bones[1])) + ".stretch.ik" + self.side_suffix)) elimb_str = copy_bone( self.obj, self.org_bones[2], make_mechanism_name( pantin_utils.strip_LR_numbers(strip_org(self.org_bones[2])) + ".stretch.ik" + self.side_suffix)) joint_str = new_bone( self.obj, pantin_utils.strip_LR_numbers(strip_org(self.org_bones[1])) + '.IK' + self.side_suffix) eb[joint_str].head = eb[flimb_str].head eb[joint_str].tail = (eb[flimb_str].head + Vector( (0, 0, 1)) * eb[flimb_str].length / 2) align_bone_x_axis(self.obj, joint_str, Vector((-1, 0, 0))) # put_bone(self.obj, joint_str, Vector(eb[flimb_str].head)) # Pelvis follow elimb_ik_root = copy_bone( self.obj, self.org_bones[2], make_mechanism_name( pantin_utils.strip_LR_numbers(strip_org(self.org_bones[2])) + ".ik_root" + self.side_suffix)) elimb_ik_parent = copy_bone( self.obj, self.org_bones[2], make_mechanism_name( pantin_utils.strip_LR_numbers(strip_org(self.org_bones[2])) + ".ik_parent" + self.side_suffix)) elimb_ik_socket = copy_bone( self.obj, self.org_bones[2], make_mechanism_name( pantin_utils.strip_LR_numbers(strip_org(self.org_bones[2])) + ".ik_socket" + self.side_suffix)) # Get edit bones ulimb_ik_e = eb[ulimb_ik] flimb_ik_e = eb[flimb_ik] elimb_ik_e = eb[elimb_ik] ulimb_str_e = eb[ulimb_str] flimb_str_e = eb[flimb_str] elimb_str_e = eb[elimb_str] joint_str_e = eb[joint_str] elimb_ik_root_e = eb[elimb_ik_root] elimb_ik_parent_e = eb[elimb_ik_parent] elimb_ik_socket_e = eb[elimb_ik_socket] # Parenting # Side org chain for b, o_b in zip(self.side_org_bones[1:], self.org_bones[1:]): eb[b].parent = eb[ pantin_utils.strip_LR_numbers(eb[o_b].parent.name) + self.side_suffix] if self.org_parent is not None: ulimb_ik_e.use_connect = False ulimb_ik_e.parent = eb[self.org_parent] flimb_ik_e.use_connect = False flimb_ik_e.parent = ulimb_ik_e elimb_ik_root_e.use_connect = False elimb_ik_root_e.parent = None elimb_ik_parent_e.use_connect = False elimb_ik_parent_e.parent = eb[self.side_org_bones[0]].parent elimb_ik_socket_e.use_connect = False elimb_ik_socket_e.parent = None elimb_ik_e.use_connect = False elimb_ik_e.parent = elimb_ik_socket_e if self.org_parent is not None: ulimb_str_e.use_connect = False ulimb_str_e.parent = eb[self.org_parent] flimb_str_e.use_connect = False flimb_str_e.parent = joint_str_e elimb_str_e.use_connect = True elimb_str_e.parent = flimb_ik_e joint_str_e.use_connect = False joint_str_e.parent = ulimb_ik_e # Layers joint_str_e.layers = elimb_str_e.layers # Object mode, get pose bones bpy.ops.object.mode_set(mode='OBJECT') pb = self.obj.pose.bones ulimb_ik_p = pb[ulimb_ik] flimb_ik_p = pb[flimb_ik] elimb_ik_p = pb[elimb_ik] ulimb_str_p = pb[ulimb_str] flimb_str_p = pb[flimb_str] elimb_str_p = pb[elimb_str] joint_str_p = pb[joint_str] joint_str_p.lock_location = (False, False, True) joint_str_p.lock_rotation = (True, True, False) joint_str_p.lock_rotation_w = False joint_str_p.lock_scale = (False, False, False) joint_str_p.rotation_mode = 'XZY' # Set up custom properties prop = rna_idprop_ui_prop_get(elimb_ik_p, "pelvis_follow", create=True) elimb_ik_p["pelvis_follow"] = int(self.pelvis_follow) prop["soft_min"] = 0 prop["soft_max"] = 1 prop["min"] = 0 prop["max"] = 1 prop = rna_idprop_ui_prop_get(elimb_ik_p, "IK_FK", create=True) elimb_ik_p["IK_FK"] = 0 prop["soft_min"] = 0 prop["soft_max"] = 1 prop["min"] = 0 prop["max"] = 1 # Constraints # Bend hint, ripped off from Rigify' biped con = flimb_ik_p.constraints.new('LIMIT_ROTATION') con.name = "bend_hint" con.use_limit_z = True con.min_z = radians(45) con.max_z = radians(45) con.owner_space = 'LOCAL' con = flimb_ik_p.constraints.new('IK') con.name = "ik" con.target = self.obj con.subtarget = elimb_ik con.chain_count = 2 con = ulimb_str_p.constraints.new('COPY_LOCATION') con.name = "anchor" con.target = self.obj con.subtarget = ulimb_ik con.target_space = 'LOCAL' con.owner_space = 'LOCAL' con = elimb_str_p.constraints.new('COPY_ROTATION') con.name = "copy rotation" con.target = self.obj con.subtarget = elimb_ik con.target_space = 'POSE' con.owner_space = 'POSE' con = ulimb_str_p.constraints.new('STRETCH_TO') con.name = "stretch to" con.target = self.obj con.subtarget = joint_str con.volume = 'NO_VOLUME' con.rest_length = ulimb_str_p.length con.keep_axis = 'PLANE_Z' con = flimb_str_p.constraints.new('STRETCH_TO') con.name = "stretch to" con.target = self.obj con.subtarget = elimb_str con.volume = 'NO_VOLUME' con.rest_length = flimb_str_p.length con.keep_axis = 'PLANE_Z' # Pelvis follow con = pb[elimb_ik_socket].constraints.new('COPY_TRANSFORMS') con.name = "copy root" con.target = self.obj con.subtarget = elimb_ik_root con = pb[elimb_ik_socket].constraints.new('COPY_TRANSFORMS') con.name = "copy socket" con.target = self.obj con.subtarget = elimb_ik_parent # Drivers driver = self.obj.driver_add(con.path_from_id("influence")) driver.driver.expression = 'pelvis_follow' var = driver.driver.variables.new() var.type = 'SINGLE_PROP' var.name = 'pelvis_follow' var.targets[0].id_type = 'OBJECT' var.targets[0].id = self.obj var.targets[0].data_path = (pb[elimb_ik].path_from_id() + '["pelvis_follow"]') # IK Limits ulimb_ik_p.lock_ik_x = True ulimb_ik_p.lock_ik_y = True flimb_ik_p.lock_ik_x = True flimb_ik_p.lock_ik_y = True flimb_ik_p.use_ik_limit_z = True flimb_ik_p.ik_min_z = radians(self.ik_limits[0]) # 0.0 flimb_ik_p.ik_max_z = radians(self.ik_limits[1]) # radians(160.0) # Arm ik angle fix limb_angle = ulimb_ik_p.vector.xz.angle_signed(flimb_ik_p.vector.xz) if self.ik_limits[0] < 0: # folds counterclockwise (arms) # has to be slightly less than the original angle flimb_ik_p.ik_max_z = -limb_angle - .02 else: # has to be slightly more than the original angle flimb_ik_p.ik_min_z = -limb_angle + .02 return [ ulimb_ik, ulimb_str, flimb_ik, flimb_str, joint_str, elimb_ik, elimb_str ]
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 the bones uarm = copy_bone(self.obj, self.org_bones[0], make_mechanism_name(strip_org(insert_before_lr(self.org_bones[0], "_ik")))) farm = copy_bone(self.obj, self.org_bones[1], make_mechanism_name(strip_org(insert_before_lr(self.org_bones[1], "_ik")))) hand = copy_bone(self.obj, self.org_bones[2], strip_org(insert_before_lr(self.org_bones[2], "_ik"))) pole = copy_bone(self.obj, self.org_bones[0], strip_org(insert_before_lr(self.org_bones[0], "_pole"))) vishand = 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 uarm_e = eb[uarm] farm_e = eb[farm] hand_e = eb[hand] pole_e = eb[pole] vishand_e = eb[vishand] vispole_e = eb[vispole] # Parenting farm_e.parent = uarm_e hand_e.use_connect = False hand_e.parent = None pole_e.use_connect = False vishand_e.use_connect = False vishand_e.parent = None vispole_e.use_connect = False vispole_e.parent = None # Misc hand_e.use_local_location = False vishand_e.hide_select = True vispole_e.hide_select = True # Positioning v1 = farm_e.tail - uarm_e.head if 'X' in self.primary_rotation_axis or 'Y' in self.primary_rotation_axis: v2 = v1.cross(farm_e.x_axis) if (v2 * farm_e.z_axis) > 0.0: v2 *= -1.0 else: v2 = v1.cross(farm_e.z_axis) if (v2 * farm_e.x_axis) < 0.0: v2 *= -1.0 v2.normalize() v2 *= v1.length if '-' in self.primary_rotation_axis: v2 *= -1 pole_e.head = farm_e.head + v2 pole_e.tail = pole_e.head + (Vector((0, 1, 0)) * (v1.length / 8)) pole_e.roll = 0.0 vishand_e.tail = vishand_e.head + Vector((0, 0, v1.length / 32)) vispole_e.tail = vispole_e.head + Vector((0, 0, v1.length / 32)) # Determine the pole offset value plane = (farm_e.tail - uarm_e.head).normalized() vec1 = uarm_e.x_axis.normalized() vec2 = (pole_e.head - uarm_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 # uarm_p = pb[uarm] # UNUSED farm_p = pb[farm] hand_p = pb[hand] pole_p = pb[pole] vishand_p = pb[vishand] vispole_p = pb[vispole] # Set the elbow to only bend on the primary axis if 'X' in self.primary_rotation_axis: farm_p.lock_ik_y = True farm_p.lock_ik_z = True elif 'Y' in self.primary_rotation_axis: farm_p.lock_ik_x = True farm_p.lock_ik_z = True else: farm_p.lock_ik_x = True farm_p.lock_ik_y = True # 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(hand_p, "ikfk_switch", create=True) hand_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 = farm_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 = farm_p.constraints.new('IK') con.name = "ik" con.target = self.obj con.subtarget = hand con.pole_target = self.obj con.pole_subtarget = pole con.pole_angle = pole_offset con.chain_count = 2 # Constrain org bones to controls con = pb[self.org_bones[0]].constraints.new('COPY_TRANSFORMS') con.name = "ik" con.target = self.obj con.subtarget = uarm 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 = hand_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 = farm 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 = hand_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 = hand 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 = hand_p.path_from_id() + '["ikfk_switch"]' # VIS hand constraints con = vishand_p.constraints.new('COPY_LOCATION') con.name = "copy_loc" con.target = self.obj con.subtarget = self.org_bones[2] con = vishand_p.constraints.new('STRETCH_TO') con.name = "stretch_to" con.target = self.obj con.subtarget = hand con.volume = 'NO_VOLUME' con.rest_length = vishand_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: hand_p.bone.layers = self.layers pole_p.bone.layers = self.layers vishand_p.bone.layers = self.layers vispole_p.bone.layers = self.layers # Create widgets create_line_widget(self.obj, vispole) create_line_widget(self.obj, vishand) create_sphere_widget(self.obj, pole) ob = create_widget(self.obj, hand) 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 return [uarm, farm, hand, pole]
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 control(self): """ Generate the control rig. """ bpy.ops.object.mode_set(mode='EDIT') # Figure out the name for the control bone (remove the last .##) ctrl_name = re.sub("([0-9]+\.)", "", strip_org(self.org_bones[0])[::-1], count=1)[::-1] # Create the bones ctrl = copy_bone(self.obj, self.org_bones[0], ctrl_name) helpers = [] bones = [] for bone in self.org_bones: bones += [copy_bone(self.obj, bone, strip_org(bone))] helpers += [ copy_bone(self.obj, bone, make_mechanism_name(strip_org(bone))) ] # Position bones eb = self.obj.data.edit_bones length = 0.0 for bone in helpers: length += eb[bone].length eb[bone].length /= 2 eb[ctrl].length = length * 1.5 # Parent bones prev = eb[self.org_bones[0]].parent for (b, h) in zip(bones, helpers): b_e = eb[b] h_e = eb[h] b_e.use_connect = False h_e.use_connect = False b_e.parent = h_e h_e.parent = prev prev = b_e # Transform locks and rotation mode bpy.ops.object.mode_set(mode='OBJECT') pb = self.obj.pose.bones for bone in bones[1:]: pb[bone].lock_location = True, True, True if pb[self.org_bones[0]].bone.use_connect is True: pb[bones[0]].lock_location = True, True, True pb[ctrl].lock_scale = True, False, True for bone in helpers: pb[bone].rotation_mode = 'XYZ' # Drivers i = 1 val = 1.2 / (len(self.org_bones) - 1) for bone in helpers: # Add custom prop prop_name = "bend_%02d" % i prop = rna_idprop_ui_prop_get(pb[ctrl], prop_name, create=True) prop["min"] = 0.0 prop["max"] = 1.0 prop["soft_min"] = 0.0 prop["soft_max"] = 1.0 if i == 1: pb[ctrl][prop_name] = 0.0 else: pb[ctrl][prop_name] = val # Add driver if 'X' in self.primary_rotation_axis: fcurve = pb[bone].driver_add("rotation_euler", 0) elif 'Y' in self.primary_rotation_axis: fcurve = pb[bone].driver_add("rotation_euler", 1) else: fcurve = pb[bone].driver_add("rotation_euler", 2) driver = fcurve.driver driver.type = 'SCRIPTED' var = driver.variables.new() var.name = "ctrl_y" var.targets[0].id_type = 'OBJECT' var.targets[0].id = self.obj var.targets[0].data_path = pb[ctrl].path_from_id() + '.scale[1]' var = driver.variables.new() var.name = "bend" var.targets[0].id_type = 'OBJECT' var.targets[0].id = self.obj var.targets[0].data_path = pb[ctrl].path_from_id( ) + '["' + prop_name + '"]' if '-' in self.primary_rotation_axis: driver.expression = "-(1.0-ctrl_y) * bend * 3.14159 * 2" else: driver.expression = "(1.0-ctrl_y) * bend * 3.14159 * 2" i += 1 # Constraints con = pb[helpers[0]].constraints.new('COPY_LOCATION') con.name = "copy_location" con.target = self.obj con.subtarget = ctrl con = pb[helpers[0]].constraints.new('COPY_ROTATION') con.name = "copy_rotation" con.target = self.obj con.subtarget = ctrl # Constrain org bones to the control bones for (bone, org) in zip(bones, self.org_bones): con = pb[org].constraints.new('COPY_TRANSFORMS') con.name = "copy_transforms" con.target = self.obj con.subtarget = bone # Set layers for extra control bones if self.ex_layers: for bone in bones: pb[bone].bone.layers = self.ex_layers # Create control widgets w = create_widget(self.obj, ctrl) if w is not None: mesh = w.data verts = [(0, 0, 0), (0, 1, 0), (0.05, 1, 0), (0.05, 1.1, 0), (-0.05, 1.1, 0), (-0.05, 1, 0)] if 'Z' in self.primary_rotation_axis: # Flip x/z coordinates temp = [] for v in verts: temp += [(v[2], v[1], v[0])] verts = temp edges = [(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 1)] mesh.from_pydata(verts, edges, []) mesh.update() for bone in bones: create_limb_widget(self.obj, bone)
def generate(self): bpy.ops.object.mode_set(mode='EDIT') eb = self.obj.data.edit_bones trackers = [] flaps = [] flaps_MCH = [] # Left and right tracking bones for side in ['.L', '.R']: tracker = copy_bone( self.obj, self.org_bone, make_mechanism_name( strip_org(self.org_bone)) + side ) trackers.append(tracker) vertical = copy_bone( self.obj, self.org_bone, make_mechanism_name( strip_org(self.org_bone)) + '.vertical' ) # Front and rear bones for i, flap in enumerate(['.Front', '.Rear']): flap_mch_b = copy_bone( self.obj, self.org_bone, make_mechanism_name( strip_org(self.org_bone)) + flap ) flaps_MCH.append(flap_mch_b) flap_b = copy_bone( self.obj, self.org_bone, strip_org(self.org_bone) + flap ) flaps.append(flap_b) # Def bones def_bone = pantin_utils.create_deformation( self.obj, flap_b, member_index=self.params.Z_index, bone_index=i, new_name=strip_org(self.org_bone) + flap) # Parenting eb[flap_b].parent = eb[flap_mch_b] eb[flap_b].use_connect = False bpy.ops.object.mode_set(mode='OBJECT') pb = self.obj.pose.bones # Constraints con = pb[vertical].constraints.new('COPY_ROTATION') con.name = "Copy Pelvis" con.target = self.obj con.subtarget = pb[self.org_bone].parent.name con.use_x = False con.use_y = False con.use_z = True con.invert_z = True con.target_space = 'LOCAL' con.owner_space = 'LOCAL' for f, shin in zip(trackers, (self.params.shin_name_l, self.params.shin_name_r) ): con = pb[f].constraints.new('DAMPED_TRACK') con.name = "Track " + shin con.target = self.obj con.subtarget = "ORG-" + shin for f in flaps: # Widgets widget_size = pb[f].length pantin_utils.create_capsule_widget( self.obj, f, length=widget_size, width=widget_size*0.2, head_tail=0.5, horizontal=False ) for f_i, f in enumerate(flaps_MCH): con = pb[f].constraints.new('DAMPED_TRACK') con.name = "Track vertical" con.target = self.obj con.subtarget = vertical con.head_tail = 1.0 for s_i, shin in enumerate((self.params.shin_name_l, self.params.shin_name_r)): con = pb[f].constraints.new('DAMPED_TRACK') con.name = "Track " + shin con.target = self.obj con.subtarget = "ORG-" + shin # Drivers driver = self.obj.driver_add(con.path_from_id("influence")) # Relative component: which leg to track if f_i != s_i: relative = 'L > R' else: relative = 'L <= R' if s_i == 0: # Left absolute = 'L+P ' else: # Right absolute = 'R+P ' # Absolute component: do not track if rotation is below / above 0 if f_i == 0: # Front absolute += ' < 0' else: # Rear absolute += ' > 0' driver.driver.expression = '1 if {} and {} else 0'.format(relative, absolute) var = driver.driver.variables.new() var.type = 'TRANSFORMS' var.name = 'L' var.targets[0].id = self.obj var.targets[0].bone_target = trackers[0] var.targets[0].transform_type = 'ROT_Z' var.targets[0].transform_space = 'LOCAL_SPACE' var = driver.driver.variables.new() var.type = 'TRANSFORMS' var.name = 'R' var.targets[0].id = self.obj var.targets[0].bone_target = trackers[1] var.targets[0].transform_type = 'ROT_Z' var.targets[0].transform_space = 'LOCAL_SPACE' var = driver.driver.variables.new() var.type = 'TRANSFORMS' var.name = 'P' var.targets[0].id = self.obj var.targets[0].bone_target = pb[self.org_bone].parent.name var.targets[0].transform_type = 'ROT_Z' var.targets[0].transform_space = 'LOCAL_SPACE' return { 'imports': UI_IMPORTS, 'utilities': PANTIN_UTILS, 'register': PANTIN_REGISTER, 'register_props': REGISTER_PANTIN_PROPS, }
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 }
def generate(self): bpy.ops.object.mode_set(mode='EDIT') eb = self.obj.data.edit_bones pelvis = self.org_bones[0] pelvis_e = eb[pelvis] # # Intermediate root bone # root_name = self.params.root_name # root = new_bone(self.obj, root_name) # root_e = eb[root] # root_e.head = Vector((0, 0, 0)) # root_e.tail = Vector((0, 0, 1)) * pelvis_e.length/2 # align_bone_x_axis(self.obj, root, Vector((-1, 0, 0))) # root_e.layers = [i == 28 for i in range(32)] # # Flip bone # flip = new_bone(self.obj, make_mechanism_name('Flip')) # flip_e = eb[flip] # # flip_e.head = pelvis_e.head # flip_e.tail = flip_e.head + Vector((0, 0, 1)) * pelvis_e.length/2 # align_bone_x_axis(self.obj, flip, Vector((-1, 0, 0))) # root_e = eb[root] # flip_e.use_connect = False # flip_e.parent = root_e ctrl_chain = [] def_chain = [] for i, b in enumerate(self.org_bones): # Control bones ctrl_bone = copy_bone(self.obj, b) ctrl_bone_e = eb[ctrl_bone] # Name ctrl_bone_e.name = ctrl_bone = strip_org(b) # Parenting if i == 0: # First bone # Vertical intermediate pelvis (animation helper) inter_pelvis = copy_bone( self.obj, b, make_mechanism_name(strip_org(b) + '.intermediate')) ctrl_bone_e = eb[ctrl_bone] ctrl_bone_e.tail = ctrl_bone_e.head ctrl_bone_e.tail[2] += 1.0 * eb[b].length align_bone_z_axis(self.obj, ctrl_bone, Vector((0, 1, 0))) ctrl_bone_e = eb[ctrl_bone] # ctrl_bone_e.parent = eb[self.org_bones[0]].parent # eb[ctrl_bone].parent = None eb[inter_pelvis].parent = ctrl_bone_e elif i == 1: ctrl_bone_e.parent = eb[inter_pelvis] else: # The rest ctrl_bone_e.parent = eb[ctrl_chain[-1]] # Add to list ctrl_chain += [ctrl_bone_e.name] # Def bones def_bone = pantin_utils.create_deformation( self.obj, b, member_index=self.params.Z_index, bone_index=i) def_chain.append(def_bone) # flip_e = eb[flip] pelvis_e = eb[ctrl_chain[0]] pelvis_e.use_connect = False # pelvis_e.parent = flip_e bpy.ops.object.mode_set(mode='OBJECT') pb = self.obj.pose.bones # # Pose bone settings # flip_p = pb[flip] # flip_p.rotation_mode = 'XZY' # root_p = pb[root] # root_p.lock_location = (False, False, True) # root_p.lock_rotation = (True, True, False) # root_p.lock_rotation_w = False # root_p.lock_scale = (False, False, False) # root_p.rotation_mode = 'XZY' # # Set up custom properties # prop = rna_idprop_ui_prop_get(flip_p, "flip", create=True) # flip_p["flip"] = 0 # prop["soft_min"] = 0 # prop["soft_max"] = 1 # prop["min"] = 0 # prop["max"] = 1 # Widgets global_scale = self.obj.dimensions[2] member_factor = 0.1 widget_size = global_scale * member_factor pelvis = ctrl_chain[0] # abdomen = ctrl_chain[1] # torso = ctrl_chain[2] # shoulder = ctrl_chain[3] # create_cube_widget(self.obj, pelvis, radius=widget_size*4) radius = widget_size pelvis_center = pb[pelvis].center vp = ((-radius * 2.0 + pelvis_center.x, -radius + pelvis_center.z), (-radius * 2.0 + pelvis_center.x, radius + pelvis_center.z), (radius * 2.0 + pelvis_center.x, radius + pelvis_center.z), (radius * 2.0 + pelvis_center.x, -radius + pelvis_center.z)) pantin_utils.create_aligned_polygon_widget(self.obj, pelvis, vertex_points=vp) # pantin_utils.create_aligned_half_ellipse_widget( # self.obj, root, width=widget_size*1.5, height=widget_size) for bone in ctrl_chain[1:]: pantin_utils.create_capsule_widget(self.obj, bone, length=widget_size, width=widget_size * 0.1, head_tail=0.5) # create_widget(self.obj, bone) # Drivers # driver = self.obj.driver_add( # 'pose.bones["{}"].rotation_euler'.format(flip), 1) # driver.driver.expression = 'pi*flip' # var_flip = driver.driver.variables.new() # # var_flip.type = 'SINGLE_PROP' # var_flip.name = 'flip' # var_flip.targets[0].id_type = 'OBJECT' # var_flip.targets[0].id = self.obj # var_flip.targets[0].data_path = 'pose.bones["root"]["flip"]'.format(flip) # Constraints # for pelvis con = pb[self.org_bones[0]].constraints.new('COPY_TRANSFORMS') con.name = "copy_transforms" con.target = self.obj con.subtarget = inter_pelvis # for others for org, ctrl in zip(self.org_bones[1:], ctrl_chain[1:]): con = pb[org].constraints.new('COPY_TRANSFORMS') con.name = "copy_transforms" con.target = self.obj con.subtarget = ctrl return { 'script': [UI_PANTIN_SCRIPT], 'imports': UI_IMPORTS, 'utilities': PANTIN_UTILS, 'register': PANTIN_REGISTER, 'register_props': REGISTER_PANTIN_PROPS, }
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): if self.params.use_parent_Z_index and self.org_parent is not None: # Get parent's Z indices bpy.ops.object.mode_set(mode='OBJECT') pb = self.obj.pose.bones def_parent_name = make_deformer_name(strip_org(self.org_parent)) if (self.params.object_side != ".C" and def_parent_name[-2:] not in ['.L', '.R']): def_parent_name += self.params.object_side # print("DEF PARENT", def_parent_name) if not def_parent_name in pb: raise MetarigError( "RIGIFY ERROR: Bone %s does not have a %s side" % (strip_org(self.org_parent), self.params.object_side)) parent_p = pb[def_parent_name] member_Z_index = parent_p['member_index'] bone_Z_index = 0 for b in pb: if b.bone.use_deform and b.name.startswith('DEF-'): if (b['member_index'] == member_Z_index and b['bone_index'] > bone_Z_index): bone_Z_index = b['bone_index'] bone_Z_index += 1 bpy.ops.object.mode_set(mode='EDIT') else: member_Z_index = self.params.member_Z_index bone_Z_index = self.params.first_bone_Z_index eb = self.obj.data.edit_bones ctrl_chain = [] # mch_chain = [] # Control bones # Left left_ctrl = copy_bone(self.obj, self.org_bone, strip_org(self.params.eye_name) + '.L') left_ctrl_e = eb[left_ctrl] left_ctrl_e.use_connect = False left_ctrl_e.tail = (left_ctrl_e.tail + Vector( (0, 0, 1)) * left_ctrl_e.length) left_ctrl_e.head = eb[self.org_bone].tail align_bone_z_axis(self.obj, left_ctrl, Vector((0, 1, 0))) ctrl_chain.append(left_ctrl) # Right right_ctrl = copy_bone(self.obj, self.org_bone, strip_org(self.params.eye_name) + '.R') right_ctrl_e = eb[right_ctrl] right_ctrl_e.use_connect = False right_ctrl_e.tail = (right_ctrl_e.head + Vector( (0, 0, 1)) * right_ctrl_e.length) align_bone_z_axis(self.obj, right_ctrl, Vector((0, 1, 0))) ctrl_chain.append(right_ctrl) # Main main_ctrl = copy_bone(self.obj, self.org_bone, strip_org(self.org_bone)) main_ctrl_e = eb[main_ctrl] main_ctrl_e.head = (main_ctrl_e.head + main_ctrl_e.tail) / 2 if self.org_parent is not None: main_ctrl_e.parent = eb[self.org_parent] ctrl_chain.append(main_ctrl) # Mechanism bones inter = copy_bone( self.obj, self.org_bone, make_mechanism_name(strip_org(self.org_bone) + '.intermediate')) eb[inter].parent = eb[main_ctrl] eb[left_ctrl].parent = eb[inter] eb[right_ctrl].parent = eb[inter] # # Def bones for i, b in enumerate([left_ctrl, right_ctrl]): def_bone = pantin_utils.create_deformation(self.obj, b, member_Z_index, bone_Z_index + i, 0.0, b) bpy.ops.object.mode_set(mode='OBJECT') pb = self.obj.pose.bones # Widgets pantin_utils.create_capsule_widget(self.obj, main_ctrl, length=pb[self.org_bone].length, width=pb[self.org_bone].length * 0.7, horizontal=False) for b in [left_ctrl, right_ctrl]: pantin_utils.create_aligned_circle_widget(self.obj, b, radius=pb[b].length / 4) # for ctrl_bone in ctrl_chain: # global_scale = pb[ctrl_bone].length # self.obj.dimensions[2] # # member_factor = 0.06 # widget_size = global_scale * 0.5 # * member_factor # pantin_utils.create_aligned_circle_widget( # self.obj, ctrl_bone, radius=widget_size) # Constraints # for org, ctrl in zip(self.org_bones, mch_chain): con = pb[self.org_bone].constraints.new('COPY_TRANSFORMS') con.name = "copy_transforms" con.target = self.obj con.subtarget = inter # # Pelvis follow # if self.params.do_flip: # pantin_utils.create_ik_child_of( # self.obj, ctrl_bone, self.params.pelvis_name) return { 'imports': UI_IMPORTS, 'utilities': PANTIN_UTILS, 'register': PANTIN_REGISTER, 'register_props': REGISTER_PANTIN_PROPS, }
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 control(self): """ Generate the control rig. """ bpy.ops.object.mode_set(mode="EDIT") # Figure out the name for the control bone (remove the last .##) ctrl_name = re.sub("([0-9]+\.)", "", strip_org(self.org_bones[0])[::-1], count=1)[::-1] # Create the bones ctrl = copy_bone(self.obj, self.org_bones[0], ctrl_name) helpers = [] bones = [] for bone in self.org_bones: bones += [copy_bone(self.obj, bone, strip_org(bone))] helpers += [copy_bone(self.obj, bone, make_mechanism_name(strip_org(bone)))] # Position bones eb = self.obj.data.edit_bones length = 0.0 for bone in helpers: length += eb[bone].length eb[bone].length /= 2 eb[ctrl].length = length * 1.5 # Parent bones prev = eb[self.org_bones[0]].parent for (b, h) in zip(bones, helpers): b_e = eb[b] h_e = eb[h] b_e.use_connect = False h_e.use_connect = False b_e.parent = h_e h_e.parent = prev prev = b_e # Transform locks and rotation mode bpy.ops.object.mode_set(mode="OBJECT") pb = self.obj.pose.bones for bone in bones[1:]: pb[bone].lock_location = True, True, True if pb[self.org_bones[0]].bone.use_connect == True: pb[bones[0]].lock_location = True, True, True pb[ctrl].lock_scale = True, False, True for bone in helpers: pb[bone].rotation_mode = "XYZ" # Drivers i = 1 val = 1.2 / (len(self.org_bones) - 1) for bone in helpers: # Add custom prop prop_name = "bend_%02d" % i prop = rna_idprop_ui_prop_get(pb[ctrl], prop_name, create=True) prop["min"] = 0.0 prop["max"] = 1.0 prop["soft_min"] = 0.0 prop["soft_max"] = 1.0 if i == 1: pb[ctrl][prop_name] = 0.0 else: pb[ctrl][prop_name] = val # Add driver if "X" in self.primary_rotation_axis: fcurve = pb[bone].driver_add("rotation_euler", 0) elif "Y" in self.primary_rotation_axis: fcurve = pb[bone].driver_add("rotation_euler", 1) else: fcurve = pb[bone].driver_add("rotation_euler", 2) driver = fcurve.driver driver.type = "SCRIPTED" var = driver.variables.new() var.name = "ctrl_y" var.targets[0].id_type = "OBJECT" var.targets[0].id = self.obj var.targets[0].data_path = pb[ctrl].path_from_id() + ".scale[1]" var = driver.variables.new() var.name = "bend" var.targets[0].id_type = "OBJECT" var.targets[0].id = self.obj var.targets[0].data_path = pb[ctrl].path_from_id() + '["' + prop_name + '"]' if "-" in self.primary_rotation_axis: driver.expression = "-(1.0-ctrl_y) * bend * 3.14159 * 2" else: driver.expression = "(1.0-ctrl_y) * bend * 3.14159 * 2" i += 1 # Constraints con = pb[helpers[0]].constraints.new("COPY_LOCATION") con.name = "copy_location" con.target = self.obj con.subtarget = ctrl con = pb[helpers[0]].constraints.new("COPY_ROTATION") con.name = "copy_rotation" con.target = self.obj con.subtarget = ctrl # Constrain org bones to the control bones for (bone, org) in zip(bones, self.org_bones): con = pb[org].constraints.new("COPY_TRANSFORMS") con.name = "copy_transforms" con.target = self.obj con.subtarget = bone # Set layers for extra control bones if self.ex_layers: for bone in bones: pb[bone].bone.layers = self.ex_layers # Create control widgets w = create_widget(self.obj, ctrl) if w != None: mesh = w.data verts = [(0, 0, 0), (0, 1, 0), (0.05, 1, 0), (0.05, 1.1, 0), (-0.05, 1.1, 0), (-0.05, 1, 0)] if "Z" in self.primary_rotation_axis: # Flip x/z coordinates temp = [] for v in verts: temp += [(v[2], v[1], v[0])] verts = temp edges = [(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 1)] mesh.from_pydata(verts, edges, []) mesh.update() for bone in bones: create_limb_widget(self.obj, bone)
def deform(self): """ Generate the deformation rig. Just a copy of the original bones, except the first digit which is a twist bone. """ bpy.ops.object.mode_set(mode='EDIT') # Create the bones # First bone is a twist bone if self.use_digit_twist: b1a = copy_bone( self.obj, self.org_bones[0], make_deformer_name(strip_org(self.org_bones[0] + ".01"))) b1b = copy_bone( self.obj, self.org_bones[0], make_deformer_name(strip_org(self.org_bones[0] + ".02"))) b1tip = copy_bone( self.obj, self.org_bones[0], make_mechanism_name(strip_org(self.org_bones[0] + ".tip"))) else: b1 = copy_bone(self.obj, self.org_bones[0], make_deformer_name(strip_org(self.org_bones[0]))) # The rest are normal bones = [] for bone in self.org_bones[1:]: bones += [ copy_bone(self.obj, bone, make_deformer_name(strip_org(bone))) ] # Position bones eb = self.obj.data.edit_bones if self.use_digit_twist: b1a_e = eb[b1a] b1b_e = eb[b1b] b1tip_e = eb[b1tip] b1tip_e.use_connect = False b1tip_e.tail += Vector((0.1, 0, 0)) b1tip_e.head = b1b_e.tail b1tip_e.length = b1a_e.length / 4 center = (b1a_e.head + b1a_e.tail) / 2 b1a_e.tail = center b1b_e.use_connect = False b1b_e.head = center # Parenting if self.use_digit_twist: b1b_e.parent = eb[self.org_bones[0]] b1tip_e.parent = eb[self.org_bones[0]] else: eb[b1].use_connect = False eb[b1].parent = eb[self.org_bones[0]] for (ba, bb) in zip(bones, self.org_bones[1:]): eb[ba].use_connect = False eb[ba].parent = eb[bb] # Constraints if self.use_digit_twist: bpy.ops.object.mode_set(mode='OBJECT') pb = self.obj.pose.bones b1a_p = pb[b1a] con = b1a_p.constraints.new('COPY_LOCATION') con.name = "copy_location" con.target = self.obj con.subtarget = self.org_bones[0] con = b1a_p.constraints.new('COPY_SCALE') con.name = "copy_scale" con.target = self.obj con.subtarget = self.org_bones[0] con = b1a_p.constraints.new('DAMPED_TRACK') con.name = "track_to" con.target = self.obj con.subtarget = b1tip
def deform(self): """ Generate the deformation rig. Just a copy of the original bones, except the first digit which is a twist bone. """ bpy.ops.object.mode_set(mode="EDIT") # Create the bones # First bone is a twist bone if self.use_digit_twist: b1a = copy_bone(self.obj, self.org_bones[0], make_deformer_name(strip_org(self.org_bones[0] + ".01"))) b1b = copy_bone(self.obj, self.org_bones[0], make_deformer_name(strip_org(self.org_bones[0] + ".02"))) b1tip = copy_bone(self.obj, self.org_bones[0], make_mechanism_name(strip_org(self.org_bones[0] + ".tip"))) else: b1 = copy_bone(self.obj, self.org_bones[0], make_deformer_name(strip_org(self.org_bones[0]))) # The rest are normal bones = [] for bone in self.org_bones[1:]: bones += [copy_bone(self.obj, bone, make_deformer_name(strip_org(bone)))] # Position bones eb = self.obj.data.edit_bones if self.use_digit_twist: b1a_e = eb[b1a] b1b_e = eb[b1b] b1tip_e = eb[b1tip] b1tip_e.use_connect = False b1tip_e.tail += Vector((0.1, 0, 0)) b1tip_e.head = b1b_e.tail b1tip_e.length = b1a_e.length / 4 center = (b1a_e.head + b1a_e.tail) / 2 b1a_e.tail = center b1b_e.use_connect = False b1b_e.head = center # Parenting if self.use_digit_twist: b1b_e.parent = eb[self.org_bones[0]] b1tip_e.parent = eb[self.org_bones[0]] else: eb[b1].use_connect = False eb[b1].parent = eb[self.org_bones[0]] for (ba, bb) in zip(bones, self.org_bones[1:]): eb[ba].use_connect = False eb[ba].parent = eb[bb] # Constraints if self.use_digit_twist: bpy.ops.object.mode_set(mode="OBJECT") pb = self.obj.pose.bones b1a_p = pb[b1a] con = b1a_p.constraints.new("COPY_LOCATION") con.name = "copy_location" con.target = self.obj con.subtarget = self.org_bones[0] con = b1a_p.constraints.new("COPY_SCALE") con.name = "copy_scale" con.target = self.obj con.subtarget = self.org_bones[0] con = b1a_p.constraints.new("DAMPED_TRACK") con.name = "track_to" con.target = self.obj con.subtarget = b1tip
def generate(self): ui_script = "" for s, limb in self.sides.items(): side_org_bones, ik_limb, fk_limb = limb (ulimb_ik, ulimb_str, flimb_ik, flimb_str, joint_str, elimb_ik, elimb_str) = ik_limb.generate() ulimb_fk, flimb_fk, elimb_fk = fk_limb.generate() bpy.ops.object.mode_set(mode='EDIT') eb = self.obj.data.edit_bones # Foot rig foot_fr = copy_bone( self.obj, self.org_bones[2], pantin_utils.strip_LR_numbers( make_mechanism_name(strip_org(self.org_bones[2]))) + '.fr' + s) foot_tgt = copy_bone( self.obj, self.org_bones[2], pantin_utils.strip_LR_numbers( make_mechanism_name(strip_org(self.org_bones[2]))) + '.tgt' + s) heel_fr = copy_bone( self.obj, self.org_bones[3], pantin_utils.strip_LR_numbers( make_mechanism_name(strip_org(self.org_bones[3]))) + '.fr' + s) toe_fr = copy_bone( self.obj, self.org_bones[4], pantin_utils.strip_LR_numbers( make_mechanism_name(strip_org(self.org_bones[4]))) + '.fr' + s) toe_ik_ctl = copy_bone( self.obj, self.org_bones[4], pantin_utils.strip_LR_numbers(strip_org(self.org_bones[4])) + '.IK' + s) toe_fk_ctl = copy_bone( self.obj, self.org_bones[4], pantin_utils.strip_LR_numbers(strip_org(self.org_bones[4])) + '.FK' + s) toe_pos = copy_bone( self.obj, self.org_bones[4], pantin_utils.strip_LR_numbers( make_mechanism_name(strip_org(self.org_bones[4]))) + '.pos' + s) roll_fr = new_bone(self.obj, "Foot roll" + s) # Position eb[roll_fr].head = (eb[elimb_str].head + Vector( (-1, 0, 0)) * eb[elimb_str].length * 2) eb[roll_fr].tail = (eb[elimb_str].head + Vector( (-1, 0, 1)) * eb[elimb_str].length * 2) eb[roll_fr].layers = eb[elimb_ik].layers # IK foot horizontal and starting at heel eb[elimb_ik].head = eb[heel_fr].tail eb[elimb_ik].tail.z = eb[heel_fr].tail.z align_bone_x_axis(self.obj, elimb_ik, Vector((0, 0, 1))) align_bone_x_axis(self.obj, roll_fr, Vector((-1, 0, 0))) align_bone_x_axis(self.obj, foot_fr, Vector((-1, 0, 0))) align_bone_x_axis(self.obj, heel_fr, Vector((-1, 0, 0))) align_bone_x_axis(self.obj, toe_fr, Vector((-1, 0, 0))) # Parenting eb[foot_fr].parent = None eb[heel_fr].parent = None eb[toe_fr].parent = None flip_bone(self.obj, foot_fr) flip_bone(self.obj, heel_fr) flip_bone(self.obj, toe_fr) eb[foot_fr].use_connect = True eb[foot_fr].parent = eb[toe_fr] eb[foot_tgt].use_connect = True eb[foot_tgt].parent = eb[foot_fr] eb[toe_fr].use_connect = False eb[toe_fr].parent = eb[heel_fr] eb[toe_ik_ctl].use_connect = True eb[toe_ik_ctl].parent = eb[toe_fr] eb[toe_fk_ctl].use_connect = True eb[toe_fk_ctl].parent = eb[elimb_fk] eb[toe_pos].use_connect = False eb[toe_pos].parent = eb[elimb_str] eb[heel_fr].use_connect = False eb[heel_fr].parent = eb[elimb_ik] eb[roll_fr].use_connect = False eb[roll_fr].parent = eb[elimb_ik] if self.params.do_stretch: eb[elimb_str].use_connect = False # Def bones if s == '.L': Z_index = -self.params.Z_index else: Z_index = self.params.Z_index side_org_bones = side_org_bones[:3] + side_org_bones[ -1:] # Ignore heel for i, b in enumerate(side_org_bones): def_bone_name = pantin_utils.strip_LR_numbers(strip_org(b)) def_bone = pantin_utils.create_deformation( self.obj, b, member_index=Z_index, bone_index=i, new_name=def_bone_name + s) # Set layers if specified active_layer = pantin_utils.layers_to_index(eb[ulimb_ik].layers) right_offset = self.params.right_offset if self.params.duplicate_lr else 0 if s == '.R': for b in (ulimb_ik, joint_str, elimb_ik, roll_fr, toe_ik_ctl): eb[b].layers = get_layers(active_layer + right_offset) for b in (ulimb_fk, flimb_fk, elimb_fk, toe_fk_ctl): eb[b].layers = get_layers(active_layer + self.params.fk_offset + right_offset) elif s == '.L': for b in (ulimb_fk, flimb_fk, elimb_fk, toe_fk_ctl): eb[b].layers = get_layers(active_layer + self.params.fk_offset) bpy.ops.object.mode_set(mode='OBJECT') pb = self.obj.pose.bones # Bone settings pb[roll_fr].rotation_mode = 'XZY' pb[roll_fr].lock_location = [True] * 3 pb[roll_fr].lock_rotation = [True, True, False] pb[roll_fr].lock_scale = [True] * 3 pb[foot_fr].rotation_mode = 'XZY' # Widgets # IK global_scale = self.obj.dimensions[2] member_factor = 0.06 if s == '.R': side_factor = 1.2 else: side_factor = 1.0 widget_size = global_scale * member_factor * side_factor pantin_utils.create_aligned_circle_widget(self.obj, ulimb_ik, number_verts=3, radius=widget_size) pantin_utils.create_aligned_circle_widget(self.obj, joint_str, radius=widget_size) # FK widget_size = 0.5 for bone in (ulimb_fk, flimb_fk, elimb_fk, toe_fk_ctl): pantin_utils.create_capsule_widget(self.obj, bone, length=widget_size, width=widget_size * 0.2, head_tail=0.5, horizontal=False, overshoot=True) # Default follow value pb[ulimb_fk]["follow"] = 0.0 # Foot WGT down = pb[heel_fr].head.z left = pb[heel_fr].head.x - (side_factor - 1) * pb[heel_fr].length right = pb[foot_fr].head.x up = pb[foot_fr].tail.z + (side_factor - 1) * pb[heel_fr].length foot_verts = ((left, down), (left, up), (right, down + (up - down) * 2 / 3), (right, down)) pantin_utils.create_aligned_polygon_widget(self.obj, elimb_ik, foot_verts) # Toe WGT left = right right = pb[toe_fr].head.x + (side_factor - 1) * pb[heel_fr].length up = down + (up - down) * 2 / 3 # TODO investigate why moving an edit bones # screws up widgets' matrices (foot_ik has moved) toe_verts = ((left, down), (left, up), (right, down + (up - down) * 2 / 3), (right, down)) pantin_utils.create_aligned_polygon_widget(self.obj, toe_ik_ctl, toe_verts) pantin_utils.create_aligned_crescent_widget(self.obj, roll_fr, radius=side_factor * pb[roll_fr].length / 2) # Constraints foot_fr_p = pb[foot_fr] heel_fr_p = pb[heel_fr] toe_fr_p = pb[toe_fr] roll_fr_p = pb[roll_fr] hor_vector = Vector((1, 0, 0)) foot_rotation = (foot_fr_p.vector.rotation_difference( hor_vector).to_euler('XZY')) toe_rotation = toe_fr_p.vector.rotation_difference( hor_vector).to_euler('XZY') foot_vertical_rot = foot_rotation[1] - pi / 2 toe_vertical_rot = toe_rotation[1] - pi / 2 con = foot_fr_p.constraints.new('TRANSFORM') con.name = "roll" con.target = self.obj con.subtarget = roll_fr con.map_from = 'ROTATION' con.map_to = 'ROTATION' con.from_min_z_rot = radians(0.0) con.from_max_z_rot = radians(60.0) con.to_min_z_rot = radians(0.0) con.to_max_z_rot = foot_vertical_rot con.target_space = 'LOCAL' con.owner_space = 'LOCAL' con = heel_fr_p.constraints.new('TRANSFORM') con.name = "roll" con.target = self.obj con.subtarget = roll_fr con.map_from = 'ROTATION' con.map_to = 'ROTATION' con.from_min_z_rot = radians(-60.0) con.from_max_z_rot = 0.0 con.to_min_z_rot = radians(-60.0) con.to_max_z_rot = 0.0 con.target_space = 'LOCAL' con.owner_space = 'LOCAL' con = toe_fr_p.constraints.new('TRANSFORM') con.name = "roll" con.target = self.obj con.subtarget = roll_fr con.map_from = 'ROTATION' con.map_to = 'ROTATION' con.from_min_z_rot = radians(60.0) con.from_max_z_rot = radians(90.0) con.to_min_z_rot = radians(0.0) con.to_max_z_rot = toe_vertical_rot con.target_space = 'LOCAL' con.owner_space = 'LOCAL' # Compensate foot for heel con = foot_fr_p.constraints.new('TRANSFORM') con.name = "roll_compensate" con.target = self.obj con.subtarget = roll_fr con.map_from = 'ROTATION' con.map_to = 'ROTATION' con.from_min_z_rot = radians(60.0) con.from_max_z_rot = radians(90.0) con.to_min_z_rot = radians(0.0) con.to_max_z_rot = -toe_vertical_rot con.target_space = 'LOCAL' con.owner_space = 'LOCAL' # Roll limits con = roll_fr_p.constraints.new('LIMIT_ROTATION') con.name = "limit rotation" con.use_limit_z = True con.min_z = radians(-60.0) con.max_z = radians(90.0) con.owner_space = 'LOCAL' # Edit IK to follow the rolled foot instead of ik control con = pb[flimb_ik].constraints["ik"] con.subtarget = foot_tgt con = pb[elimb_str].constraints["copy rotation"] con.subtarget = foot_tgt con = pb[toe_pos].constraints.new('COPY_ROTATION') con.name = "copy rotation" con.target = self.obj con.subtarget = toe_ik_ctl #con.invert_x = True con.target_space = 'POSE' con.owner_space = 'POSE' # Optional stretch to the foot if self.params.do_stretch: con1 = pb[flimb_str].constraints.new('STRETCH_TO') con1.name = "stretch to foot" con1.target = self.obj con1.subtarget = foot_tgt con1.volume = 'NO_VOLUME' con1.rest_length = pb[flimb_str].length con1.keep_axis = 'PLANE_Z' con2 = pb[elimb_str].constraints.new('COPY_LOCATION') con2.name = "copy foot location" con2.target = self.obj con2.subtarget = foot_tgt con2.target_space = 'POSE' con2.owner_space = 'POSE' # Set up custom properties prop = rna_idprop_ui_prop_get(pb[elimb_ik], "foot_stretch", create=True) pb[elimb_ik]["foot_stretch"] = 1 # int(self.foot_stretch) prop["soft_min"] = 0 prop["soft_max"] = 1 prop["min"] = 0 prop["max"] = 1 # Drivers for c in (con1, con2): driver = self.obj.driver_add(c.path_from_id("influence")) driver.driver.expression = 'foot_stretch' var_fs = driver.driver.variables.new() var_fs.type = 'SINGLE_PROP' var_fs.name = 'foot_stretch' var_fs.targets[0].id_type = 'OBJECT' var_fs.targets[0].id = self.obj var_fs.targets[0].data_path = ( pb[elimb_ik].path_from_id() + '["foot_stretch"]') for org, ctrl in zip( side_org_bones, [ulimb_str, flimb_str, elimb_str, toe_ik_ctl]): con = pb[org].constraints.new('COPY_TRANSFORMS') con.name = "copy_ik" con.target = self.obj con.subtarget = ctrl for org, ctrl in zip(side_org_bones, [ulimb_fk, flimb_fk, elimb_fk, toe_fk_ctl]): con = pb[org].constraints.new('COPY_TRANSFORMS') con.name = "copy_fk" con.target = self.obj con.subtarget = ctrl # Drivers driver = self.obj.driver_add(con.path_from_id("influence")) driver.driver.expression = 'fk' var_fk = driver.driver.variables.new() var_fk.type = 'SINGLE_PROP' var_fk.name = 'fk' var_fk.targets[0].id_type = 'OBJECT' var_fk.targets[0].id = self.obj var_fk.targets[ 0].data_path = 'pose.bones["{}"]["IK_FK"]'.format(elimb_ik) ui_script += UI_PANTIN_LIMB_SCRIPT % ( '"{}", "{}", "{}", "{}"'.format( ulimb_ik, joint_str, elimb_ik, toe_ik_ctl), '"{}", "{}", "{}", "{}"'.format( ulimb_fk, flimb_fk, elimb_fk, toe_fk_ctl)) if self.params.do_stretch: ui_script += """ layout.prop(pose_bones[ik_leg[2]], \ '["foot_stretch"]', \ text="Foot stretch (" + ik_leg[2] + ")", slider=True) """ return { 'script': [ui_script], 'imports': UI_IMPORTS, 'utilities': PANTIN_UTILS + [UTILITIES_PANTIN_LIMBS], 'register': PANTIN_REGISTER + REGISTER_PANTIN_LIMBS, 'register_props': REGISTER_PANTIN_PROPS, }
def generate(self): bpy.ops.object.mode_set(mode='EDIT') eb = self.obj.data.edit_bones # Create the control bones ulimb_fk_name = pantin_utils.strip_LR_numbers( strip_org(self.org_bones[0])) + '.FK' + self.side_suffix follow_name = pantin_utils.strip_LR_numbers( make_mechanism_name(strip_org( self.org_bones[0]))) + '.FK.follow' + self.side_suffix target = eb[self.org_bones[0]].parent_recursive[-1].name target = strip_org(target) ulimb_fk, ulimb_follow = pantin_utils.make_follow( self.obj, self.org_bones[0], target, ctrl_name=ulimb_fk_name, follow_name=follow_name) flimb_fk = copy_bone( self.obj, self.org_bones[1], pantin_utils.strip_LR_numbers(strip_org(self.org_bones[1])) + '.FK' + self.side_suffix) elimb_fk = copy_bone( self.obj, self.org_bones[2], pantin_utils.strip_LR_numbers(strip_org(self.org_bones[2])) + '.FK' + self.side_suffix) # Get edit bones ulimb_fk_e = eb[ulimb_fk] flimb_fk_e = eb[flimb_fk] elimb_fk_e = eb[elimb_fk] # Parenting # Side org chain for b, o_b in zip(self.side_org_bones[1:], self.org_bones[1:]): eb[b].parent = eb[ pantin_utils.strip_LR_numbers(eb[o_b].parent.name) + self.side_suffix] flimb_fk_e.parent = ulimb_fk_e elimb_fk_e.parent = flimb_fk_e # Object mode, get pose bones bpy.ops.object.mode_set(mode='OBJECT') pb = self.obj.pose.bones ulimb_fk_p = pb[ulimb_fk] flimb_fk_p = pb[flimb_fk] elimb_fk_p = pb[elimb_fk] # Set up custom properties prop = rna_idprop_ui_prop_get(ulimb_fk_p, "pelvis_follow", create=True) ulimb_fk_p["pelvis_follow"] = int(self.pelvis_follow) prop["soft_min"] = 0 prop["soft_max"] = 1 prop["min"] = 0 prop["max"] = 1 return [ulimb_fk, flimb_fk, elimb_fk]
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 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. """ 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_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 make_follow(obj, b, target, ctrl_name=None, follow_name=None): eb = obj.data.edit_bones # Control bone if ctrl_name is None: ctrl_name = strip_org(b) ctrl_bone = copy_bone(obj, b, ctrl_name) # Follow bone if follow_name is None: follow_name = make_mechanism_name(strip_org(b)) + ".follow" follow_bone = copy_bone(obj, b, follow_name) eb[follow_bone].tail = eb[follow_bone].head + Vector((0, 0, 0.1)) align_bone_z_axis(obj, follow_bone, Vector((0, 1, 0))) # Parenting bone_parent_name = eb[b].parent.name eb[ctrl_bone].use_connect = False eb[follow_bone].parent = eb[bone_parent_name] eb[ctrl_bone].use_connect = False eb[ctrl_bone].parent = eb[follow_bone] bpy.ops.object.mode_set(mode='OBJECT') pb = obj.pose.bones # Set up custom properties prop = rna_idprop_ui_prop_get(pb[ctrl_bone], "follow", create=True) pb[ctrl_bone]["follow"] = 1.0 prop["soft_min"] = 0.0 prop["soft_max"] = 1.0 prop["min"] = 0.0 prop["max"] = 1.0 # Get follow bone's parent chain parent_chain = pb[follow_bone].parent_recursive parent_chain = [strip_org(b.name) for b in parent_chain] parent_chain.reverse() for i_c, parent_name in enumerate(parent_chain): con = pb[follow_bone].constraints.new('COPY_ROTATION') con.name = 'follow_' + parent_name con.target = obj con.subtarget = parent_name con.use_offset = True con.use_x = True con.use_y = True con.use_z = True if i_c == len(parent_chain) - 1: con.invert_x = True con.invert_y = True con.invert_z = True con.invert_z = True con.target_space = 'LOCAL' con.owner_space = 'LOCAL' # TODO investigate strange behaviour with FLIP # Drivers driver = obj.driver_add(con.path_from_id("influence")) driver.driver.expression = '1-follow' var_pf = driver.driver.variables.new() var_pf.type = 'SINGLE_PROP' var_pf.name = 'follow' var_pf.targets[0].id_type = 'OBJECT' var_pf.targets[0].id = obj var_pf.targets[0].data_path = pb[ctrl_bone].path_from_id( ) + '["follow"]' bpy.ops.object.mode_set(mode='EDIT') return ctrl_bone, follow_bone
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_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): def parent_ctrl(eb, child, parent_to=None): """This tries to parent the child to a .L/.R bone.""" # Get parent if none supplied if parent_to is None and eb[child].parent is not None: parent_to = eb[child].parent.name print(parent_to) if parent_to + self.params.object_side in eb: eb[child].parent = (eb[parent_to + self.params.object_side]) elif parent_to in eb: eb[child].parent = eb[parent_to] elif 'MCH-Flip' in eb: eb[child].parent = eb['MCH-Flip'] else: raise Exception( "RIGIFY ERROR: Bone %s does not have a %s side" % (strip_org(eb[b].parent.name), side)) if self.params.use_parent_Z_index and self.org_parent is not None: # Get parent's Z indices bpy.ops.object.mode_set(mode='OBJECT') pb = self.obj.pose.bones def_parent_name = make_deformer_name(strip_org(self.org_parent)) if (self.params.object_side != ".C" and def_parent_name[-2:] not in ['.L', '.R']): def_parent_name += self.params.object_side if not def_parent_name in pb: raise Exception( "RIGIFY ERROR: Bone %s does not have a %s side" % (strip_org(self.org_parent), self.params.object_side)) parent_p = pb[def_parent_name] member_Z_index = parent_p['member_index'] bone_Z_index = 0 for b in pb: if b.bone.use_deform and b.name.startswith('DEF-'): if not 'member_index' in b: raise MetarigError( "RIGIFY ERROR: One rig bone with should not be connected. " "Check armature for connected bones.") if (b['member_index'] == member_Z_index and b['bone_index'] > bone_Z_index): bone_Z_index = b['bone_index'] bone_Z_index += 1 bpy.ops.object.mode_set(mode='EDIT') else: member_Z_index = self.params.member_Z_index bone_Z_index = self.params.first_bone_Z_index eb = self.obj.data.edit_bones ctrl_chain = [] mch_chain = [] # def_chain = [] # if self.params.duplicate_lr: # sides = ['.L', '.R'] # else: side = self.params.object_side if side == '.C': side = '' # IK control bone if self.params.chain_type == 'IK': last_bone = self.org_bones[-1] ctrl_bone = new_bone(self.obj, strip_org(last_bone) + ".ik" + side) ctrl_bone_e = eb[ctrl_bone] ctrl_bone_e.head = eb[last_bone].tail ctrl_bone_e.tail = eb[last_bone].tail + Vector((0.3, 0, 0)) align_bone_z_axis(self.obj, ctrl_bone, Vector((0, 1, 0))) ctrl_chain.append(ctrl_bone) # ctrl_bone_e.layers = layers for i, b in enumerate(self.org_bones): # Control bones if self.params.chain_type in {'Normal', 'Curve', 'Dynamic'}: if side in b: ctrl_bone_name = b else: ctrl_bone_name = b + side ctrl_bone_name = strip_org(ctrl_bone_name) ctrl_bone = copy_bone(self.obj, b, ctrl_bone_name) ctrl_bone_e = eb[ctrl_bone] ctrl_chain.append(ctrl_bone) if self.params.chain_type == 'Curve': ctrl_bone_e.use_connect = False if self.params.curve_parent_to_first: if i > 0: parent_ctrl(eb, ctrl_bone, parent_to=ctrl_chain[0]) else: parent_ctrl(eb, ctrl_bone, parent_to=self.org_parent) else: parent_ctrl(eb, ctrl_bone, parent_to=self.org_parent) ctrl_bone_e.tail = (ctrl_bone_e.head + Vector( (0, 0, 1)) * ctrl_bone_e.length) align_bone_z_axis(self.obj, ctrl_bone, Vector((0, 1, 0))) elif self.params.chain_type == 'Dynamic': # Create an empty object to use slow parent # What follows is quite dirty. # ctrl_bone_e.parent = eb[self.org_parent] parent_ctrl(eb, ctrl_bone) empty_name = self.obj.name + "_" + strip_org(b) + '.dyn' if empty_name in bpy.data.objects: empty_obj = bpy.data.objects[empty_name] else: empty_obj = bpy.data.objects.new(empty_name, None) if not empty_name in bpy.context.scene.objects: bpy.context.scene.objects.link(empty_obj) empty_obj.empty_draw_type = 'SPHERE' empty_obj.empty_draw_size = self.obj.data.bones[ b].length / 10 empty_obj.hide = True empty_obj.parent = self.obj empty_obj.parent_type = 'BONE' empty_obj.parent_bone = ctrl_bone empty_obj.matrix_local = Matrix() empty_obj.use_slow_parent = True empty_obj.slow_parent_offset = 1.0 # Mechanism bones if self.params.chain_type == 'Curve': stretch_bone = copy_bone( self.obj, b, make_mechanism_name(strip_org(b)) + '.stretch' + side) stretch_bone_e = eb[stretch_bone] stretch_bone_e.use_connect = False stretch_bone_e.parent = eb[ctrl_bone] mch_chain.append(stretch_bone) elif self.params.chain_type == 'IK': ik_bone = copy_bone( self.obj, b, make_mechanism_name(strip_org(b)) + '.ik' + side) ik_bone_e = eb[ik_bone] ik_bone_e.parent = eb[mch_chain[-1] if i > 0 else self. org_parent] mch_chain.append(ik_bone) elif self.params.chain_type == 'Dynamic': dyn_bone = copy_bone( self.obj, b, make_mechanism_name(strip_org(b)) + '.dyn' + side) dyn_bone_e = eb[dyn_bone] dyn_bone_e.parent = eb[ctrl_bone] mch_chain.append(dyn_bone) # Parenting # if self.params.chain_type == 'Normal': if (i == 0 and self.params.chain_type in ('Normal', 'Dynamic')): parent_ctrl(eb, ctrl_bone) # Def bones def_bone = pantin_utils.create_deformation(self.obj, b, member_Z_index, bone_Z_index + i, 0.0, b + side) if self.params.chain_type == 'Curve': # Curve end bone last_bone = self.org_bones[-1] ctrl_bone = new_bone(self.obj, strip_org(last_bone) + ".end" + side) ctrl_bone_e = eb[ctrl_bone] last_bone_e = eb[last_bone] ctrl_bone_e.use_connect = False if self.params.curve_parent_to_first: ctrl_bone_e.parent = eb[ctrl_chain[0]] else: parent_ctrl(eb, ctrl_bone, parent_to=self.org_parent) ctrl_bone_e.head = last_bone_e.tail ctrl_bone_e.tail = (ctrl_bone_e.head + (last_bone_e.tail - last_bone_e.head)) align_bone_z_axis(self.obj, ctrl_bone, Vector((0, 1, 0))) ctrl_chain.append(ctrl_bone) ctrl_bone_e.layers = last_bone_e.layers # ctrl_bone_e.layers = layers bpy.ops.object.mode_set(mode='OBJECT') pb = self.obj.pose.bones # Pose bone settings if self.params.chain_type in ('IK', 'Curve', 'Dynamic'): pbone = pb[ctrl_chain[-1]] pbone.rotation_mode = 'XZY' pbone.lock_location = (False, False, True) pbone.lock_rotation = (True, True, False) pbone.lock_rotation_w = False pbone.lock_scale = (False, False, False) if self.params.chain_type in ('IK', 'Curve', 'Dynamic'): # Widgets for ctrl_bone in ctrl_chain: global_scale = pb[ctrl_bone].length # self.obj.dimensions[2] # member_factor = 0.06 widget_size = global_scale * 0.3 # * member_factor pantin_utils.create_aligned_circle_widget(self.obj, ctrl_bone, radius=widget_size) # Constraints for org, mch in zip(self.org_bones, mch_chain): con = pb[org].constraints.new('COPY_TRANSFORMS') con.name = "copy_transforms" con.target = self.obj con.subtarget = mch else: # Widgets widget_size = 0.5 for bone in ctrl_chain: pantin_utils.create_capsule_widget(self.obj, bone, length=widget_size, width=widget_size * 0.1, head_tail=0.5, horizontal=False) # Constraints for org, ctrl in zip(self.org_bones, ctrl_chain): con = pb[org].constraints.new('COPY_TRANSFORMS') con.name = "copy_transforms" con.target = self.obj con.subtarget = ctrl ui_script = "" if self.params.chain_type == 'Curve': for ctrl, mch in zip(ctrl_chain[1:], mch_chain): con = pb[mch].constraints.new('STRETCH_TO') con.name = "stretch_to" con.target = self.obj con.subtarget = ctrl con.volume = 'NO_VOLUME' con.keep_axis = 'PLANE_Z' elif self.params.chain_type == 'IK': last_bone = mch_chain[-1] con = pb[last_bone].constraints.new('IK') con.target = self.obj con.subtarget = ctrl_bone con.chain_count = len(self.org_bones) # # Pelvis follow # if self.params.do_flip: # pantin_utils.create_ik_child_of( # self.obj, ctrl_bone, self.params.pelvis_name) elif self.params.chain_type == 'Dynamic': for ctrl, mch in zip(ctrl_chain, mch_chain): con = pb[mch].constraints.new('DAMPED_TRACK') con.name = "damped_track" con.target = empty_obj # con.volume = 'NO_VOLUME' # con.keep_axis = 'PLANE_Z' # con.rest_length = pb[ctrl].length ui_script = script % (ctrl, dyn_bone) # % ctrl_bone, MCH-bone.dyn elif self.params.chain_type == 'Def': # Modify constraints to add side suffix if side in ('.L', '.R'): for b in self.org_bones: for con in pb[b].constraints: if (hasattr(con, 'subtarget') and con.subtarget + side in pb): con.subtarget += side return { 'script': [ui_script], 'imports': UI_IMPORTS, 'utilities': PANTIN_UTILS, 'register': PANTIN_REGISTER, 'register_props': REGISTER_PANTIN_PROPS, }
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): bpy.ops.object.mode_set(mode='EDIT') ctrl_chain = [] eb = self.obj.data.edit_bones # Control bones # Global control ctrl_g = copy_bone(self.obj, self.mouth, strip_org(self.mouth)) ctrl_g_eb = eb[ctrl_g] ctrl_chain.append(ctrl_g) if self.org_parent is not None: ctrl_g_eb.use_connect = False ctrl_g_eb.parent = eb[self.org_parent] # Right control ctrl_r_name = strip_org(self.ur.split('_')[0] + '.R') ctrl_r = new_bone(self.obj, ctrl_r_name) eb[ctrl_r].head = eb[self.ur].head eb[ctrl_r].tail = eb[self.ur].head + Vector( (0, 0, 1)) * eb[self.ur].length # Left control ctrl_l_name = strip_org(self.ul.split('_')[0] + '.L') ctrl_l = new_bone(self.obj, ctrl_l_name) eb[ctrl_l].head = eb[self.ul].tail eb[ctrl_l].tail = eb[self.ul].tail + Vector( (0, 0, 1)) * eb[self.ul].length # Up control ctrl_uc_name = strip_org(self.uc) ctrl_uc = new_bone(self.obj, ctrl_uc_name) eb[ctrl_uc].head = (eb[self.uc].head + eb[self.uc].tail) / 2 eb[ctrl_uc].tail = eb[ctrl_uc].head + Vector( (0, 0, 1)) * eb[self.uc].length # Down control ctrl_lc_name = strip_org(self.lc) ctrl_lc = new_bone(self.obj, ctrl_lc_name) eb[ctrl_lc].head = (eb[self.lc].head + eb[self.lc].tail) / 2 eb[ctrl_lc].tail = eb[ctrl_lc].head + Vector( (0, 0, 1)) * eb[self.lc].length for b in [ctrl_r, ctrl_uc, ctrl_lc, ctrl_l]: align_bone_x_axis(self.obj, b, Vector((-1, 0, 0))) eb[b].layers = eb[self.lc].layers eb[b].parent = eb[self.mouth] ctrl_chain.append(b) bpy.ops.object.mode_set(mode='OBJECT') pb = self.obj.pose.bones for b in [ctrl_r, ctrl_uc, ctrl_lc, ctrl_l]: pb[b].lock_location = (False, False, True) pb[b].lock_rotation = (True, True, False) pb[b].lock_rotation_w = False pb[b].lock_scale = (False, False, False) pb[b].rotation_mode = 'XZY' bpy.ops.object.mode_set(mode='EDIT') eb = self.obj.data.edit_bones # Stretch # RIGHT stretch_r_chain = [] for bone in [self.ur, self.lr]: mch_b = copy_bone( self.obj, bone, pantin_utils.strip_LR(make_mechanism_name(strip_org(bone))) + '.stretch.R') mch_eb = eb[mch_b] mch_eb.parent = eb[ctrl_r] stretch_r_chain.append(mch_b) # CENTER stretch_c_chain = [] for bone in [self.uc, self.lc]: mch_b = copy_bone( self.obj, bone, pantin_utils.strip_LR(make_mechanism_name(strip_org(bone))) + '.stretch') mch_eb = eb[mch_b] mch_eb.use_connect = False mch_eb.parent = eb[strip_org(bone)] stretch_c_chain.append(mch_b) #LEFT stretch_l_chain = [] for i, bone in enumerate([self.ul, self.ll]): mch_b = copy_bone( self.obj, bone, pantin_utils.strip_LR(make_mechanism_name(strip_org(bone))) + '.stretch.L') mch_eb = eb[mch_b] mch_eb.parent = eb[stretch_c_chain[i]] stretch_l_chain.append(mch_b) # Def bones Z_index = self.params.Z_index for i, b in enumerate([ self.mouth, stretch_l_chain[1], stretch_r_chain[1], stretch_c_chain[1], stretch_l_chain[0], stretch_r_chain[0], stretch_c_chain[0], ]): def_bone_name = b.split('.')[0][4:] if b[-1] in ('L', 'R'): def_bone_name += '.' + b[-1] def_bone = pantin_utils.create_deformation(self.obj, b, member_index=Z_index, bone_index=i, new_name=def_bone_name) if b == stretch_c_chain[1]: pantin_utils.create_deformation( self.obj, b, member_index=Z_index, bone_index=i + 1, new_name=strip_org(self.org_bones[0]) + '_int') bpy.ops.object.mode_set(mode='OBJECT') pb = self.obj.pose.bones # Widgets wgt_radius = pb[ctrl_uc].length / 3 for b in [ctrl_r, ctrl_l, ctrl_uc, ctrl_lc]: pantin_utils.create_aligned_circle_widget(self.obj, b, radius=wgt_radius) pantin_utils.create_aligned_circle_widget(self.obj, ctrl_g, radius=pb[ctrl_g].length, head_tail=0.0, width_ratio=2.0) # Constraints for src_b, target_b in zip(stretch_r_chain, stretch_c_chain): mch_pb = pb[src_b] con = mch_pb.constraints.new('STRETCH_TO') con.name = "stretch to" con.target = self.obj con.subtarget = target_b con.volume = 'NO_VOLUME' con.rest_length = mch_pb.length con.keep_axis = 'PLANE_Z' for src_b in stretch_l_chain: mch_pb = pb[src_b] con = mch_pb.constraints.new('STRETCH_TO') con.name = "stretch to" con.target = self.obj con.subtarget = ctrl_l con.volume = 'NO_VOLUME' con.rest_length = mch_pb.length con.keep_axis = 'PLANE_Z' for org, ctrl in zip(self.org_bones, [ctrl_g] + stretch_r_chain + stretch_c_chain + stretch_l_chain): con = pb[org].constraints.new('COPY_TRANSFORMS') con.name = "copy_transforms" con.target = self.obj con.subtarget = ctrl return { 'imports': UI_IMPORTS, 'utilities': PANTIN_UTILS, 'register': PANTIN_REGISTER, 'register_props': REGISTER_PANTIN_PROPS, }