def process_edit(obj, spine_root_name):
    eb = obj.data.edit_bones
    org_hips = eb[spine_root_name]

    if MCH_HIPS not in eb:
        mch_hips = org_hips
        mch_hips.name = MCH_HIPS

        copy_bone_simple(obj, mch_hips.name, spine_root_name)

        org_hips = eb[spine_root_name]
        org_hips.use_deform = False

        for child in list(mch_hips.children):
            child.parent = org_hips

        mch_hips.layers = LAYER_MCH
        org_hips.parent = mch_hips
    else:
        mch_hips = eb[MCH_HIPS]

    org_thigh_l = midpoint_l = eb[ORG_THIGH+'L']
    org_thigh_r = midpoint_r = eb[ORG_THIGH+'R']
    #if ORG_PELVIS+'L' in eb:
    #    midpoint_l = eb[ORG_PELVIS+'L']
    #    midpoint_r = eb[ORG_PELVIS+'R']

    #midpoint = (Vector(midpoint_l.head) + Vector(midpoint_r.head))/2
    midpoint = mch_hips.head

    delta_l = get_or_create_mch(eb,MCH_DELTA+'L',mch_hips,org_thigh_l.head,midpoint)
    delta_r = get_or_create_mch(eb,MCH_DELTA+'R',mch_hips,org_thigh_r.head,midpoint)

    lencoeff = abs(midpoint[0] - org_thigh_l.head[0]) * 0.3

    ik_tgt = get_or_create_mch(eb,MCH_IK_TGT,delta_r,midpoint,midpoint+Vector((0,0,lencoeff)),True)

    end_l = midpoint + Vector((-lencoeff,0,org_thigh_l.length))
    leg_l_dist = get_or_create_mch(eb,MCH_IK_L_DIST,delta_l,midpoint,end_l,True)
    leg_l_dist.length = org_thigh_l.length
    leg_l_dist.use_inherit_scale = False
    align_bone_x_axis(obj, MCH_IK_L_DIST, Vector((1,0,0)))

    end_r = midpoint + Vector((2*(leg_l_dist.tail[0] - midpoint[0]),0,0))
    leg_r_dist = get_or_create_mch(eb,MCH_IK_R_DIST,leg_l_dist,leg_l_dist.tail,end_r,True)
    leg_r_dist.length = org_thigh_r.length
    leg_r_dist.use_inherit_scale = False
    align_bone_x_axis(obj, MCH_IK_R_DIST, Vector((1,0,0)))

    return {
        'pole_angle': pole_offset(leg_l_dist, leg_r_dist, leg_r_dist),
        'shin_length': eb['ORG-shin.L'].length,
        'thigh_length': org_thigh_l.length,
    }
    def create_pivot(self, pivot=None):
        """ Create the pivot control and mechanism bones """

        org_bones = self.org_bones

        bpy.ops.object.mode_set(mode='EDIT')
        eb = self.obj.data.edit_bones

        if not pivot:
            pivot = int(len(org_bones) / 2)

        pivot_name = org_bones[pivot]
        if '.L' in pivot_name:
            prefix = strip_org(org_bones[pivot]).split('.')[0] + '.L'
        elif '.R' in pivot_name:
            prefix = strip_org(org_bones[pivot]).split('.')[0] + '.R'
        else:
            prefix = strip_org(org_bones[pivot]).split('.')[0]

        ctrl_name = get_bone_name(prefix, 'ctrl', 'pivot')
        ctrl_name = copy_bone(self.obj, pivot_name, ctrl_name)
        ctrl_eb = eb[ctrl_name]

        self.orient_bone(ctrl_eb, 'y', self.spine_length / 2.5)

        pivot_loc = eb[pivot_name].head + (
            (eb[pivot_name].tail - eb[pivot_name].head) /
            2) * (len(org_bones) % 2)

        put_bone(self.obj, ctrl_name, pivot_loc)

        v = eb[org_bones[-1]].tail - eb[org_bones[
            0]].head  # Create a vector from head of first ORG to tail of last
        v.normalize()
        v_proj = eb[org_bones[0]].y_axis.dot(
            v) * v  # projection of first ORG to v
        v_point = eb[org_bones[
            0]].y_axis - v_proj  # a vector co-planar to first ORG and v directed out of the chain

        if v_point.magnitude < eb[org_bones[
                0]].y_axis.magnitude * 1e-03:  # if v_point is too small it's not usable
            v_point = eb[org_bones[0]].x_axis

        if self.params.tweak_axis == 'auto':
            align_bone_y_axis(self.obj, ctrl_name, v)
            align_bone_z_axis(self.obj, ctrl_name, -v_point)
        elif self.params.tweak_axis == 'x':
            align_bone_y_axis(self.obj, ctrl_name, Vector((1, 0, 0)))
            align_bone_x_axis(self.obj, ctrl_name, Vector((0, 0, 1)))
        elif self.params.tweak_axis == 'y':
            align_bone_y_axis(self.obj, ctrl_name, Vector((0, 1, 0)))
            align_bone_x_axis(self.obj, ctrl_name, Vector((1, 0, 0)))
        elif self.params.tweak_axis == 'z':
            align_bone_y_axis(self.obj, ctrl_name, Vector((0, 0, 1)))
            align_bone_x_axis(self.obj, ctrl_name, Vector((1, 0, 0)))

        return {'ctrl': ctrl_name}
Ejemplo n.º 3
0
    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]
Ejemplo n.º 4
0
    def generate(self):
        bpy.ops.object.mode_set(mode='EDIT')

        eb = self.obj.data.edit_bones

        # Create the control bones
        ulimb_ik = copy_bone(
            self.obj, self.org_bones[0],
            pantin_utils.strip_LR_numbers(strip_org(self.org_bones[0])) +
            '.IK' + self.side_suffix)
        flimb_ik = copy_bone(
            self.obj, self.org_bones[1],
            make_mechanism_name(
                pantin_utils.strip_LR_numbers(strip_org(self.org_bones[1])) +
                '.IK' + self.side_suffix))
        elimb_ik = copy_bone(
            self.obj, self.org_bones[2],
            pantin_utils.strip_LR_numbers(strip_org(self.org_bones[2])) +
            '.IK' + self.side_suffix)

        ulimb_str = copy_bone(
            self.obj, self.org_bones[0],
            make_mechanism_name(
                pantin_utils.strip_LR_numbers(strip_org(self.org_bones[0])) +
                ".stretch.ik" + self.side_suffix))
        flimb_str = copy_bone(
            self.obj, self.org_bones[1],
            make_mechanism_name(
                pantin_utils.strip_LR_numbers(strip_org(self.org_bones[1])) +
                ".stretch.ik" + self.side_suffix))
        elimb_str = copy_bone(
            self.obj, self.org_bones[2],
            make_mechanism_name(
                pantin_utils.strip_LR_numbers(strip_org(self.org_bones[2])) +
                ".stretch.ik" + self.side_suffix))

        joint_str = new_bone(
            self.obj,
            pantin_utils.strip_LR_numbers(strip_org(self.org_bones[1])) +
            '.IK' + self.side_suffix)
        eb[joint_str].head = eb[flimb_str].head
        eb[joint_str].tail = (eb[flimb_str].head + Vector(
            (0, 0, 1)) * eb[flimb_str].length / 2)
        align_bone_x_axis(self.obj, joint_str, Vector((-1, 0, 0)))
        # put_bone(self.obj, joint_str, Vector(eb[flimb_str].head))

        # Pelvis follow
        elimb_ik_root = copy_bone(
            self.obj, self.org_bones[2],
            make_mechanism_name(
                pantin_utils.strip_LR_numbers(strip_org(self.org_bones[2])) +
                ".ik_root" + self.side_suffix))
        elimb_ik_parent = copy_bone(
            self.obj, self.org_bones[2],
            make_mechanism_name(
                pantin_utils.strip_LR_numbers(strip_org(self.org_bones[2])) +
                ".ik_parent" + self.side_suffix))
        elimb_ik_socket = copy_bone(
            self.obj, self.org_bones[2],
            make_mechanism_name(
                pantin_utils.strip_LR_numbers(strip_org(self.org_bones[2])) +
                ".ik_socket" + self.side_suffix))

        # Get edit bones
        ulimb_ik_e = eb[ulimb_ik]
        flimb_ik_e = eb[flimb_ik]
        elimb_ik_e = eb[elimb_ik]

        ulimb_str_e = eb[ulimb_str]
        flimb_str_e = eb[flimb_str]
        elimb_str_e = eb[elimb_str]

        joint_str_e = eb[joint_str]

        elimb_ik_root_e = eb[elimb_ik_root]
        elimb_ik_parent_e = eb[elimb_ik_parent]
        elimb_ik_socket_e = eb[elimb_ik_socket]

        # Parenting

        # Side org chain
        for b, o_b in zip(self.side_org_bones[1:], self.org_bones[1:]):
            eb[b].parent = eb[
                pantin_utils.strip_LR_numbers(eb[o_b].parent.name) +
                self.side_suffix]

        if self.org_parent is not None:
            ulimb_ik_e.use_connect = False
            ulimb_ik_e.parent = eb[self.org_parent]

        flimb_ik_e.use_connect = False
        flimb_ik_e.parent = ulimb_ik_e

        elimb_ik_root_e.use_connect = False
        elimb_ik_root_e.parent = None
        elimb_ik_parent_e.use_connect = False
        elimb_ik_parent_e.parent = eb[self.side_org_bones[0]].parent
        elimb_ik_socket_e.use_connect = False
        elimb_ik_socket_e.parent = None
        elimb_ik_e.use_connect = False
        elimb_ik_e.parent = elimb_ik_socket_e

        if self.org_parent is not None:
            ulimb_str_e.use_connect = False
            ulimb_str_e.parent = eb[self.org_parent]

        flimb_str_e.use_connect = False
        flimb_str_e.parent = joint_str_e

        elimb_str_e.use_connect = True
        elimb_str_e.parent = flimb_ik_e

        joint_str_e.use_connect = False
        joint_str_e.parent = ulimb_ik_e

        # Layers
        joint_str_e.layers = elimb_str_e.layers
        # Object mode, get pose bones
        bpy.ops.object.mode_set(mode='OBJECT')
        pb = self.obj.pose.bones

        ulimb_ik_p = pb[ulimb_ik]
        flimb_ik_p = pb[flimb_ik]
        elimb_ik_p = pb[elimb_ik]

        ulimb_str_p = pb[ulimb_str]
        flimb_str_p = pb[flimb_str]
        elimb_str_p = pb[elimb_str]

        joint_str_p = pb[joint_str]

        joint_str_p.lock_location = (False, False, True)
        joint_str_p.lock_rotation = (True, True, False)
        joint_str_p.lock_rotation_w = False
        joint_str_p.lock_scale = (False, False, False)
        joint_str_p.rotation_mode = 'XZY'

        # Set up custom properties
        prop = rna_idprop_ui_prop_get(elimb_ik_p, "pelvis_follow", create=True)
        elimb_ik_p["pelvis_follow"] = int(self.pelvis_follow)
        prop["soft_min"] = 0
        prop["soft_max"] = 1
        prop["min"] = 0
        prop["max"] = 1

        prop = rna_idprop_ui_prop_get(elimb_ik_p, "IK_FK", create=True)
        elimb_ik_p["IK_FK"] = 0
        prop["soft_min"] = 0
        prop["soft_max"] = 1
        prop["min"] = 0
        prop["max"] = 1

        # Constraints
        # Bend hint, ripped off from Rigify' biped
        con = flimb_ik_p.constraints.new('LIMIT_ROTATION')
        con.name = "bend_hint"
        con.use_limit_z = True
        con.min_z = radians(45)
        con.max_z = radians(45)
        con.owner_space = 'LOCAL'

        con = flimb_ik_p.constraints.new('IK')
        con.name = "ik"
        con.target = self.obj
        con.subtarget = elimb_ik
        con.chain_count = 2

        con = ulimb_str_p.constraints.new('COPY_LOCATION')
        con.name = "anchor"
        con.target = self.obj
        con.subtarget = ulimb_ik
        con.target_space = 'LOCAL'
        con.owner_space = 'LOCAL'

        con = elimb_str_p.constraints.new('COPY_ROTATION')
        con.name = "copy rotation"
        con.target = self.obj
        con.subtarget = elimb_ik
        con.target_space = 'POSE'
        con.owner_space = 'POSE'

        con = ulimb_str_p.constraints.new('STRETCH_TO')
        con.name = "stretch to"
        con.target = self.obj
        con.subtarget = joint_str
        con.volume = 'NO_VOLUME'
        con.rest_length = ulimb_str_p.length
        con.keep_axis = 'PLANE_Z'

        con = flimb_str_p.constraints.new('STRETCH_TO')
        con.name = "stretch to"
        con.target = self.obj
        con.subtarget = elimb_str
        con.volume = 'NO_VOLUME'
        con.rest_length = flimb_str_p.length
        con.keep_axis = 'PLANE_Z'

        # Pelvis follow
        con = pb[elimb_ik_socket].constraints.new('COPY_TRANSFORMS')
        con.name = "copy root"
        con.target = self.obj
        con.subtarget = elimb_ik_root

        con = pb[elimb_ik_socket].constraints.new('COPY_TRANSFORMS')
        con.name = "copy socket"
        con.target = self.obj
        con.subtarget = elimb_ik_parent

        # Drivers
        driver = self.obj.driver_add(con.path_from_id("influence"))
        driver.driver.expression = 'pelvis_follow'
        var = driver.driver.variables.new()

        var.type = 'SINGLE_PROP'
        var.name = 'pelvis_follow'
        var.targets[0].id_type = 'OBJECT'
        var.targets[0].id = self.obj
        var.targets[0].data_path = (pb[elimb_ik].path_from_id() +
                                    '["pelvis_follow"]')

        # IK Limits
        ulimb_ik_p.lock_ik_x = True
        ulimb_ik_p.lock_ik_y = True

        flimb_ik_p.lock_ik_x = True
        flimb_ik_p.lock_ik_y = True
        flimb_ik_p.use_ik_limit_z = True
        flimb_ik_p.ik_min_z = radians(self.ik_limits[0])  # 0.0
        flimb_ik_p.ik_max_z = radians(self.ik_limits[1])  # radians(160.0)

        # Arm ik angle fix
        limb_angle = ulimb_ik_p.vector.xz.angle_signed(flimb_ik_p.vector.xz)
        if self.ik_limits[0] < 0:  # folds counterclockwise (arms)
            # has to be slightly less than the original angle
            flimb_ik_p.ik_max_z = -limb_angle - .02
        else:
            # has to be slightly more than the original angle
            flimb_ik_p.ik_min_z = -limb_angle + .02

        return [
            ulimb_ik, ulimb_str, flimb_ik, flimb_str, joint_str, elimb_ik,
            elimb_str
        ]
Ejemplo n.º 5
0
    def generate(self):
        bpy.ops.object.mode_set(mode='EDIT')

        ctrl_chain = []

        eb = self.obj.data.edit_bones

        # Control bones
        # Global control
        ctrl_g = copy_bone(self.obj, self.mouth, strip_org(self.mouth))
        ctrl_g_eb = eb[ctrl_g]
        ctrl_chain.append(ctrl_g)
        if self.org_parent is not None:
            ctrl_g_eb.use_connect = False
            ctrl_g_eb.parent = eb[self.org_parent]

        # Right control
        ctrl_r_name = strip_org(self.ur.split('_')[0] + '.R')
        ctrl_r = new_bone(self.obj, ctrl_r_name)
        eb[ctrl_r].head = eb[self.ur].head
        eb[ctrl_r].tail = eb[self.ur].head + Vector(
            (0, 0, 1)) * eb[self.ur].length

        # Left control
        ctrl_l_name = strip_org(self.ul.split('_')[0] + '.L')
        ctrl_l = new_bone(self.obj, ctrl_l_name)
        eb[ctrl_l].head = eb[self.ul].tail
        eb[ctrl_l].tail = eb[self.ul].tail + Vector(
            (0, 0, 1)) * eb[self.ul].length

        # Up control
        ctrl_uc_name = strip_org(self.uc)
        ctrl_uc = new_bone(self.obj, ctrl_uc_name)
        eb[ctrl_uc].head = (eb[self.uc].head + eb[self.uc].tail) / 2
        eb[ctrl_uc].tail = eb[ctrl_uc].head + Vector(
            (0, 0, 1)) * eb[self.uc].length

        # Down control
        ctrl_lc_name = strip_org(self.lc)
        ctrl_lc = new_bone(self.obj, ctrl_lc_name)
        eb[ctrl_lc].head = (eb[self.lc].head + eb[self.lc].tail) / 2
        eb[ctrl_lc].tail = eb[ctrl_lc].head + Vector(
            (0, 0, 1)) * eb[self.lc].length

        for b in [ctrl_r, ctrl_uc, ctrl_lc, ctrl_l]:
            align_bone_x_axis(self.obj, b, Vector((-1, 0, 0)))
            eb[b].layers = eb[self.lc].layers
            eb[b].parent = eb[self.mouth]
            ctrl_chain.append(b)

        bpy.ops.object.mode_set(mode='OBJECT')
        pb = self.obj.pose.bones
        for b in [ctrl_r, ctrl_uc, ctrl_lc, ctrl_l]:
            pb[b].lock_location = (False, False, True)
            pb[b].lock_rotation = (True, True, False)
            pb[b].lock_rotation_w = False
            pb[b].lock_scale = (False, False, False)
            pb[b].rotation_mode = 'XZY'
        bpy.ops.object.mode_set(mode='EDIT')
        eb = self.obj.data.edit_bones

        # Stretch
        # RIGHT
        stretch_r_chain = []
        for bone in [self.ur, self.lr]:
            mch_b = copy_bone(
                self.obj, bone,
                pantin_utils.strip_LR(make_mechanism_name(strip_org(bone))) +
                '.stretch.R')
            mch_eb = eb[mch_b]
            mch_eb.parent = eb[ctrl_r]
            stretch_r_chain.append(mch_b)

        # CENTER
        stretch_c_chain = []
        for bone in [self.uc, self.lc]:
            mch_b = copy_bone(
                self.obj, bone,
                pantin_utils.strip_LR(make_mechanism_name(strip_org(bone))) +
                '.stretch')
            mch_eb = eb[mch_b]
            mch_eb.use_connect = False
            mch_eb.parent = eb[strip_org(bone)]
            stretch_c_chain.append(mch_b)

        #LEFT
        stretch_l_chain = []
        for i, bone in enumerate([self.ul, self.ll]):
            mch_b = copy_bone(
                self.obj, bone,
                pantin_utils.strip_LR(make_mechanism_name(strip_org(bone))) +
                '.stretch.L')
            mch_eb = eb[mch_b]
            mch_eb.parent = eb[stretch_c_chain[i]]
            stretch_l_chain.append(mch_b)

        # Def bones
        Z_index = self.params.Z_index
        for i, b in enumerate([
                self.mouth,
                stretch_l_chain[1],
                stretch_r_chain[1],
                stretch_c_chain[1],
                stretch_l_chain[0],
                stretch_r_chain[0],
                stretch_c_chain[0],
        ]):
            def_bone_name = b.split('.')[0][4:]
            if b[-1] in ('L', 'R'):
                def_bone_name += '.' + b[-1]
            def_bone = pantin_utils.create_deformation(self.obj,
                                                       b,
                                                       member_index=Z_index,
                                                       bone_index=i,
                                                       new_name=def_bone_name)
            if b == stretch_c_chain[1]:
                pantin_utils.create_deformation(
                    self.obj,
                    b,
                    member_index=Z_index,
                    bone_index=i + 1,
                    new_name=strip_org(self.org_bones[0]) + '_int')

        bpy.ops.object.mode_set(mode='OBJECT')
        pb = self.obj.pose.bones

        # Widgets
        wgt_radius = pb[ctrl_uc].length / 3
        for b in [ctrl_r, ctrl_l, ctrl_uc, ctrl_lc]:
            pantin_utils.create_aligned_circle_widget(self.obj,
                                                      b,
                                                      radius=wgt_radius)
        pantin_utils.create_aligned_circle_widget(self.obj,
                                                  ctrl_g,
                                                  radius=pb[ctrl_g].length,
                                                  head_tail=0.0,
                                                  width_ratio=2.0)

        # Constraints
        for src_b, target_b in zip(stretch_r_chain, stretch_c_chain):
            mch_pb = pb[src_b]
            con = mch_pb.constraints.new('STRETCH_TO')
            con.name = "stretch to"
            con.target = self.obj
            con.subtarget = target_b
            con.volume = 'NO_VOLUME'
            con.rest_length = mch_pb.length
            con.keep_axis = 'PLANE_Z'
        for src_b in stretch_l_chain:
            mch_pb = pb[src_b]
            con = mch_pb.constraints.new('STRETCH_TO')
            con.name = "stretch to"
            con.target = self.obj
            con.subtarget = ctrl_l
            con.volume = 'NO_VOLUME'
            con.rest_length = mch_pb.length
            con.keep_axis = 'PLANE_Z'

        for org, ctrl in zip(self.org_bones, [ctrl_g] + stretch_r_chain +
                             stretch_c_chain + stretch_l_chain):
            con = pb[org].constraints.new('COPY_TRANSFORMS')
            con.name = "copy_transforms"
            con.target = self.obj
            con.subtarget = ctrl

        return {
            'imports': UI_IMPORTS,
            'utilities': PANTIN_UTILS,
            'register': PANTIN_REGISTER,
            'register_props': REGISTER_PANTIN_PROPS,
        }
Ejemplo n.º 6
0
    def generate(self):
        ui_script = ""
        for s, limb in self.sides.items():
            side_org_bones, ik_limb, fk_limb = limb
            (ulimb_ik, ulimb_str, flimb_ik, flimb_str, joint_str, elimb_ik,
             elimb_str) = ik_limb.generate()

            ulimb_fk, flimb_fk, elimb_fk = fk_limb.generate()

            bpy.ops.object.mode_set(mode='EDIT')
            eb = self.obj.data.edit_bones

            # Foot rig
            foot_fr = copy_bone(
                self.obj, self.org_bones[2],
                pantin_utils.strip_LR_numbers(
                    make_mechanism_name(strip_org(self.org_bones[2]))) +
                '.fr' + s)
            foot_tgt = copy_bone(
                self.obj, self.org_bones[2],
                pantin_utils.strip_LR_numbers(
                    make_mechanism_name(strip_org(self.org_bones[2]))) +
                '.tgt' + s)
            heel_fr = copy_bone(
                self.obj, self.org_bones[3],
                pantin_utils.strip_LR_numbers(
                    make_mechanism_name(strip_org(self.org_bones[3]))) +
                '.fr' + s)
            toe_fr = copy_bone(
                self.obj, self.org_bones[4],
                pantin_utils.strip_LR_numbers(
                    make_mechanism_name(strip_org(self.org_bones[4]))) +
                '.fr' + s)
            toe_ik_ctl = copy_bone(
                self.obj, self.org_bones[4],
                pantin_utils.strip_LR_numbers(strip_org(self.org_bones[4])) +
                '.IK' + s)
            toe_fk_ctl = copy_bone(
                self.obj, self.org_bones[4],
                pantin_utils.strip_LR_numbers(strip_org(self.org_bones[4])) +
                '.FK' + s)
            toe_pos = copy_bone(
                self.obj, self.org_bones[4],
                pantin_utils.strip_LR_numbers(
                    make_mechanism_name(strip_org(self.org_bones[4]))) +
                '.pos' + s)
            roll_fr = new_bone(self.obj, "Foot roll" + s)

            # Position
            eb[roll_fr].head = (eb[elimb_str].head + Vector(
                (-1, 0, 0)) * eb[elimb_str].length * 2)
            eb[roll_fr].tail = (eb[elimb_str].head + Vector(
                (-1, 0, 1)) * eb[elimb_str].length * 2)
            eb[roll_fr].layers = eb[elimb_ik].layers

            # IK foot horizontal and starting at heel
            eb[elimb_ik].head = eb[heel_fr].tail
            eb[elimb_ik].tail.z = eb[heel_fr].tail.z
            align_bone_x_axis(self.obj, elimb_ik, Vector((0, 0, 1)))

            align_bone_x_axis(self.obj, roll_fr, Vector((-1, 0, 0)))
            align_bone_x_axis(self.obj, foot_fr, Vector((-1, 0, 0)))
            align_bone_x_axis(self.obj, heel_fr, Vector((-1, 0, 0)))
            align_bone_x_axis(self.obj, toe_fr, Vector((-1, 0, 0)))

            # Parenting
            eb[foot_fr].parent = None
            eb[heel_fr].parent = None
            eb[toe_fr].parent = None

            flip_bone(self.obj, foot_fr)
            flip_bone(self.obj, heel_fr)
            flip_bone(self.obj, toe_fr)

            eb[foot_fr].use_connect = True
            eb[foot_fr].parent = eb[toe_fr]

            eb[foot_tgt].use_connect = True
            eb[foot_tgt].parent = eb[foot_fr]

            eb[toe_fr].use_connect = False
            eb[toe_fr].parent = eb[heel_fr]

            eb[toe_ik_ctl].use_connect = True
            eb[toe_ik_ctl].parent = eb[toe_fr]

            eb[toe_fk_ctl].use_connect = True
            eb[toe_fk_ctl].parent = eb[elimb_fk]

            eb[toe_pos].use_connect = False
            eb[toe_pos].parent = eb[elimb_str]

            eb[heel_fr].use_connect = False
            eb[heel_fr].parent = eb[elimb_ik]

            eb[roll_fr].use_connect = False
            eb[roll_fr].parent = eb[elimb_ik]

            if self.params.do_stretch:
                eb[elimb_str].use_connect = False

            # Def bones
            if s == '.L':
                Z_index = -self.params.Z_index
            else:
                Z_index = self.params.Z_index

            side_org_bones = side_org_bones[:3] + side_org_bones[
                -1:]  # Ignore heel
            for i, b in enumerate(side_org_bones):
                def_bone_name = pantin_utils.strip_LR_numbers(strip_org(b))
                def_bone = pantin_utils.create_deformation(
                    self.obj,
                    b,
                    member_index=Z_index,
                    bone_index=i,
                    new_name=def_bone_name + s)

            # Set layers if specified
            active_layer = pantin_utils.layers_to_index(eb[ulimb_ik].layers)
            right_offset = self.params.right_offset if self.params.duplicate_lr else 0
            if s == '.R':
                for b in (ulimb_ik, joint_str, elimb_ik, roll_fr, toe_ik_ctl):
                    eb[b].layers = get_layers(active_layer + right_offset)
                for b in (ulimb_fk, flimb_fk, elimb_fk, toe_fk_ctl):
                    eb[b].layers = get_layers(active_layer +
                                              self.params.fk_offset +
                                              right_offset)
            elif s == '.L':
                for b in (ulimb_fk, flimb_fk, elimb_fk, toe_fk_ctl):
                    eb[b].layers = get_layers(active_layer +
                                              self.params.fk_offset)

            bpy.ops.object.mode_set(mode='OBJECT')
            pb = self.obj.pose.bones

            # Bone settings
            pb[roll_fr].rotation_mode = 'XZY'
            pb[roll_fr].lock_location = [True] * 3
            pb[roll_fr].lock_rotation = [True, True, False]
            pb[roll_fr].lock_scale = [True] * 3
            pb[foot_fr].rotation_mode = 'XZY'

            # Widgets
            # IK
            global_scale = self.obj.dimensions[2]
            member_factor = 0.06
            if s == '.R':
                side_factor = 1.2
            else:
                side_factor = 1.0
            widget_size = global_scale * member_factor * side_factor
            pantin_utils.create_aligned_circle_widget(self.obj,
                                                      ulimb_ik,
                                                      number_verts=3,
                                                      radius=widget_size)
            pantin_utils.create_aligned_circle_widget(self.obj,
                                                      joint_str,
                                                      radius=widget_size)

            # FK
            widget_size = 0.5
            for bone in (ulimb_fk, flimb_fk, elimb_fk, toe_fk_ctl):
                pantin_utils.create_capsule_widget(self.obj,
                                                   bone,
                                                   length=widget_size,
                                                   width=widget_size * 0.2,
                                                   head_tail=0.5,
                                                   horizontal=False,
                                                   overshoot=True)

                # Default follow value
                pb[ulimb_fk]["follow"] = 0.0

            # Foot WGT
            down = pb[heel_fr].head.z
            left = pb[heel_fr].head.x - (side_factor - 1) * pb[heel_fr].length
            right = pb[foot_fr].head.x
            up = pb[foot_fr].tail.z + (side_factor - 1) * pb[heel_fr].length

            foot_verts = ((left, down), (left, up),
                          (right, down + (up - down) * 2 / 3), (right, down))
            pantin_utils.create_aligned_polygon_widget(self.obj, elimb_ik,
                                                       foot_verts)

            # Toe WGT
            left = right
            right = pb[toe_fr].head.x + (side_factor - 1) * pb[heel_fr].length
            up = down + (up - down) * 2 / 3

            # TODO investigate why moving an edit bones
            # screws up widgets' matrices (foot_ik has moved)
            toe_verts = ((left, down), (left, up),
                         (right, down + (up - down) * 2 / 3), (right, down))
            pantin_utils.create_aligned_polygon_widget(self.obj, toe_ik_ctl,
                                                       toe_verts)

            pantin_utils.create_aligned_crescent_widget(self.obj,
                                                        roll_fr,
                                                        radius=side_factor *
                                                        pb[roll_fr].length / 2)

            # Constraints
            foot_fr_p = pb[foot_fr]
            heel_fr_p = pb[heel_fr]
            toe_fr_p = pb[toe_fr]
            roll_fr_p = pb[roll_fr]

            hor_vector = Vector((1, 0, 0))
            foot_rotation = (foot_fr_p.vector.rotation_difference(
                hor_vector).to_euler('XZY'))
            toe_rotation = toe_fr_p.vector.rotation_difference(
                hor_vector).to_euler('XZY')

            foot_vertical_rot = foot_rotation[1] - pi / 2
            toe_vertical_rot = toe_rotation[1] - pi / 2

            con = foot_fr_p.constraints.new('TRANSFORM')
            con.name = "roll"
            con.target = self.obj
            con.subtarget = roll_fr
            con.map_from = 'ROTATION'
            con.map_to = 'ROTATION'
            con.from_min_z_rot = radians(0.0)
            con.from_max_z_rot = radians(60.0)
            con.to_min_z_rot = radians(0.0)
            con.to_max_z_rot = foot_vertical_rot
            con.target_space = 'LOCAL'
            con.owner_space = 'LOCAL'

            con = heel_fr_p.constraints.new('TRANSFORM')
            con.name = "roll"
            con.target = self.obj
            con.subtarget = roll_fr
            con.map_from = 'ROTATION'
            con.map_to = 'ROTATION'
            con.from_min_z_rot = radians(-60.0)
            con.from_max_z_rot = 0.0
            con.to_min_z_rot = radians(-60.0)
            con.to_max_z_rot = 0.0
            con.target_space = 'LOCAL'
            con.owner_space = 'LOCAL'

            con = toe_fr_p.constraints.new('TRANSFORM')
            con.name = "roll"
            con.target = self.obj
            con.subtarget = roll_fr
            con.map_from = 'ROTATION'
            con.map_to = 'ROTATION'
            con.from_min_z_rot = radians(60.0)
            con.from_max_z_rot = radians(90.0)
            con.to_min_z_rot = radians(0.0)
            con.to_max_z_rot = toe_vertical_rot
            con.target_space = 'LOCAL'
            con.owner_space = 'LOCAL'

            # Compensate foot for heel
            con = foot_fr_p.constraints.new('TRANSFORM')
            con.name = "roll_compensate"
            con.target = self.obj
            con.subtarget = roll_fr
            con.map_from = 'ROTATION'
            con.map_to = 'ROTATION'
            con.from_min_z_rot = radians(60.0)
            con.from_max_z_rot = radians(90.0)
            con.to_min_z_rot = radians(0.0)
            con.to_max_z_rot = -toe_vertical_rot
            con.target_space = 'LOCAL'
            con.owner_space = 'LOCAL'

            # Roll limits
            con = roll_fr_p.constraints.new('LIMIT_ROTATION')
            con.name = "limit rotation"
            con.use_limit_z = True
            con.min_z = radians(-60.0)
            con.max_z = radians(90.0)
            con.owner_space = 'LOCAL'

            # Edit IK to follow the rolled foot instead of ik control
            con = pb[flimb_ik].constraints["ik"]
            con.subtarget = foot_tgt
            con = pb[elimb_str].constraints["copy rotation"]
            con.subtarget = foot_tgt

            con = pb[toe_pos].constraints.new('COPY_ROTATION')
            con.name = "copy rotation"
            con.target = self.obj
            con.subtarget = toe_ik_ctl
            #con.invert_x = True
            con.target_space = 'POSE'
            con.owner_space = 'POSE'

            # Optional stretch to the foot
            if self.params.do_stretch:
                con1 = pb[flimb_str].constraints.new('STRETCH_TO')
                con1.name = "stretch to foot"
                con1.target = self.obj
                con1.subtarget = foot_tgt
                con1.volume = 'NO_VOLUME'
                con1.rest_length = pb[flimb_str].length
                con1.keep_axis = 'PLANE_Z'

                con2 = pb[elimb_str].constraints.new('COPY_LOCATION')
                con2.name = "copy foot location"
                con2.target = self.obj
                con2.subtarget = foot_tgt
                con2.target_space = 'POSE'
                con2.owner_space = 'POSE'

                # Set up custom properties
                prop = rna_idprop_ui_prop_get(pb[elimb_ik],
                                              "foot_stretch",
                                              create=True)
                pb[elimb_ik]["foot_stretch"] = 1  # int(self.foot_stretch)
                prop["soft_min"] = 0
                prop["soft_max"] = 1
                prop["min"] = 0
                prop["max"] = 1

                # Drivers
                for c in (con1, con2):
                    driver = self.obj.driver_add(c.path_from_id("influence"))
                    driver.driver.expression = 'foot_stretch'
                    var_fs = driver.driver.variables.new()

                    var_fs.type = 'SINGLE_PROP'
                    var_fs.name = 'foot_stretch'
                    var_fs.targets[0].id_type = 'OBJECT'
                    var_fs.targets[0].id = self.obj
                    var_fs.targets[0].data_path = (
                        pb[elimb_ik].path_from_id() + '["foot_stretch"]')

            for org, ctrl in zip(
                    side_org_bones,
                [ulimb_str, flimb_str, elimb_str, toe_ik_ctl]):
                con = pb[org].constraints.new('COPY_TRANSFORMS')
                con.name = "copy_ik"
                con.target = self.obj
                con.subtarget = ctrl

            for org, ctrl in zip(side_org_bones,
                                 [ulimb_fk, flimb_fk, elimb_fk, toe_fk_ctl]):
                con = pb[org].constraints.new('COPY_TRANSFORMS')
                con.name = "copy_fk"
                con.target = self.obj
                con.subtarget = ctrl

                # Drivers
                driver = self.obj.driver_add(con.path_from_id("influence"))
                driver.driver.expression = 'fk'
                var_fk = driver.driver.variables.new()
                var_fk.type = 'SINGLE_PROP'
                var_fk.name = 'fk'
                var_fk.targets[0].id_type = 'OBJECT'
                var_fk.targets[0].id = self.obj
                var_fk.targets[
                    0].data_path = 'pose.bones["{}"]["IK_FK"]'.format(elimb_ik)

            ui_script += UI_PANTIN_LIMB_SCRIPT % (
                '"{}", "{}", "{}", "{}"'.format(
                    ulimb_ik, joint_str, elimb_ik,
                    toe_ik_ctl), '"{}", "{}", "{}", "{}"'.format(
                        ulimb_fk, flimb_fk, elimb_fk, toe_fk_ctl))

            if self.params.do_stretch:
                ui_script += """    layout.prop(pose_bones[ik_leg[2]], \
'["foot_stretch"]', \
text="Foot stretch (" + ik_leg[2] + ")", slider=True)
    """

        return {
            'script': [ui_script],
            'imports': UI_IMPORTS,
            'utilities': PANTIN_UTILS + [UTILITIES_PANTIN_LIMBS],
            'register': PANTIN_REGISTER + REGISTER_PANTIN_LIMBS,
            'register_props': REGISTER_PANTIN_PROPS,
        }
    def create_chain(self):
        org_bones = self.org_bones

        bpy.ops.object.mode_set(mode='EDIT')
        eb = self.obj.data.edit_bones

        twk, mch, mch_ctrl, ctrl = [], [], [], []

        suffix = ''
        if '.L' in org_bones[0]:
            suffix = '.L'
        elif '.R' in org_bones[0]:
            suffix = '.R'

        mch_auto = ''
        if not self.SINGLE_BONE:
            mch_name = copy_bone(
                self.obj, org(org_bones[0]),
                'MCH-AUTO-' + strip_org(org_bones[0]).split('.')[0] + suffix)
            eb[mch_name].head = eb[org_bones[0]].head
            eb[mch_name].tail = eb[org_bones[-1]].tail

            mch_auto = mch_name

        # Intermediary bones
        for b in org_bones:  # All

            if self.SINGLE_BONE:
                mch_name = copy_bone(self.obj, org(b),
                                     make_mechanism_name(strip_org(b)))
                eb[mch_name].length /= 4
                put_bone(self.obj, mch_name,
                         eb[b].head - (eb[mch_name].tail - eb[mch_name].head))
                align_bone_z_axis(self.obj, mch_name, eb[b].z_axis)
                mch += [mch_name]
                mch_name = copy_bone(self.obj, org(b),
                                     make_mechanism_name(strip_org(b)))
                eb[mch_name].length /= 4
                put_bone(self.obj, mch_name, eb[b].tail)
                mch += [mch_name]
                break
            else:
                mch_name = copy_bone(self.obj, org(b),
                                     make_mechanism_name(strip_org(b)))
                eb[mch_name].length /= 4

                mch += [mch_name]

                if b == org_bones[-1]:  # Add extra
                    mch_name = copy_bone(self.obj, org(b),
                                         make_mechanism_name(strip_org(b)))
                    eb[mch_name].length /= 4
                    put_bone(self.obj, mch_name, eb[b].tail)
                    mch += [mch_name]

        # Tweak & Ctrl bones
        v = eb[org_bones[-1]].tail - eb[org_bones[
            0]].head  # Create a vector from head of first ORG to tail of last
        v.normalize()
        v_proj = eb[org_bones[0]].y_axis.dot(
            v) * v  # projection of first ORG to v
        v_point = eb[org_bones[
            0]].y_axis - v_proj  # a vector co-planar to first ORG and v directed out of the chain

        if v_point.magnitude < eb[org_bones[0]].y_axis.magnitude * 1e-03:
            v_point = eb[org_bones[0]].x_axis

        for b in org_bones:  # All

            suffix = ''
            if '.L' in b:
                suffix = '.L'
            elif '.R' in b:
                suffix = '.R'

            if b == org_bones[0]:
                name = get_bone_name(b.split('.')[0] + suffix, 'ctrl', 'ctrl')
                if self.params.use_parent_ctrls:
                    name = make_mechanism_name(name)
                name = copy_bone(self.obj, org(b), name)
                align_bone_x_axis(self.obj, name, eb[org(b)].x_axis)
                ctrl += [name]
            else:
                name = 'tweak_' + strip_org(b)
                name = copy_bone(self.obj, org(b), name)
                twk += [name]

            self.orient_bone(eb[name], 'y', eb[name].length / 2)

            if self.params.tweak_axis == 'auto':
                align_bone_y_axis(self.obj, name, v)
                align_bone_z_axis(self.obj, name, -v_point)  # invert?
            elif self.params.tweak_axis == 'x':
                align_bone_y_axis(self.obj, name, Vector((1, 0, 0)))
                align_bone_x_axis(self.obj, name, Vector((0, 0, 1)))
            elif self.params.tweak_axis == 'y':
                align_bone_y_axis(self.obj, name, Vector((0, 1, 0)))
                align_bone_x_axis(self.obj, name, Vector((1, 0, 0)))
            elif self.params.tweak_axis == 'z':
                align_bone_y_axis(self.obj, name, Vector((0, 0, 1)))
                align_bone_x_axis(self.obj, name, Vector((1, 0, 0)))

            if b == org_bones[-1]:  # Add extra
                ctrl_name = get_bone_name(
                    b.split('.')[0] + suffix, 'ctrl', 'ctrl')
                if self.params.use_parent_ctrls:
                    ctrl_name = make_mechanism_name(ctrl_name)
                ctrl_name = copy_bone(self.obj, org(b), ctrl_name)

                self.orient_bone(eb[ctrl_name], 'y', eb[ctrl_name].length / 2)

                if self.params.conv_bone:
                    align_bone_y_axis(self.obj, ctrl_name,
                                      eb[org(self.params.conv_bone)].y_axis)
                    align_bone_x_axis(self.obj, ctrl_name,
                                      eb[org(self.params.conv_bone)].x_axis)
                    align_bone_z_axis(self.obj, ctrl_name,
                                      eb[org(self.params.conv_bone)].z_axis)

                else:
                    if twk:
                        lastname = twk[-1]
                    else:
                        lastname = ctrl[-1]
                    align_bone_y_axis(self.obj, ctrl_name, eb[lastname].y_axis)
                    align_bone_x_axis(self.obj, ctrl_name, eb[lastname].x_axis)
                put_bone(self.obj, ctrl_name, eb[b].tail)

                ctrl += [ctrl_name]

        conv_twk = ''
        # Convergence tweak
        if self.params.conv_bone:
            conv_twk = 'tweak_' + strip_org(self.params.conv_bone)

            if not (conv_twk in eb.keys()):
                conv_twk = copy_bone(self.obj, org(self.params.conv_bone),
                                     conv_twk)

        for b in org_bones:

            if self.SINGLE_BONE:
                break

            # Mch controls
            suffix = ''
            if '.L' in b:
                suffix = '.L'
            elif '.R' in b:
                suffix = '.R'

            mch_ctrl_name = "MCH-CTRL-" + strip_org(b).split('.')[0] + suffix
            mch_ctrl_name = copy_bone(self.obj, twk[0] if twk else ctrl[0],
                                      mch_ctrl_name)

            eb[mch_ctrl_name].length /= 6

            put_bone(self.obj, mch_ctrl_name, eb[b].head)

            mch_ctrl += [mch_ctrl_name]

            if b == org_bones[-1]:  # Add extra
                mch_ctrl_name = "MCH-CTRL-" + strip_org(b).split(
                    '.')[0] + suffix
                mch_ctrl_name = copy_bone(self.obj, twk[0] if twk else ctrl[0],
                                          mch_ctrl_name)

                eb[mch_ctrl_name].length /= 6

                put_bone(self.obj, mch_ctrl_name, eb[b].tail)

                mch_ctrl += [mch_ctrl_name]

        return {
            'mch': mch,
            'mch_ctrl': mch_ctrl,
            'mch_auto': mch_auto,
            'tweak': twk,
            'ctrl': ctrl,
            'conv': conv_twk
        }