def create_aligned_circle_widget(rig, bone_name, number_verts=32, radius=1.0, width_ratio=1.0, head_tail=0.0, bone_transform_name=None): """ Creates a circle widget, aligned to view. """ obj = create_widget(rig, bone_name, bone_transform_name) if obj is not None: pbone = rig.pose.bones[bone_name] # print(pbone.matrix.translation) pos = pbone.matrix.translation verts, edges = create_circle_polygon(number_verts, 'Z', radius) head_tail_vector = Vector((0, head_tail, 0)) * pbone.length verts = [ 1 / pbone.length * ((Vector(v) @ Matrix.Scale(width_ratio, 3, Vector( (1, 0, 0)))) + head_tail_vector) for v in verts ] mesh = obj.data mesh.from_pydata(verts, edges, []) mesh.update()
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. """ bone_list = self.ik_limb.generate() uarm = bone_list[0] farm = bone_list[1] hand = bone_list[2] # hand_mch = bone_list[3] pole = bone_list[4] # vispole = bone_list[5] # vishand = bone_list[6] ob = create_widget(self.obj, hand) 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 [uarm, farm, hand, pole]
def create_axis_line_widget(rig, bone_name, length=1, axis='X', bone_transform_name=None): """ Creates a basic line widget which remains horizontal. """ obj = create_widget(rig, bone_name, bone_transform_name) if obj is not None: pbone = rig.pose.bones[bone_name] # print(pbone.matrix.translation) pos = pbone.matrix.translation assert (axis in 'XYZ') if axis == 'X': verts = [(-1, 0, 0), (1, 0, 0)] if axis == 'Y': verts = [(0, -1, 0), (0, 1, 0)] if axis == 'Z': verts = [(0, 0, -1), (0, 0, 1)] verts = [ pbone.matrix.inverted() * (pos + Vector(v) * length) for v in verts ] edges = [(0, 1)] mesh = obj.data mesh.from_pydata(verts, edges, []) mesh.update()
def create_capsule_widget(rig, bone_name, length=None, width=None, head_tail=0.0, horizontal=True, overshoot=False, bone_transform_name=None): """ Create a basic line widget which optionally remains horizontal. """ obj = create_widget(rig, bone_name, bone_transform_name) if obj is not None: pbone = rig.pose.bones[bone_name] # print(pbone.matrix.translation) pos = pbone.matrix.translation if length is None: length = pbone.length * 2 if width is None: width = length * 0.1 if horizontal: head_tail_vector = pbone.vector * head_tail verts, edges = create_capsule_polygon(16, length, width, overshoot=overshoot) verts = [(pbone.matrix * pbone.length).inverted() @ (pos + Vector(v) + head_tail_vector) for v in verts] else: head_tail_vector = Vector((0, 1, 0)) * head_tail verts, edges = create_capsule_polygon(16, length, width, 1, 0, overshoot=overshoot) verts = [(Vector(v) + head_tail_vector) for v in verts] mesh = obj.data mesh.from_pydata(verts, edges, []) mesh.update()
def create_aligned_polygon_widget(rig, bone_name, vertex_points, bone_transform_name=None): """ Creates a basic line widget which remains horizontal. """ obj = create_widget(rig, bone_name, bone_transform_name) if obj is not None: pbone = rig.pose.bones[bone_name] verts = [Vector((x, 0.0, y)) for x, y in vertex_points] edges = [] for i in range(len(verts)): edges.append((i, i + 1)) edges[-1] = (0, len(verts) - 1) verts = [(pbone.matrix * pbone.length).inverted() @ (v) for v in verts] mesh = obj.data mesh.from_pydata(verts, edges, []) mesh.update()
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. """ ctrl_bones = self.fk_limb.generate() thigh = ctrl_bones[0] shin = ctrl_bones[1] foot = ctrl_bones[2] foot_mch = ctrl_bones[3] # Position foot control bpy.ops.object.mode_set(mode='EDIT') eb = self.obj.data.edit_bones foot_e = eb[foot] vec = Vector(eb[self.org_bones[3]].vector) vec.normalize() foot_e.tail = foot_e.head + (vec * foot_e.length) foot_e.roll = eb[self.org_bones[3]].roll bpy.ops.object.mode_set(mode='OBJECT') # Create foot widget 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, foot_mch]
def create_aligned_half_ellipse_widget(rig, bone_name, width, height, bone_transform_name=None, head_tail=0.0): """ Creates a half ellipse widget, aligned to view. """ obj = create_widget(rig, bone_name, bone_transform_name) if obj is not None: pbone = rig.pose.bones[bone_name] # print(pbone.matrix.translation) pos = pbone.matrix.translation verts, edges = create_half_ellipse_polygon(16, width, height) head_tail_vector = pbone.vector * head_tail verts = [(pbone.matrix * pbone.length).inverted() * (pos + Vector(v) + head_tail_vector) for v in verts] mesh = obj.data mesh.from_pydata(verts, edges, []) mesh.update()
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 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') # Figure out the name for the control bone (remove the last .##) last_bone = self.org_bones[-1:][0] ctrl_name = re.sub("([0-9]+\.)", "", strip_org(last_bone)[::-1], count=1)[::-1] # Make control bone ctrl = copy_bone(self.obj, last_bone, ctrl_name) # Make deformation bones def_bones = [] for bone in self.org_bones: b = copy_bone(self.obj, bone, deformer(strip_org(bone))) def_bones += [b] # Parenting eb = self.obj.data.edit_bones for d, b in zip(def_bones, self.org_bones): eb[d].use_connect = False eb[d].parent = eb[b] # Constraints bpy.ops.object.mode_set(mode='OBJECT') pb = self.obj.pose.bones i = 0 div = len(self.org_bones) - 1 for b in self.org_bones: con = pb[b].constraints.new('COPY_TRANSFORMS') con.name = "copy_transforms" con.target = self.obj con.subtarget = ctrl con.target_space = 'LOCAL' con.owner_space = 'LOCAL' con.influence = i / div con = pb[b].constraints.new('COPY_ROTATION') con.name = "copy_rotation" con.target = self.obj con.subtarget = ctrl con.target_space = 'LOCAL' con.owner_space = 'LOCAL' if 'X' in self.palm_rotation_axis: con.invert_x = True con.use_x = True con.use_z = False else: con.invert_z = True con.use_x = False con.use_z = True con.use_y = False con.influence = (i / div) - (1 - cos((i * pi / 2) / div)) i += 1 # Create control widget w = create_widget(self.obj, ctrl) if w != None: mesh = w.data verts = [(0.15780271589756012, 2.086162567138672e-07, -0.30000004172325134), (0.15780259668827057, 1.0, -0.2000001072883606), (-0.15780280530452728, 0.9999999403953552, -0.20000004768371582), (-0.15780259668827057, -2.086162567138672e-07, -0.29999998211860657), (-0.15780256688594818, -2.7089754439657554e-07, 0.30000004172325134), (-0.1578027755022049, 0.9999998807907104, 0.19999995827674866), (0.15780262649059296, 0.9999999403953552, 0.19999989867210388), (0.1578027456998825, 1.4633496903115883e-07, 0.29999998211860657), (0.15780268609523773, 0.2500001788139343, -0.27500003576278687), (-0.15780264139175415, 0.24999985098838806, -0.2749999761581421), (0.15780262649059296, 0.7500000596046448, -0.22500008344650269), (-0.1578027606010437, 0.7499998807907104, -0.2250000238418579), (0.15780265629291534, 0.75, 0.22499991953372955), (0.15780271589756012, 0.2500000596046448, 0.2749999761581421), (-0.15780261158943176, 0.2499997615814209, 0.27500003576278687), (-0.1578027307987213, 0.7499998807907104, 0.22499997913837433)] if 'Z' in self.palm_rotation_axis: # Flip x/z coordinates temp = [] for v in verts: temp += [(v[2], v[1], v[0])] verts = temp edges = [(1, 2), (0, 3), (4, 7), (5, 6), (8, 0), (9, 3), (10, 1), (11, 2), (12, 6), (13, 7), (4, 14), (15, 5), (10, 8), (11, 9), (15, 14), (12, 13)] mesh.from_pydata(verts, edges, []) mesh.update() mod = w.modifiers.new("subsurf", 'SUBSURF') mod.levels = 2
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): """ 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 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 generate(self): """ Generate the rig. Do NOT modify any of the original bones, except for adding constraints. The main armature should be selected and active before this is called. """ bpy.ops.object.mode_set(mode='EDIT') make_rocker = False if self.org_bones[5] is not None: make_rocker = True # Create the bones thigh = copy_bone( self.obj, self.org_bones[0], make_mechanism_name( strip_org(insert_before_lr(self.org_bones[0], "_ik")))) shin = copy_bone( self.obj, self.org_bones[1], make_mechanism_name( strip_org(insert_before_lr(self.org_bones[1], "_ik")))) foot = copy_bone(self.obj, self.org_bones[2], strip_org(insert_before_lr(self.org_bones[2], "_ik"))) foot_ik_target = copy_bone( self.obj, self.org_bones[2], make_mechanism_name( strip_org(insert_before_lr(self.org_bones[2], "_ik_target")))) pole = copy_bone( self.obj, self.org_bones[0], strip_org(insert_before_lr(self.org_bones[0], "_pole"))) toe = copy_bone(self.obj, self.org_bones[3], strip_org(self.org_bones[3])) toe_parent = copy_bone( self.obj, self.org_bones[2], make_mechanism_name(strip_org(self.org_bones[3] + ".parent"))) toe_parent_socket1 = copy_bone( self.obj, self.org_bones[2], make_mechanism_name(strip_org(self.org_bones[3] + ".socket1"))) toe_parent_socket2 = copy_bone( self.obj, self.org_bones[2], make_mechanism_name(strip_org(self.org_bones[3] + ".socket2"))) foot_roll = copy_bone( self.obj, self.org_bones[4], strip_org(insert_before_lr(self.org_bones[2], "_roll"))) roll1 = copy_bone( self.obj, self.org_bones[4], make_mechanism_name(strip_org(self.org_bones[2] + ".roll.01"))) roll2 = copy_bone( self.obj, self.org_bones[4], make_mechanism_name(strip_org(self.org_bones[2] + ".roll.02"))) if make_rocker: rocker1 = copy_bone( self.obj, self.org_bones[5], make_mechanism_name(strip_org(self.org_bones[2] + ".rocker.01"))) rocker2 = copy_bone( self.obj, self.org_bones[5], make_mechanism_name(strip_org(self.org_bones[2] + ".rocker.02"))) visfoot = copy_bone( self.obj, self.org_bones[2], "VIS-" + strip_org(insert_before_lr(self.org_bones[2], "_ik"))) vispole = copy_bone( self.obj, self.org_bones[1], "VIS-" + strip_org(insert_before_lr(self.org_bones[0], "_pole"))) # Get edit bones eb = self.obj.data.edit_bones org_foot_e = eb[self.org_bones[2]] thigh_e = eb[thigh] shin_e = eb[shin] foot_e = eb[foot] foot_ik_target_e = eb[foot_ik_target] pole_e = eb[pole] toe_e = eb[toe] toe_parent_e = eb[toe_parent] toe_parent_socket1_e = eb[toe_parent_socket1] toe_parent_socket2_e = eb[toe_parent_socket2] foot_roll_e = eb[foot_roll] roll1_e = eb[roll1] roll2_e = eb[roll2] if make_rocker: rocker1_e = eb[rocker1] rocker2_e = eb[rocker2] visfoot_e = eb[visfoot] vispole_e = eb[vispole] # Parenting shin_e.parent = thigh_e foot_e.use_connect = False foot_e.parent = None foot_ik_target_e.use_connect = False foot_ik_target_e.parent = roll2_e pole_e.use_connect = False pole_e.parent = foot_e toe_e.parent = toe_parent_e toe_parent_e.use_connect = False toe_parent_e.parent = toe_parent_socket1_e toe_parent_socket1_e.use_connect = False toe_parent_socket1_e.parent = roll1_e toe_parent_socket2_e.use_connect = False toe_parent_socket2_e.parent = eb[self.org_bones[2]] foot_roll_e.use_connect = False foot_roll_e.parent = foot_e roll1_e.use_connect = False roll1_e.parent = foot_e roll2_e.use_connect = False roll2_e.parent = roll1_e visfoot_e.use_connect = False visfoot_e.parent = None vispole_e.use_connect = False vispole_e.parent = None if make_rocker: rocker1_e.use_connect = False rocker2_e.use_connect = False roll1_e.parent = rocker2_e rocker2_e.parent = rocker1_e rocker1_e.parent = foot_e # Misc foot_e.use_local_location = False visfoot_e.hide_select = True vispole_e.hide_select = True # Positioning vec = Vector(toe_e.vector) vec.normalize() foot_e.tail = foot_e.head + (vec * foot_e.length) foot_e.roll = toe_e.roll v1 = shin_e.tail - thigh_e.head if 'X' in self.primary_rotation_axis or 'Y' in self.primary_rotation_axis: v2 = v1.cross(shin_e.x_axis) if (v2 * shin_e.z_axis) > 0.0: v2 *= -1.0 else: v2 = v1.cross(shin_e.z_axis) if (v2 * shin_e.x_axis) < 0.0: v2 *= -1.0 v2.normalize() v2 *= v1.length if '-' in self.primary_rotation_axis: v2 *= -1 pole_e.head = shin_e.head + v2 pole_e.tail = pole_e.head + (Vector((0, 1, 0)) * (v1.length / 8)) pole_e.roll = 0.0 flip_bone(self.obj, toe_parent_socket1) flip_bone(self.obj, toe_parent_socket2) toe_parent_socket1_e.head = Vector(org_foot_e.tail) toe_parent_socket2_e.head = Vector(org_foot_e.tail) toe_parent_socket1_e.tail = Vector(org_foot_e.tail) + (Vector( (0, 0, 1)) * foot_e.length / 2) toe_parent_socket2_e.tail = Vector(org_foot_e.tail) + (Vector( (0, 0, 1)) * foot_e.length / 3) toe_parent_socket2_e.roll = toe_parent_socket1_e.roll tail = Vector(roll1_e.tail) roll1_e.tail = Vector(org_foot_e.tail) roll1_e.tail = Vector(org_foot_e.tail) roll1_e.head = tail roll2_e.head = Vector(org_foot_e.tail) foot_roll_e.head = Vector(org_foot_e.tail) put_bone(self.obj, foot_roll, roll1_e.head) foot_roll_e.length /= 2 roll_axis = roll1_e.vector.cross(org_foot_e.vector) align_x_axis(self.obj, roll1, roll_axis) align_x_axis(self.obj, roll2, roll_axis) foot_roll_e.roll = roll2_e.roll visfoot_e.tail = visfoot_e.head + Vector((0, 0, v1.length / 32)) vispole_e.tail = vispole_e.head + Vector((0, 0, v1.length / 32)) if make_rocker: d = toe_e.y_axis.dot(rocker1_e.x_axis) if d >= 0.0: flip_bone(self.obj, rocker2) else: flip_bone(self.obj, rocker1) # Weird alignment issues. Fix. toe_parent_e.head = Vector(org_foot_e.head) toe_parent_e.tail = Vector(org_foot_e.tail) toe_parent_e.roll = org_foot_e.roll foot_e.head = Vector(org_foot_e.head) foot_ik_target_e.head = Vector(org_foot_e.head) foot_ik_target_e.tail = Vector(org_foot_e.tail) # Determine the pole offset value plane = (shin_e.tail - thigh_e.head).normalized() vec1 = thigh_e.x_axis.normalized() vec2 = (pole_e.head - thigh_e.head).normalized() pole_offset = angle_on_plane(plane, vec1, vec2) # Object mode, get pose bones bpy.ops.object.mode_set(mode='OBJECT') pb = self.obj.pose.bones # thigh_p = pb[thigh] # UNUSED shin_p = pb[shin] foot_p = pb[foot] pole_p = pb[pole] foot_roll_p = pb[foot_roll] roll1_p = pb[roll1] roll2_p = pb[roll2] if make_rocker: rocker1_p = pb[rocker1] rocker2_p = pb[rocker2] toe_p = pb[toe] toe_parent_p = pb[toe_parent] toe_parent_socket1_p = pb[toe_parent_socket1] visfoot_p = pb[visfoot] vispole_p = pb[vispole] # Set the knee to only bend on the primary axis. if 'X' in self.primary_rotation_axis: shin_p.lock_ik_y = True shin_p.lock_ik_z = True elif 'Y' in self.primary_rotation_axis: shin_p.lock_ik_x = True shin_p.lock_ik_z = True else: shin_p.lock_ik_x = True shin_p.lock_ik_y = True # Foot roll control only rotates on x-axis, or x and y if rocker. foot_roll_p.rotation_mode = 'XYZ' if make_rocker: foot_roll_p.lock_rotation = False, False, True else: foot_roll_p.lock_rotation = False, True, True foot_roll_p.lock_location = True, True, True foot_roll_p.lock_scale = True, True, True # roll and rocker bones set to euler rotation roll1_p.rotation_mode = 'XYZ' roll2_p.rotation_mode = 'XYZ' if make_rocker: rocker1_p.rotation_mode = 'XYZ' rocker2_p.rotation_mode = 'XYZ' # Pole target only translates pole_p.lock_location = False, False, False pole_p.lock_rotation = True, True, True pole_p.lock_rotation_w = True pole_p.lock_scale = True, True, True # Set up custom properties if self.switch == True: prop = rna_idprop_ui_prop_get(foot_p, "ikfk_switch", create=True) foot_p["ikfk_switch"] = 0.0 prop["soft_min"] = prop["min"] = 0.0 prop["soft_max"] = prop["max"] = 1.0 # Bend direction hint if self.bend_hint: con = shin_p.constraints.new('LIMIT_ROTATION') con.name = "bend_hint" con.owner_space = 'LOCAL' if self.primary_rotation_axis == 'X': con.use_limit_x = True con.min_x = pi / 10 con.max_x = pi / 10 elif self.primary_rotation_axis == '-X': con.use_limit_x = True con.min_x = -pi / 10 con.max_x = -pi / 10 elif self.primary_rotation_axis == 'Y': con.use_limit_y = True con.min_y = pi / 10 con.max_y = pi / 10 elif self.primary_rotation_axis == '-Y': con.use_limit_y = True con.min_y = -pi / 10 con.max_y = -pi / 10 elif self.primary_rotation_axis == 'Z': con.use_limit_z = True con.min_z = pi / 10 con.max_z = pi / 10 elif self.primary_rotation_axis == '-Z': con.use_limit_z = True con.min_z = -pi / 10 con.max_z = -pi / 10 # IK Constraint con = shin_p.constraints.new('IK') con.name = "ik" con.target = self.obj con.subtarget = foot_ik_target con.pole_target = self.obj con.pole_subtarget = pole con.pole_angle = pole_offset con.chain_count = 2 # toe_parent constraint con = toe_parent_socket1_p.constraints.new('COPY_LOCATION') con.name = "copy_location" con.target = self.obj con.subtarget = toe_parent_socket2 con = toe_parent_socket1_p.constraints.new('COPY_SCALE') con.name = "copy_scale" con.target = self.obj con.subtarget = toe_parent_socket2 con = toe_parent_socket1_p.constraints.new( 'COPY_TRANSFORMS') # drive with IK switch con.name = "fk" con.target = self.obj con.subtarget = toe_parent_socket2 fcurve = con.driver_add("influence") driver = fcurve.driver var = driver.variables.new() driver.type = 'AVERAGE' var.name = "var" var.targets[0].id_type = 'OBJECT' var.targets[0].id = self.obj var.targets[0].data_path = foot_p.path_from_id() + '["ikfk_switch"]' mod = fcurve.modifiers[0] mod.poly_order = 1 mod.coefficients[0] = 1.0 mod.coefficients[1] = -1.0 # Foot roll drivers fcurve = roll1_p.driver_add("rotation_euler", 0) driver = fcurve.driver var = driver.variables.new() driver.type = 'SCRIPTED' driver.expression = "min(0,var)" var.name = "var" var.targets[0].id_type = 'OBJECT' var.targets[0].id = self.obj var.targets[0].data_path = foot_roll_p.path_from_id( ) + '.rotation_euler[0]' fcurve = roll2_p.driver_add("rotation_euler", 0) driver = fcurve.driver var = driver.variables.new() driver.type = 'SCRIPTED' driver.expression = "max(0,var)" var.name = "var" var.targets[0].id_type = 'OBJECT' var.targets[0].id = self.obj var.targets[0].data_path = foot_roll_p.path_from_id( ) + '.rotation_euler[0]' if make_rocker: fcurve = rocker1_p.driver_add("rotation_euler", 0) driver = fcurve.driver var = driver.variables.new() driver.type = 'SCRIPTED' driver.expression = "max(0,-var)" var.name = "var" var.targets[0].id_type = 'OBJECT' var.targets[0].id = self.obj var.targets[0].data_path = foot_roll_p.path_from_id( ) + '.rotation_euler[1]' fcurve = rocker2_p.driver_add("rotation_euler", 0) driver = fcurve.driver var = driver.variables.new() driver.type = 'SCRIPTED' driver.expression = "max(0,var)" var.name = "var" var.targets[0].id_type = 'OBJECT' var.targets[0].id = self.obj var.targets[0].data_path = foot_roll_p.path_from_id( ) + '.rotation_euler[1]' # Constrain org bones to controls con = pb[self.org_bones[0]].constraints.new('COPY_TRANSFORMS') con.name = "ik" con.target = self.obj con.subtarget = thigh if self.switch == True: # IK/FK switch driver fcurve = con.driver_add("influence") driver = fcurve.driver var = driver.variables.new() driver.type = 'AVERAGE' var.name = "var" var.targets[0].id_type = 'OBJECT' var.targets[0].id = self.obj var.targets[0].data_path = foot_p.path_from_id( ) + '["ikfk_switch"]' con = pb[self.org_bones[1]].constraints.new('COPY_TRANSFORMS') con.name = "ik" con.target = self.obj con.subtarget = shin if self.switch == True: # IK/FK switch driver fcurve = con.driver_add("influence") driver = fcurve.driver var = driver.variables.new() driver.type = 'AVERAGE' var.name = "var" var.targets[0].id_type = 'OBJECT' var.targets[0].id = self.obj var.targets[0].data_path = foot_p.path_from_id( ) + '["ikfk_switch"]' con = pb[self.org_bones[2]].constraints.new('COPY_TRANSFORMS') con.name = "ik" con.target = self.obj con.subtarget = foot_ik_target if self.switch == True: # IK/FK switch driver fcurve = con.driver_add("influence") driver = fcurve.driver var = driver.variables.new() driver.type = 'AVERAGE' var.name = "var" var.targets[0].id_type = 'OBJECT' var.targets[0].id = self.obj var.targets[0].data_path = foot_p.path_from_id( ) + '["ikfk_switch"]' con = pb[self.org_bones[3]].constraints.new('COPY_TRANSFORMS') con.name = "copy_transforms" con.target = self.obj con.subtarget = toe # VIS foot constraints con = visfoot_p.constraints.new('COPY_LOCATION') con.name = "copy_loc" con.target = self.obj con.subtarget = self.org_bones[2] con = visfoot_p.constraints.new('STRETCH_TO') con.name = "stretch_to" con.target = self.obj con.subtarget = foot con.volume = 'NO_VOLUME' con.rest_length = visfoot_p.length # VIS pole constraints con = vispole_p.constraints.new('COPY_LOCATION') con.name = "copy_loc" con.target = self.obj con.subtarget = self.org_bones[1] con = vispole_p.constraints.new('STRETCH_TO') con.name = "stretch_to" con.target = self.obj con.subtarget = pole con.volume = 'NO_VOLUME' con.rest_length = vispole_p.length # Set layers if specified if self.layers: foot_p.bone.layers = self.layers pole_p.bone.layers = self.layers foot_roll_p.bone.layers = self.layers visfoot_p.bone.layers = self.layers vispole_p.bone.layers = self.layers toe_p.bone.layers = [ (i[0] or i[1]) for i in zip(toe_p.bone.layers, self.layers) ] # Both FK and IK layers # Create widgets create_line_widget(self.obj, vispole) create_line_widget(self.obj, visfoot) create_sphere_widget(self.obj, pole) create_circle_widget(self.obj, toe, radius=0.7, head_tail=0.5) ob = create_widget(self.obj, foot) if ob != None: verts = [(0.7, 1.5, 0.0), (0.7, -0.25, 0.0), (-0.7, -0.25, 0.0), (-0.7, 1.5, 0.0), (0.7, 0.723, 0.0), (-0.7, 0.723, 0.0), (0.7, 0.0, 0.0), (-0.7, 0.0, 0.0)] edges = [(1, 2), (0, 3), (0, 4), (3, 5), (4, 6), (1, 6), (5, 7), (2, 7)] mesh = ob.data mesh.from_pydata(verts, edges, []) mesh.update() mod = ob.modifiers.new("subsurf", 'SUBSURF') mod.levels = 2 ob = create_widget(self.obj, foot_roll) if ob != None: verts = [ (0.3999999761581421, 0.766044557094574, 0.6427875757217407), (0.17668449878692627, 3.823702598992895e-08, 3.2084670920085046e-08), (-0.17668461799621582, 9.874240447516058e-08, 8.285470443070153e-08), (-0.39999961853027344, 0.7660449147224426, 0.6427879333496094), (0.3562471270561218, 0.6159579753875732, 0.5168500542640686), (-0.35624682903289795, 0.6159582138061523, 0.5168502926826477), (0.20492683351039886, 0.09688037633895874, 0.0812922865152359), (-0.20492687821388245, 0.0968804731965065, 0.08129236847162247) ] edges = [(1, 2), (0, 3), (0, 4), (3, 5), (1, 6), (4, 6), (2, 7), (5, 7)] mesh = ob.data mesh.from_pydata(verts, edges, []) mesh.update() mod = ob.modifiers.new("subsurf", 'SUBSURF') mod.levels = 2 return [thigh, shin, foot, pole, foot_roll, foot_ik_target]
def create_aligned_crescent_widget(rig, bone_name, radius=1.0, head_tail=0.0, bone_transform_name=None): """ Creates a crescent widget, aligned to view. """ obj = create_widget(rig, bone_name, bone_transform_name) if obj is not None: pbone = rig.pose.bones[bone_name] # print(pbone.matrix.translation) pos = pbone.matrix.translation verts = [ Vector((-0.3826834559440613, 3.5762786865234375e-07, 0.9238792061805725)), Vector((-0.5555702447891235, 3.5762786865234375e-07, 0.8314692974090576)), Vector((-0.7071067690849304, 3.5762786865234375e-07, 0.7071064710617065)), Vector((-0.8314696550369263, 2.980232238769531e-07, 0.5555698871612549)), Vector((-0.9238795042037964, 3.2782554626464844e-07, 0.382683128118515)), Vector((-0.9807852506637573, 2.980232238769531e-07, 0.19509007036685944)), Vector((-1.0, 2.84984679410627e-07, -2.0948681367372046e-07)), Vector((-0.9807853102684021, 2.682209014892578e-07, -0.19509048759937286)), Vector((-0.9238795638084412, 2.682209014892578e-07, -0.38268357515335083)), Vector((-0.8314696550369263, 2.384185791015625e-07, -0.5555704832077026)), Vector((-0.7071067690849304, 2.384185791015625e-07, -0.7071070671081543)), Vector((-0.5555701851844788, 2.384185791015625e-07, -0.8314699530601501)), Vector((-0.38268327713012695, 2.384185791015625e-07, -0.9238799214363098)), Vector((-0.19509008526802063, 2.384185791015625e-07, -0.980785608291626)), Vector((3.2584136988589307e-07, 2.384185791015625e-07, -1.000000238418579)), Vector((0.19509072601795197, 2.384185791015625e-07, -0.9807854890823364)), Vector((0.38268381357192993, 2.384185791015625e-07, -0.923284649848938)), Vector((0.22629565000534058, 2.384185791015625e-07, -0.9575635194778442)), Vector((0.06365743279457092, 2.384185791015625e-07, -0.954291045665741)), Vector((-0.09898078441619873, 2.384185791015625e-07, -0.9143458008766174)), Vector((-0.2553688883781433, 2.384185791015625e-07, -0.8406103253364563)), Vector((-0.39949703216552734, 2.384185791015625e-07, -0.737377941608429)), Vector((-0.5258263349533081, 2.384185791015625e-07, -0.6102247834205627)), Vector((-0.6295021176338196, 2.384185791015625e-07, -0.465727299451828)), Vector((-0.7065401673316956, 2.682209014892578e-07, -0.3110540509223938)), Vector((-0.7539799809455872, 2.682209014892578e-07, -0.15349547564983368)), Vector((-0.7699984908103943, 2.84984679410627e-07, -1.378889180614351e-07)), Vector((-0.7539798617362976, 2.980232238769531e-07, 0.153495192527771)), Vector((-0.706540048122406, 3.2782554626464844e-07, 0.31105372309684753)), Vector((-0.6295021176338196, 2.980232238769531e-07, 0.4657267928123474)), Vector((-0.5258263349533081, 3.5762786865234375e-07, 0.6102243065834045)), Vector((-0.3994970917701721, 3.5762786865234375e-07, 0.737377405166626)), Vector((-0.25536900758743286, 3.5762786865234375e-07, 0.8406097292900085)), Vector((-0.09898099303245544, 3.5762786865234375e-07, 0.9143452048301697)), Vector((0.06365716457366943, 3.5762786865234375e-07, 0.9542905688285828)), Vector((0.22629405558109283, 3.5762786865234375e-07, 0.9575631022453308)), Vector((0.3826821446418762, 3.5762786865234375e-07, 0.9232847094535828)), Vector((0.19508881866931915, 3.5762786865234375e-07, 0.9807852506637573)), Vector((0.0, 3.5762786865234375e-07, 0.9999997019767761)) ] edges = [] for i in range(len(verts)): edges.append((i, i + 1)) edges[-1] = (0, len(verts) - 1) head_tail_vector = pbone.vector * head_tail verts = [(pbone.matrix * pbone.length).inverted() @ (pos + Vector(v) + head_tail_vector) * radius for v in verts] mesh = obj.data mesh.from_pydata(verts, edges, []) mesh.update()
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]