def create_widgets(self): bpy.ops.object.mode_set(mode='OBJECT') pose_bones = self.obj.pose.bones ctrl_chain = self.bones['ctrl'][strip_org(self.base_bone)] for i, bone in enumerate(ctrl_chain): if i != len(ctrl_chain) - 1: create_circle_widget(self.obj, bone, radius=0.5, head_tail=0.75, with_line=False) else: create_ballsocket_widget(self.obj, bone, size=0.7) for bone in self.bones['tweaks'][strip_org(self.base_bone)]: create_sphere_widget(self.obj, bone) pose_bones[ctrl_chain[-1]].custom_shape_transform = \ pose_bones[self.bones['tweaks'][strip_org(self.base_bone)][-1]] super().create_widgets()
def create_widgets(self): bpy.ops.object.mode_set(mode='OBJECT') # master_eye eye_ctrl = self.bones['eye_ctrl']['master_eye'] create_circle_widget(self.obj, eye_ctrl, head_tail=1.0) # eye target eye_target = self.bones['eye_ctrl']['eye_target'] create_eye_widget(self.obj, eye_target) # eye hook if 'eye_hook' in self.bones['eye_ctrl']: eye_target = self.bones['eye_ctrl']['eye_hook'] create_gear_widget(self.obj, eye_target, size=10.0) # top lid master if 'top_lid_master' in self.bones['eye_ctrl']: top_lid_master = self.bones['eye_ctrl']['top_lid_master'] create_cube_widget(self.obj, top_lid_master) # bottom lid master if 'bottom_lid_master' in self.bones['eye_ctrl']: bottom_lid_master = self.bones['eye_ctrl']['bottom_lid_master'] create_cube_widget(self.obj, bottom_lid_master) if 'common' in self.bones['eye_ctrl']: common_ctrl = self.bones['eye_ctrl']['common'] if self.is_clustered(): cluster = self.get_cluster_positions() create_widget_from_cluster(self.obj, common_ctrl, cluster) else: create_eyes_widget(self.obj, common_ctrl) super().create_widgets()
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. """ # 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 gen_control(self): """ Generate the control rig. """ #--------------------------------- # Create the hip and rib controls bpy.ops.object.mode_set(mode='EDIT') # Copy org bones hip_control = copy_bone(self.obj, self.org_bones[0], strip_org(self.org_bones[0])) rib_control = copy_bone(self.obj, self.org_bones[-1], strip_org(self.org_bones[-1])) rib_mch = copy_bone( self.obj, self.org_bones[-1], make_mechanism_name(strip_org(self.org_bones[-1] + ".follow"))) hinge = copy_bone( self.obj, self.org_bones[0], make_mechanism_name(strip_org(self.org_bones[-1]) + ".hinge")) eb = self.obj.data.edit_bones hip_control_e = eb[hip_control] rib_control_e = eb[rib_control] rib_mch_e = eb[rib_mch] hinge_e = eb[hinge] # Parenting hip_control_e.use_connect = False rib_control_e.use_connect = False rib_mch_e.use_connect = False hinge_e.use_connect = False hinge_e.parent = None rib_control_e.parent = hinge_e rib_mch_e.parent = rib_control_e # Position flip_bone(self.obj, hip_control) flip_bone(self.obj, hinge) hinge_e.length /= 2 rib_mch_e.length /= 2 put_bone(self.obj, rib_control, hip_control_e.head) put_bone(self.obj, rib_mch, hip_control_e.head) bpy.ops.object.mode_set(mode='POSE') bpy.ops.object.mode_set(mode='EDIT') eb = self.obj.data.edit_bones # Switch to object mode bpy.ops.object.mode_set(mode='OBJECT') pb = self.obj.pose.bones hip_control_p = pb[hip_control] rib_control_p = pb[rib_control] hinge_p = pb[hinge] # No translation on rib control rib_control_p.lock_location = [True, True, True] # Hip does not use local location hip_control_p.bone.use_local_location = False # Custom hinge property prop = rna_idprop_ui_prop_get(rib_control_p, "isolate", create=True) rib_control_p["isolate"] = 1.0 prop["soft_min"] = prop["min"] = 0.0 prop["soft_max"] = prop["max"] = 1.0 # Constraints con = hinge_p.constraints.new('COPY_LOCATION') con.name = "copy_location" con.target = self.obj con.subtarget = hip_control con1 = hinge_p.constraints.new('COPY_ROTATION') con1.name = "isolate_off.01" con1.target = self.obj con1.subtarget = hip_control con2 = rib_control_p.constraints.new('COPY_SCALE') con2.name = "isolate_off.02" con2.target = self.obj con2.subtarget = hip_control con2.use_offset = True con2.target_space = 'LOCAL' con2.owner_space = 'LOCAL' # Drivers for "isolate_off" fcurve = con1.driver_add("influence") driver = fcurve.driver var = driver.variables.new() driver.type = 'AVERAGE' var.name = "var" var.targets[0].id_type = 'OBJECT' var.targets[0].id = self.obj var.targets[0].data_path = rib_control_p.path_from_id() + '["isolate"]' mod = fcurve.modifiers[0] mod.poly_order = 1 mod.coefficients[0] = 1.0 mod.coefficients[1] = -1.0 fcurve = con2.driver_add("influence") driver = fcurve.driver var = driver.variables.new() driver.type = 'AVERAGE' var.name = "var" var.targets[0].id_type = 'OBJECT' var.targets[0].id = self.obj var.targets[0].data_path = rib_control_p.path_from_id() + '["isolate"]' mod = fcurve.modifiers[0] mod.poly_order = 1 mod.coefficients[0] = 1.0 mod.coefficients[1] = -1.0 # Appearence hip_control_p.custom_shape_transform = pb[self.org_bones[0]] rib_control_p.custom_shape_transform = pb[self.org_bones[-1]] #------------------------- # Create flex spine chain # Create bones/parenting/positiong bpy.ops.object.mode_set(mode='EDIT') flex_bones = [] flex_helpers = [] prev_bone = None for b in self.org_bones: # Create bones bone = copy_bone(self.obj, b, make_mechanism_name(strip_org(b) + ".flex")) helper = copy_bone(self.obj, rib_mch, make_mechanism_name(strip_org(b) + ".flex_h")) flex_bones += [bone] flex_helpers += [helper] eb = self.obj.data.edit_bones bone_e = eb[bone] helper_e = eb[helper] # Parenting bone_e.use_connect = False helper_e.use_connect = False if prev_bone == None: helper_e.parent = eb[hip_control] bone_e.parent = helper_e # Position put_bone(self.obj, helper, bone_e.head) helper_e.length /= 4 prev_bone = bone # Constraints bpy.ops.object.mode_set(mode='OBJECT') pb = self.obj.pose.bones rib_control_p = pb[rib_control] rib_mch_p = pb[rib_mch] inc = 1.0 / (len(flex_helpers) - 1) inf = 1.0 / (len(flex_helpers) - 1) for b in zip(flex_helpers[1:], flex_bones[:-1], self.org_bones[1:]): bone_p = pb[b[0]] # Scale constraints con = bone_p.constraints.new('COPY_SCALE') con.name = "copy_scale1" con.target = self.obj con.subtarget = flex_helpers[0] con.influence = 1.0 con = bone_p.constraints.new('COPY_SCALE') con.name = "copy_scale2" con.target = self.obj con.subtarget = rib_mch con.influence = inf # Bend constraints con = bone_p.constraints.new('COPY_ROTATION') con.name = "bend1" con.target = self.obj con.subtarget = flex_helpers[0] con.influence = 1.0 con = bone_p.constraints.new('COPY_ROTATION') con.name = "bend2" con.target = self.obj con.subtarget = rib_mch con.influence = inf # If not the rib control if b[0] != flex_helpers[-1]: # Custom bend property prop_name = "bend_" + strip_org(b[2]) prop = rna_idprop_ui_prop_get(rib_control_p, prop_name, create=True) rib_control_p[prop_name] = inf prop["min"] = 0.0 prop["max"] = 1.0 prop["soft_min"] = 0.0 prop["soft_max"] = 1.0 # Bend driver fcurve = con.driver_add("influence") driver = fcurve.driver var = driver.variables.new() driver.type = 'AVERAGE' var.name = prop_name var.targets[0].id_type = 'OBJECT' var.targets[0].id = self.obj var.targets[0].data_path = rib_control_p.path_from_id( ) + '["' + prop_name + '"]' # Location constraint con = bone_p.constraints.new('COPY_LOCATION') con.name = "copy_location" con.target = self.obj con.subtarget = b[1] con.head_tail = 1.0 inf += inc #---------------------------- # Create reverse spine chain # Create bones/parenting/positioning bpy.ops.object.mode_set(mode='EDIT') rev_bones = [] prev_bone = None for b in zip(flex_bones, self.org_bones): # Create bones bone = copy_bone(self.obj, b[1], make_mechanism_name(strip_org(b[1]) + ".reverse")) rev_bones += [bone] eb = self.obj.data.edit_bones bone_e = eb[bone] # Parenting bone_e.use_connect = False bone_e.parent = eb[b[0]] # Position flip_bone(self.obj, bone) bone_e.tail = Vector(eb[b[0]].head) #bone_e.head = Vector(eb[b[0]].tail) if prev_bone == None: pass # Position base bone wherever you want, for now do nothing (i.e. position at hips) else: put_bone(self.obj, bone, eb[prev_bone].tail) prev_bone = bone # Constraints bpy.ops.object.mode_set(mode='OBJECT') pb = self.obj.pose.bones prev_bone = None for bone in rev_bones: bone_p = pb[bone] con = bone_p.constraints.new('COPY_LOCATION') con.name = "copy_location" con.target = self.obj if prev_bone == None: con.subtarget = hip_control # Position base bone wherever you want, for now hips else: con.subtarget = prev_bone con.head_tail = 1.0 prev_bone = bone #--------------------------------------------- # Constrain org bones to flex bone's rotation pb = self.obj.pose.bones for b in zip(self.org_bones, flex_bones): con = pb[b[0]].constraints.new('COPY_TRANSFORMS') con.name = "copy_rotation" con.target = self.obj con.subtarget = b[1] #--------------------------- # Create pivot slide system pb = self.obj.pose.bones bone_p = pb[self.org_bones[0]] rib_control_p = pb[rib_control] # Custom pivot_slide property prop = rna_idprop_ui_prop_get(rib_control_p, "pivot_slide", create=True) rib_control_p["pivot_slide"] = 1.0 / len(self.org_bones) prop["min"] = 0.0 prop["max"] = 1.0 prop["soft_min"] = 1.0 / len(self.org_bones) prop["soft_max"] = 1.0 - (1.0 / len(self.org_bones)) # Anchor constraint con = bone_p.constraints.new('COPY_LOCATION') con.name = "copy_location" con.target = self.obj con.subtarget = rev_bones[0] # Slide constraints i = 1 tot = len(rev_bones) for rb in rev_bones: con = bone_p.constraints.new('COPY_LOCATION') con.name = "slide." + str(i) con.target = self.obj con.subtarget = rb con.head_tail = 1.0 # Driver fcurve = con.driver_add("influence") driver = fcurve.driver var = driver.variables.new() driver.type = 'AVERAGE' var.name = "slide" var.targets[0].id_type = 'OBJECT' var.targets[0].id = self.obj var.targets[0].data_path = rib_control_p.path_from_id( ) + '["pivot_slide"]' mod = fcurve.modifiers[0] mod.poly_order = 1 mod.coefficients[0] = 1 - i mod.coefficients[1] = tot i += 1 # Create control widgets w1 = create_circle_widget(self.obj, hip_control, radius=1.0, head_tail=1.0) w2 = create_circle_widget(self.obj, rib_control, radius=1.0, head_tail=0.0) if w1 != None: obj_to_bone(w1, self.obj, self.org_bones[0]) if w2 != None: obj_to_bone(w2, self.obj, self.org_bones[-1]) # Return control names return hip_control, rib_control
def gen_control(self): """ Generate the control rig. """ #--------------------------------- # Create the neck and head controls bpy.ops.object.mode_set(mode='EDIT') # Create bones neck_ctrl = copy_bone(self.obj, self.org_bones[0], strip_org(self.org_bones[0])) neck_follow = copy_bone(self.obj, self.org_bones[-1], make_mechanism_name(strip_org(self.org_bones[0] + ".follow"))) neck_child = new_bone(self.obj, make_mechanism_name(strip_org(self.org_bones[0] + ".child"))) head_ctrl = copy_bone(self.obj, self.org_bones[-1], strip_org(self.org_bones[-1])) head_mch = new_bone(self.obj, make_mechanism_name(strip_org(self.org_bones[-1]))) if self.isolate: head_socket1 = copy_bone(self.obj, self.org_bones[-1], make_mechanism_name(strip_org(self.org_bones[-1] + ".socket1"))) head_socket2 = copy_bone(self.obj, self.org_bones[-1], make_mechanism_name(strip_org(self.org_bones[-1] + ".socket2"))) # Create neck chain bones neck = [] helpers = [] for name in self.org_bones: neck += [copy_bone(self.obj, name, make_mechanism_name(strip_org(name)))] helpers += [copy_bone(self.obj, neck_child, make_mechanism_name(strip_org(name + ".02")))] # Fetch edit bones eb = self.obj.data.edit_bones neck_ctrl_e = eb[neck_ctrl] neck_follow_e = eb[neck_follow] neck_child_e = eb[neck_child] head_ctrl_e = eb[head_ctrl] head_mch_e = eb[head_mch] if self.isolate: head_socket1_e = eb[head_socket1] head_socket2_e = eb[head_socket2] # Parenting head_ctrl_e.use_connect = False head_ctrl_e.parent = neck_ctrl_e.parent head_mch_e.use_connect = False head_mch_e.parent = head_ctrl_e if self.isolate: head_socket1_e.use_connect = False head_socket1_e.parent = neck_ctrl_e.parent head_socket2_e.use_connect = False head_socket2_e.parent = None head_ctrl_e.parent = head_socket2_e for (name1, name2) in zip(neck, helpers): eb[name1].use_connect = False eb[name1].parent = eb[name2] eb[name2].use_connect = False eb[name2].parent = neck_ctrl_e.parent neck_follow_e.use_connect = False neck_follow_e.parent = neck_ctrl_e.parent neck_child_e.use_connect = False neck_child_e.parent = neck_ctrl_e neck_ctrl_e.parent = neck_follow_e # Position put_bone(self.obj, neck_follow, neck_ctrl_e.head) put_bone(self.obj, neck_child, neck_ctrl_e.head) put_bone(self.obj, head_ctrl, neck_ctrl_e.head) put_bone(self.obj, head_mch, neck_ctrl_e.head) head_mch_e.length = head_ctrl_e.length / 2 neck_child_e.length = neck_ctrl_e.length / 2 if self.isolate: put_bone(self.obj, head_socket1, neck_ctrl_e.head) head_mch_e.length /= 2 put_bone(self.obj, head_socket2, neck_ctrl_e.head) head_mch_e.length /= 3 for (name1, name2) in zip(neck, helpers): put_bone(self.obj, name2, eb[name1].head) eb[name2].length = eb[name1].length / 2 # Switch to object mode bpy.ops.object.mode_set(mode='OBJECT') pb = self.obj.pose.bones neck_ctrl_p = pb[neck_ctrl] neck_follow_p = pb[neck_follow] # neck_child_p = pb[neck_child] # UNUSED head_ctrl_p = pb[head_ctrl] if self.isolate: # head_socket1_p = pb[head_socket1] # UNUSED head_socket2_p = pb[head_socket2] # Custom bone appearance neck_ctrl_p.custom_shape_transform = pb[self.org_bones[(len(self.org_bones) - 1) // 2]] head_ctrl_p.custom_shape_transform = pb[self.org_bones[-1]] # Custom properties prop = rna_idprop_ui_prop_get(head_ctrl_p, "inf_extent", create=True) head_ctrl_p["inf_extent"] = 0.5 prop["min"] = 0.0 prop["max"] = 1.0 prop["soft_min"] = 0.0 prop["soft_max"] = 1.0 prop = rna_idprop_ui_prop_get(head_ctrl_p, "neck_follow", create=True) head_ctrl_p["neck_follow"] = 1.0 prop["min"] = 0.0 prop["max"] = 2.0 prop["soft_min"] = 0.0 prop["soft_max"] = 1.0 if self.isolate: prop = rna_idprop_ui_prop_get(head_ctrl_p, "isolate", create=True) head_ctrl_p["isolate"] = 0.0 prop["min"] = 0.0 prop["max"] = 1.0 prop["soft_min"] = 0.0 prop["soft_max"] = 1.0 # Constraints # Neck follow con = neck_follow_p.constraints.new('COPY_ROTATION') con.name = "copy_rotation" con.target = self.obj con.subtarget = head_ctrl fcurve = con.driver_add("influence") driver = fcurve.driver var = driver.variables.new() driver.type = 'SCRIPTED' var.name = "follow" var.targets[0].id_type = 'OBJECT' var.targets[0].id = self.obj var.targets[0].data_path = head_ctrl_p.path_from_id() + '["neck_follow"]' driver.expression = "follow / 2" # Isolate if self.isolate: con = head_socket2_p.constraints.new('COPY_LOCATION') con.name = "copy_location" con.target = self.obj con.subtarget = head_socket1 con = head_socket2_p.constraints.new('COPY_TRANSFORMS') con.name = "copy_transforms" con.target = self.obj con.subtarget = head_socket1 fcurve = con.driver_add("influence") driver = fcurve.driver var = driver.variables.new() driver.type = 'SCRIPTED' var.name = "isolate" var.targets[0].id_type = 'OBJECT' var.targets[0].id = self.obj var.targets[0].data_path = head_ctrl_p.path_from_id() + '["isolate"]' driver.expression = "1.0 - isolate" # Neck chain first = True prev = None i = 0 l = len(neck) for (name1, name2, org_name) in zip(neck, helpers, self.org_bones): con = pb[org_name].constraints.new('COPY_TRANSFORMS') con.name = "copy_transforms" con.target = self.obj con.subtarget = name1 n_con = pb[name2].constraints.new('COPY_TRANSFORMS') n_con.name = "neck" n_con.target = self.obj n_con.subtarget = neck_child h_con = pb[name2].constraints.new('COPY_TRANSFORMS') h_con.name = "head" h_con.target = self.obj h_con.subtarget = head_mch con = pb[name2].constraints.new('COPY_LOCATION') con.name = "anchor" con.target = self.obj if first: con.subtarget = neck_ctrl else: con.subtarget = prev con.head_tail = 1.0 # Drivers n = (i + 1) / l # Neck influence fcurve = n_con.driver_add("influence") driver = fcurve.driver var = driver.variables.new() driver.type = 'SCRIPTED' var.name = "ext" var.targets[0].id_type = 'OBJECT' var.targets[0].id = self.obj var.targets[0].data_path = head_ctrl_p.path_from_id() + '["inf_extent"]' driver.expression = "1.0 if (%.4f > (1.0-ext) or (1.0-ext) == 0.0) else (%.4f / (1.0-ext))" % (n, n) # Head influence if (i + 1) == l: h_con.influence = 1.0 else: fcurve = h_con.driver_add("influence") driver = fcurve.driver var = driver.variables.new() driver.type = 'SCRIPTED' var.name = "ext" var.targets[0].id_type = 'OBJECT' var.targets[0].id = self.obj var.targets[0].data_path = head_ctrl_p.path_from_id() + '["inf_extent"]' driver.expression = "0.0 if (%.4f <= (1.0-ext)) else ((%.4f - (1.0-ext)) / ext)" % (n, n) first = False prev = name1 i += 1 # Create control widgets w1 = create_circle_widget(self.obj, neck_ctrl, radius=1.0, head_tail=0.5) w2 = create_circle_widget(self.obj, head_ctrl, radius=1.0, head_tail=0.5) if w1 != None: obj_to_bone(w1, self.obj, self.org_bones[(len(self.org_bones) - 1) // 2]) if w2 != None: obj_to_bone(w2, self.obj, self.org_bones[-1]) # Return control bones return (head_ctrl, neck_ctrl)
def gen_control(self): """ Generate the control rig. """ bpy.ops.object.mode_set(mode='EDIT') eb = self.obj.data.edit_bones #------------------------- # Get rest slide position a = self.pivot_rest * len(self.org_bones) i = floor(a) a -= i if i == len(self.org_bones): i -= 1 a = 1.0 pivot_rest_pos = eb[self.org_bones[i]].head.copy() pivot_rest_pos += eb[self.org_bones[i]].vector * a #---------------------- # Create controls # Create control bones controls = [] for i in self.control_indices: name = copy_bone(self.obj, self.org_bones[i], strip_org(self.org_bones[i])) controls += [name] # Create control parents control_parents = [] for i in self.control_indices[1:-1]: name = new_bone(self.obj, make_mechanism_name("par_" + strip_org(self.org_bones[i]))) control_parents += [name] # Create sub-control bones subcontrols = [] for i in self.control_indices: name = new_bone(self.obj, make_mechanism_name("sub_" + strip_org(self.org_bones[i]))) subcontrols += [name] # Create main control bone main_control = new_bone(self.obj, self.params.spine_main_control_name) # Create main control WGT bones main_wgt1 = new_bone(self.obj, make_mechanism_name(self.params.spine_main_control_name + ".01")) main_wgt2 = new_bone(self.obj, make_mechanism_name(self.params.spine_main_control_name + ".02")) eb = self.obj.data.edit_bones # Parent the main control eb[main_control].use_connect = False eb[main_control].parent = eb[self.org_bones[0]].parent # Parent the main WGTs eb[main_wgt1].use_connect = False eb[main_wgt1].parent = eb[main_control] eb[main_wgt2].use_connect = False eb[main_wgt2].parent = eb[main_wgt1] # Parent the controls and sub-controls for name, subname in zip(controls, subcontrols): eb[name].use_connect = False eb[name].parent = eb[main_control] eb[subname].use_connect = False eb[subname].parent = eb[name] # Parent the control parents for name, par_name in zip(controls[1:-1], control_parents): eb[par_name].use_connect = False eb[par_name].parent = eb[main_control] eb[name].parent = eb[par_name] # Position the main bone put_bone(self.obj, main_control, pivot_rest_pos) eb[main_control].length = sum([eb[b].length for b in self.org_bones]) / 2 # Position the main WGTs eb[main_wgt1].tail = (0.0, 0.0, sum([eb[b].length for b in self.org_bones]) / 4) eb[main_wgt2].length = sum([eb[b].length for b in self.org_bones]) / 4 put_bone(self.obj, main_wgt1, pivot_rest_pos) put_bone(self.obj, main_wgt2, pivot_rest_pos) # Position the controls and sub-controls pos = eb[controls[0]].head.copy() for name, subname in zip(controls, subcontrols): put_bone(self.obj, name, pivot_rest_pos) put_bone(self.obj, subname, pivot_rest_pos) eb[subname].length = eb[name].length / 3 # Position the control parents for name, par_name in zip(controls[1:-1], control_parents): put_bone(self.obj, par_name, pivot_rest_pos) eb[par_name].length = eb[name].length / 2 #----------------------------------------- # Control bone constraints and properties bpy.ops.object.mode_set(mode='OBJECT') pb = self.obj.pose.bones # Lock control locations for name in controls: bone = pb[name] bone.lock_location = True, True, True # Main control doesn't use local location pb[main_control].bone.use_local_location = False # Intermediate controls follow hips and spine for name, par_name, i in zip(controls[1:-1], control_parents, self.control_indices[1:-1]): bone = pb[par_name] # Custom bend_alpha property prop = rna_idprop_ui_prop_get(pb[name], "bend_alpha", create=True) pb[name]["bend_alpha"] = i / (len(self.org_bones) - 1) # set bend alpha prop["min"] = 0.0 prop["max"] = 1.0 prop["soft_min"] = 0.0 prop["soft_max"] = 1.0 # Custom auto_rotate prop = rna_idprop_ui_prop_get(pb[name], "auto_rotate", create=True) pb[name]["auto_rotate"] = 1.0 prop["min"] = 0.0 prop["max"] = 1.0 prop["soft_min"] = 0.0 prop["soft_max"] = 1.0 # Constraints con1 = bone.constraints.new('COPY_TRANSFORMS') con1.name = "copy_transforms" con1.target = self.obj con1.subtarget = subcontrols[0] con2 = bone.constraints.new('COPY_TRANSFORMS') con2.name = "copy_transforms" con2.target = self.obj con2.subtarget = subcontrols[-1] # Drivers fcurve = con1.driver_add("influence") driver = fcurve.driver driver.type = 'AVERAGE' var = driver.variables.new() var.name = "auto" var.targets[0].id_type = 'OBJECT' var.targets[0].id = self.obj var.targets[0].data_path = pb[name].path_from_id() + '["auto_rotate"]' fcurve = con2.driver_add("influence") driver = fcurve.driver driver.type = 'SCRIPTED' driver.expression = "alpha * auto" var = driver.variables.new() var.name = "alpha" var.targets[0].id_type = 'OBJECT' var.targets[0].id = self.obj var.targets[0].data_path = pb[name].path_from_id() + '["bend_alpha"]' var = driver.variables.new() var.name = "auto" var.targets[0].id_type = 'OBJECT' var.targets[0].id = self.obj var.targets[0].data_path = pb[name].path_from_id() + '["auto_rotate"]' #------------------------- # Create flex spine chain bpy.ops.object.mode_set(mode='EDIT') flex_bones = [] flex_subs = [] prev_bone = None for b in self.org_bones: # Create bones bone = copy_bone(self.obj, b, make_mechanism_name(strip_org(b) + ".flex")) sub = new_bone(self.obj, make_mechanism_name(strip_org(b) + ".flex_s")) flex_bones += [bone] flex_subs += [sub] eb = self.obj.data.edit_bones bone_e = eb[bone] sub_e = eb[sub] # Parenting bone_e.use_connect = False sub_e.use_connect = False if prev_bone is None: sub_e.parent = eb[controls[0]] else: sub_e.parent = eb[prev_bone] bone_e.parent = sub_e # Position put_bone(self.obj, sub, bone_e.head) sub_e.length = bone_e.length / 4 if prev_bone is not None: sub_e.use_connect = True prev_bone = bone #---------------------------- # Create reverse spine chain # Create bones/parenting/positioning bpy.ops.object.mode_set(mode='EDIT') rev_bones = [] prev_bone = None for b in zip(flex_bones, self.org_bones): # Create bones bone = copy_bone(self.obj, b[1], make_mechanism_name(strip_org(b[1]) + ".reverse")) rev_bones += [bone] eb = self.obj.data.edit_bones bone_e = eb[bone] # Parenting bone_e.use_connect = False bone_e.parent = eb[b[0]] # Position flip_bone(self.obj, bone) bone_e.tail = Vector(eb[b[0]].head) #bone_e.head = Vector(eb[b[0]].tail) if prev_bone is None: put_bone(self.obj, bone, pivot_rest_pos) else: put_bone(self.obj, bone, eb[prev_bone].tail) prev_bone = bone # Constraints bpy.ops.object.mode_set(mode='OBJECT') pb = self.obj.pose.bones prev_bone = None for bone in rev_bones: bone_p = pb[bone] con = bone_p.constraints.new('COPY_LOCATION') con.name = "copy_location" con.target = self.obj if prev_bone is None: con.subtarget = main_control else: con.subtarget = prev_bone con.head_tail = 1.0 prev_bone = bone #---------------------------------------- # Constrain original bones to flex spine bpy.ops.object.mode_set(mode='OBJECT') pb = self.obj.pose.bones for obone, fbone in zip(self.org_bones, flex_bones): con = pb[obone].constraints.new('COPY_TRANSFORMS') con.name = "copy_transforms" con.target = self.obj con.subtarget = fbone #--------------------------- # Create pivot slide system pb = self.obj.pose.bones bone_p = pb[self.org_bones[0]] main_control_p = pb[main_control] # Custom pivot_slide property prop = rna_idprop_ui_prop_get(main_control_p, "pivot_slide", create=True) main_control_p["pivot_slide"] = self.pivot_rest prop["min"] = 0.0 prop["max"] = 1.0 prop["soft_min"] = 1.0 / len(self.org_bones) prop["soft_max"] = 1.0 - (1.0 / len(self.org_bones)) # Anchor constraints con = bone_p.constraints.new('COPY_LOCATION') con.name = "copy_location" con.target = self.obj con.subtarget = rev_bones[0] con = pb[main_wgt1].constraints.new('COPY_ROTATION') con.name = "copy_rotation" con.target = self.obj con.subtarget = rev_bones[0] # Slide constraints i = 1 tot = len(rev_bones) for rb in rev_bones: con = bone_p.constraints.new('COPY_LOCATION') con.name = "slide." + str(i) con.target = self.obj con.subtarget = rb con.head_tail = 1.0 # Driver fcurve = con.driver_add("influence") driver = fcurve.driver var = driver.variables.new() driver.type = 'AVERAGE' var.name = "slide" var.targets[0].id_type = 'OBJECT' var.targets[0].id = self.obj var.targets[0].data_path = main_control_p.path_from_id() + '["pivot_slide"]' mod = fcurve.modifiers[0] mod.poly_order = 1 mod.coefficients[0] = 1 - i mod.coefficients[1] = tot # Main WGT con = pb[main_wgt1].constraints.new('COPY_ROTATION') con.name = "slide." + str(i) con.target = self.obj con.subtarget = rb # Driver fcurve = con.driver_add("influence") driver = fcurve.driver var = driver.variables.new() driver.type = 'AVERAGE' var.name = "slide" var.targets[0].id_type = 'OBJECT' var.targets[0].id = self.obj var.targets[0].data_path = main_control_p.path_from_id() + '["pivot_slide"]' mod = fcurve.modifiers[0] mod.poly_order = 1 mod.coefficients[0] = 1.5 - i mod.coefficients[1] = tot i += 1 #---------------------------------- # Constrain flex spine to controls bpy.ops.object.mode_set(mode='OBJECT') pb = self.obj.pose.bones # Constrain the bones that correspond exactly to the controls for i, name in zip(self.control_indices, subcontrols): con = pb[flex_subs[i]].constraints.new('COPY_TRANSFORMS') con.name = "copy_transforms" con.target = self.obj con.subtarget = name # Constrain the bones in-between the controls for i, j, name1, name2 in zip(self.control_indices, self.control_indices[1:], subcontrols, subcontrols[1:]): if (i + 1) < j: for n in range(i + 1, j): bone = pb[flex_subs[n]] # Custom bend_alpha property prop = rna_idprop_ui_prop_get(bone, "bend_alpha", create=True) bone["bend_alpha"] = (n - i) / (j - i) # set bend alpha prop["min"] = 0.0 prop["max"] = 1.0 prop["soft_min"] = 0.0 prop["soft_max"] = 1.0 con = bone.constraints.new('COPY_TRANSFORMS') con.name = "copy_transforms" con.target = self.obj con.subtarget = name1 con = bone.constraints.new('COPY_TRANSFORMS') con.name = "copy_transforms" con.target = self.obj con.subtarget = name2 # Driver fcurve = con.driver_add("influence") driver = fcurve.driver var = driver.variables.new() driver.type = 'AVERAGE' var.name = "alpha" var.targets[0].id_type = 'OBJECT' var.targets[0].id = self.obj var.targets[0].data_path = bone.path_from_id() + '["bend_alpha"]' #------------- # Final stuff bpy.ops.object.mode_set(mode='OBJECT') pb = self.obj.pose.bones # Control appearance # Main pb[main_control].custom_shape_transform = pb[main_wgt2] w = create_compass_widget(self.obj, main_control) if w != None: obj_to_bone(w, self.obj, main_wgt2) # Spines for name, i in zip(controls[1:-1], self.control_indices[1:-1]): pb[name].custom_shape_transform = pb[self.org_bones[i]] # Create control widgets w = create_circle_widget(self.obj, name, radius=1.0, head_tail=0.5, with_line=True) if w != None: obj_to_bone(w, self.obj, self.org_bones[i]) # Hips pb[controls[0]].custom_shape_transform = pb[self.org_bones[0]] # Create control widgets w = create_circle_widget(self.obj, controls[0], radius=1.0, head_tail=0.5, with_line=True) if w != None: obj_to_bone(w, self.obj, self.org_bones[0]) # Ribs pb[controls[-1]].custom_shape_transform = pb[self.org_bones[-1]] # Create control widgets w = create_circle_widget(self.obj, controls[-1], radius=1.0, head_tail=0.5, with_line=True) if w != None: obj_to_bone(w, self.obj, self.org_bones[-1]) # Layers pb[main_control].bone.layers = pb[self.org_bones[0]].bone.layers return [main_control] + controls
def generate(self): """ Generate the rig. Do NOT modify any of the original bones, except for adding constraints. The main armature should be selected and active before this is called. """ bpy.ops.object.mode_set(mode='EDIT') make_rocker = False if self.org_bones[5] is not None: make_rocker = True # Create the bones thigh = copy_bone(self.obj, self.org_bones[0], make_mechanism_name(strip_org(insert_before_lr(self.org_bones[0], "_ik")))) shin = copy_bone(self.obj, self.org_bones[1], make_mechanism_name(strip_org(insert_before_lr(self.org_bones[1], "_ik")))) foot = copy_bone(self.obj, self.org_bones[2], strip_org(insert_before_lr(self.org_bones[2], "_ik"))) foot_ik_target = copy_bone(self.obj, self.org_bones[2], make_mechanism_name(strip_org(insert_before_lr(self.org_bones[2], "_ik_target")))) pole = copy_bone(self.obj, self.org_bones[0], strip_org(insert_before_lr(self.org_bones[0], "_pole"))) toe = copy_bone(self.obj, self.org_bones[3], strip_org(self.org_bones[3])) toe_parent = copy_bone(self.obj, self.org_bones[2], make_mechanism_name(strip_org(self.org_bones[3] + ".parent"))) toe_parent_socket1 = copy_bone(self.obj, self.org_bones[2], make_mechanism_name(strip_org(self.org_bones[3] + ".socket1"))) toe_parent_socket2 = copy_bone(self.obj, self.org_bones[2], make_mechanism_name(strip_org(self.org_bones[3] + ".socket2"))) foot_roll = copy_bone(self.obj, self.org_bones[4], strip_org(insert_before_lr(self.org_bones[2], "_roll"))) roll1 = copy_bone(self.obj, self.org_bones[4], make_mechanism_name(strip_org(self.org_bones[2] + ".roll.01"))) roll2 = copy_bone(self.obj, self.org_bones[4], make_mechanism_name(strip_org(self.org_bones[2] + ".roll.02"))) if make_rocker: rocker1 = copy_bone(self.obj, self.org_bones[5], make_mechanism_name(strip_org(self.org_bones[2] + ".rocker.01"))) rocker2 = copy_bone(self.obj, self.org_bones[5], make_mechanism_name(strip_org(self.org_bones[2] + ".rocker.02"))) visfoot = copy_bone(self.obj, self.org_bones[2], "VIS-" + strip_org(insert_before_lr(self.org_bones[2], "_ik"))) vispole = copy_bone(self.obj, self.org_bones[1], "VIS-" + strip_org(insert_before_lr(self.org_bones[0], "_pole"))) # Get edit bones eb = self.obj.data.edit_bones org_foot_e = eb[self.org_bones[2]] thigh_e = eb[thigh] shin_e = eb[shin] foot_e = eb[foot] foot_ik_target_e = eb[foot_ik_target] pole_e = eb[pole] toe_e = eb[toe] toe_parent_e = eb[toe_parent] toe_parent_socket1_e = eb[toe_parent_socket1] toe_parent_socket2_e = eb[toe_parent_socket2] foot_roll_e = eb[foot_roll] roll1_e = eb[roll1] roll2_e = eb[roll2] if make_rocker: rocker1_e = eb[rocker1] rocker2_e = eb[rocker2] visfoot_e = eb[visfoot] vispole_e = eb[vispole] # Parenting shin_e.parent = thigh_e foot_e.use_connect = False foot_e.parent = None foot_ik_target_e.use_connect = False foot_ik_target_e.parent = roll2_e pole_e.use_connect = False pole_e.parent = foot_e toe_e.parent = toe_parent_e toe_parent_e.use_connect = False toe_parent_e.parent = toe_parent_socket1_e toe_parent_socket1_e.use_connect = False toe_parent_socket1_e.parent = roll1_e toe_parent_socket2_e.use_connect = False toe_parent_socket2_e.parent = eb[self.org_bones[2]] foot_roll_e.use_connect = False foot_roll_e.parent = foot_e roll1_e.use_connect = False roll1_e.parent = foot_e roll2_e.use_connect = False roll2_e.parent = roll1_e visfoot_e.use_connect = False visfoot_e.parent = None vispole_e.use_connect = False vispole_e.parent = None if make_rocker: rocker1_e.use_connect = False rocker2_e.use_connect = False roll1_e.parent = rocker2_e rocker2_e.parent = rocker1_e rocker1_e.parent = foot_e # Misc foot_e.use_local_location = False visfoot_e.hide_select = True vispole_e.hide_select = True # Positioning vec = Vector(toe_e.vector) vec.normalize() foot_e.tail = foot_e.head + (vec * foot_e.length) foot_e.roll = toe_e.roll v1 = shin_e.tail - thigh_e.head if 'X' in self.primary_rotation_axis or 'Y' in self.primary_rotation_axis: v2 = v1.cross(shin_e.x_axis) if (v2 * shin_e.z_axis) > 0.0: v2 *= -1.0 else: v2 = v1.cross(shin_e.z_axis) if (v2 * shin_e.x_axis) < 0.0: v2 *= -1.0 v2.normalize() v2 *= v1.length if '-' in self.primary_rotation_axis: v2 *= -1 pole_e.head = shin_e.head + v2 pole_e.tail = pole_e.head + (Vector((0, 1, 0)) * (v1.length / 8)) pole_e.roll = 0.0 flip_bone(self.obj, toe_parent_socket1) flip_bone(self.obj, toe_parent_socket2) toe_parent_socket1_e.head = Vector(org_foot_e.tail) toe_parent_socket2_e.head = Vector(org_foot_e.tail) toe_parent_socket1_e.tail = Vector(org_foot_e.tail) + (Vector((0, 0, 1)) * foot_e.length / 2) toe_parent_socket2_e.tail = Vector(org_foot_e.tail) + (Vector((0, 0, 1)) * foot_e.length / 3) toe_parent_socket2_e.roll = toe_parent_socket1_e.roll tail = Vector(roll1_e.tail) roll1_e.tail = Vector(org_foot_e.tail) roll1_e.tail = Vector(org_foot_e.tail) roll1_e.head = tail roll2_e.head = Vector(org_foot_e.tail) foot_roll_e.head = Vector(org_foot_e.tail) put_bone(self.obj, foot_roll, roll1_e.head) foot_roll_e.length /= 2 roll_axis = roll1_e.vector.cross(org_foot_e.vector) align_x_axis(self.obj, roll1, roll_axis) align_x_axis(self.obj, roll2, roll_axis) foot_roll_e.roll = roll2_e.roll visfoot_e.tail = visfoot_e.head + Vector((0, 0, v1.length / 32)) vispole_e.tail = vispole_e.head + Vector((0, 0, v1.length / 32)) if make_rocker: d = toe_e.y_axis.dot(rocker1_e.x_axis) if d >= 0.0: flip_bone(self.obj, rocker2) else: flip_bone(self.obj, rocker1) # Weird alignment issues. Fix. toe_parent_e.head = Vector(org_foot_e.head) toe_parent_e.tail = Vector(org_foot_e.tail) toe_parent_e.roll = org_foot_e.roll foot_e.head = Vector(org_foot_e.head) foot_ik_target_e.head = Vector(org_foot_e.head) foot_ik_target_e.tail = Vector(org_foot_e.tail) # Determine the pole offset value plane = (shin_e.tail - thigh_e.head).normalized() vec1 = thigh_e.x_axis.normalized() vec2 = (pole_e.head - thigh_e.head).normalized() pole_offset = angle_on_plane(plane, vec1, vec2) # Object mode, get pose bones bpy.ops.object.mode_set(mode='OBJECT') pb = self.obj.pose.bones # thigh_p = pb[thigh] # UNUSED shin_p = pb[shin] foot_p = pb[foot] pole_p = pb[pole] foot_roll_p = pb[foot_roll] roll1_p = pb[roll1] roll2_p = pb[roll2] if make_rocker: rocker1_p = pb[rocker1] rocker2_p = pb[rocker2] toe_p = pb[toe] toe_parent_p = pb[toe_parent] toe_parent_socket1_p = pb[toe_parent_socket1] visfoot_p = pb[visfoot] vispole_p = pb[vispole] # Set the knee to only bend on the primary axis. if 'X' in self.primary_rotation_axis: shin_p.lock_ik_y = True shin_p.lock_ik_z = True elif 'Y' in self.primary_rotation_axis: shin_p.lock_ik_x = True shin_p.lock_ik_z = True else: shin_p.lock_ik_x = True shin_p.lock_ik_y = True # Foot roll control only rotates on x-axis, or x and y if rocker. foot_roll_p.rotation_mode = 'XYZ' if make_rocker: foot_roll_p.lock_rotation = False, False, True else: foot_roll_p.lock_rotation = False, True, True foot_roll_p.lock_location = True, True, True foot_roll_p.lock_scale = True, True, True # roll and rocker bones set to euler rotation roll1_p.rotation_mode = 'XYZ' roll2_p.rotation_mode = 'XYZ' if make_rocker: rocker1_p.rotation_mode = 'XYZ' rocker2_p.rotation_mode = 'XYZ' # Pole target only translates pole_p.lock_location = False, False, False pole_p.lock_rotation = True, True, True pole_p.lock_rotation_w = True pole_p.lock_scale = True, True, True # Set up custom properties if self.switch == True: prop = rna_idprop_ui_prop_get(foot_p, "ikfk_switch", create=True) foot_p["ikfk_switch"] = 0.0 prop["soft_min"] = prop["min"] = 0.0 prop["soft_max"] = prop["max"] = 1.0 # Bend direction hint if self.bend_hint: con = shin_p.constraints.new('LIMIT_ROTATION') con.name = "bend_hint" con.owner_space = 'LOCAL' if self.primary_rotation_axis == 'X': con.use_limit_x = True con.min_x = pi / 10 con.max_x = pi / 10 elif self.primary_rotation_axis == '-X': con.use_limit_x = True con.min_x = -pi / 10 con.max_x = -pi / 10 elif self.primary_rotation_axis == 'Y': con.use_limit_y = True con.min_y = pi / 10 con.max_y = pi / 10 elif self.primary_rotation_axis == '-Y': con.use_limit_y = True con.min_y = -pi / 10 con.max_y = -pi / 10 elif self.primary_rotation_axis == 'Z': con.use_limit_z = True con.min_z = pi / 10 con.max_z = pi / 10 elif self.primary_rotation_axis == '-Z': con.use_limit_z = True con.min_z = -pi / 10 con.max_z = -pi / 10 # IK Constraint con = shin_p.constraints.new('IK') con.name = "ik" con.target = self.obj con.subtarget = foot_ik_target con.pole_target = self.obj con.pole_subtarget = pole con.pole_angle = pole_offset con.chain_count = 2 # toe_parent constraint con = toe_parent_socket1_p.constraints.new('COPY_LOCATION') con.name = "copy_location" con.target = self.obj con.subtarget = toe_parent_socket2 con = toe_parent_socket1_p.constraints.new('COPY_SCALE') con.name = "copy_scale" con.target = self.obj con.subtarget = toe_parent_socket2 con = toe_parent_socket1_p.constraints.new('COPY_TRANSFORMS') # drive with IK switch con.name = "fk" con.target = self.obj con.subtarget = toe_parent_socket2 fcurve = con.driver_add("influence") driver = fcurve.driver var = driver.variables.new() driver.type = 'AVERAGE' var.name = "var" var.targets[0].id_type = 'OBJECT' var.targets[0].id = self.obj var.targets[0].data_path = foot_p.path_from_id() + '["ikfk_switch"]' mod = fcurve.modifiers[0] mod.poly_order = 1 mod.coefficients[0] = 1.0 mod.coefficients[1] = -1.0 # Foot roll drivers fcurve = roll1_p.driver_add("rotation_euler", 0) driver = fcurve.driver var = driver.variables.new() driver.type = 'SCRIPTED' driver.expression = "min(0,var)" var.name = "var" var.targets[0].id_type = 'OBJECT' var.targets[0].id = self.obj var.targets[0].data_path = foot_roll_p.path_from_id() + '.rotation_euler[0]' fcurve = roll2_p.driver_add("rotation_euler", 0) driver = fcurve.driver var = driver.variables.new() driver.type = 'SCRIPTED' driver.expression = "max(0,var)" var.name = "var" var.targets[0].id_type = 'OBJECT' var.targets[0].id = self.obj var.targets[0].data_path = foot_roll_p.path_from_id() + '.rotation_euler[0]' if make_rocker: fcurve = rocker1_p.driver_add("rotation_euler", 0) driver = fcurve.driver var = driver.variables.new() driver.type = 'SCRIPTED' driver.expression = "max(0,-var)" var.name = "var" var.targets[0].id_type = 'OBJECT' var.targets[0].id = self.obj var.targets[0].data_path = foot_roll_p.path_from_id() + '.rotation_euler[1]' fcurve = rocker2_p.driver_add("rotation_euler", 0) driver = fcurve.driver var = driver.variables.new() driver.type = 'SCRIPTED' driver.expression = "max(0,var)" var.name = "var" var.targets[0].id_type = 'OBJECT' var.targets[0].id = self.obj var.targets[0].data_path = foot_roll_p.path_from_id() + '.rotation_euler[1]' # Constrain org bones to controls con = pb[self.org_bones[0]].constraints.new('COPY_TRANSFORMS') con.name = "ik" con.target = self.obj con.subtarget = thigh if self.switch == True: # IK/FK switch driver fcurve = con.driver_add("influence") driver = fcurve.driver var = driver.variables.new() driver.type = 'AVERAGE' var.name = "var" var.targets[0].id_type = 'OBJECT' var.targets[0].id = self.obj var.targets[0].data_path = foot_p.path_from_id() + '["ikfk_switch"]' con = pb[self.org_bones[1]].constraints.new('COPY_TRANSFORMS') con.name = "ik" con.target = self.obj con.subtarget = shin if self.switch == True: # IK/FK switch driver fcurve = con.driver_add("influence") driver = fcurve.driver var = driver.variables.new() driver.type = 'AVERAGE' var.name = "var" var.targets[0].id_type = 'OBJECT' var.targets[0].id = self.obj var.targets[0].data_path = foot_p.path_from_id() + '["ikfk_switch"]' con = pb[self.org_bones[2]].constraints.new('COPY_TRANSFORMS') con.name = "ik" con.target = self.obj con.subtarget = foot_ik_target if self.switch == True: # IK/FK switch driver fcurve = con.driver_add("influence") driver = fcurve.driver var = driver.variables.new() driver.type = 'AVERAGE' var.name = "var" var.targets[0].id_type = 'OBJECT' var.targets[0].id = self.obj var.targets[0].data_path = foot_p.path_from_id() + '["ikfk_switch"]' con = pb[self.org_bones[3]].constraints.new('COPY_TRANSFORMS') con.name = "copy_transforms" con.target = self.obj con.subtarget = toe # VIS foot constraints con = visfoot_p.constraints.new('COPY_LOCATION') con.name = "copy_loc" con.target = self.obj con.subtarget = self.org_bones[2] con = visfoot_p.constraints.new('STRETCH_TO') con.name = "stretch_to" con.target = self.obj con.subtarget = foot con.volume = 'NO_VOLUME' con.rest_length = visfoot_p.length # VIS pole constraints con = vispole_p.constraints.new('COPY_LOCATION') con.name = "copy_loc" con.target = self.obj con.subtarget = self.org_bones[1] con = vispole_p.constraints.new('STRETCH_TO') con.name = "stretch_to" con.target = self.obj con.subtarget = pole con.volume = 'NO_VOLUME' con.rest_length = vispole_p.length # Set layers if specified if self.layers: foot_p.bone.layers = self.layers pole_p.bone.layers = self.layers foot_roll_p.bone.layers = self.layers visfoot_p.bone.layers = self.layers vispole_p.bone.layers = self.layers toe_p.bone.layers = [(i[0] or i[1]) for i in zip(toe_p.bone.layers, self.layers)] # Both FK and IK layers # Create widgets create_line_widget(self.obj, vispole) create_line_widget(self.obj, visfoot) create_sphere_widget(self.obj, pole) create_circle_widget(self.obj, toe, radius=0.7, head_tail=0.5) ob = create_widget(self.obj, foot) if ob != None: verts = [(0.7, 1.5, 0.0), (0.7, -0.25, 0.0), (-0.7, -0.25, 0.0), (-0.7, 1.5, 0.0), (0.7, 0.723, 0.0), (-0.7, 0.723, 0.0), (0.7, 0.0, 0.0), (-0.7, 0.0, 0.0)] edges = [(1, 2), (0, 3), (0, 4), (3, 5), (4, 6), (1, 6), (5, 7), (2, 7)] mesh = ob.data mesh.from_pydata(verts, edges, []) mesh.update() mod = ob.modifiers.new("subsurf", 'SUBSURF') mod.levels = 2 ob = create_widget(self.obj, foot_roll) if ob != None: verts = [(0.3999999761581421, 0.766044557094574, 0.6427875757217407), (0.17668449878692627, 3.823702598992895e-08, 3.2084670920085046e-08), (-0.17668461799621582, 9.874240447516058e-08, 8.285470443070153e-08), (-0.39999961853027344, 0.7660449147224426, 0.6427879333496094), (0.3562471270561218, 0.6159579753875732, 0.5168500542640686), (-0.35624682903289795, 0.6159582138061523, 0.5168502926826477), (0.20492683351039886, 0.09688037633895874, 0.0812922865152359), (-0.20492687821388245, 0.0968804731965065, 0.08129236847162247)] edges = [(1, 2), (0, 3), (0, 4), (3, 5), (1, 6), (4, 6), (2, 7), (5, 7)] mesh = ob.data mesh.from_pydata(verts, edges, []) mesh.update() mod = ob.modifiers.new("subsurf", 'SUBSURF') mod.levels = 2 return [thigh, shin, foot, pole, foot_roll, foot_ik_target]
def generate(self): """ Generate the rig. Do NOT modify any of the original bones, except for adding constraints. The main armature should be selected and active before this is called. """ bpy.ops.object.mode_set(mode='EDIT') 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]