def create_mch(self):

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

        super().create_mch()

        self.bones['tail_mch'] = {}

        org_chain = self.get_chain_bones(self.base_bone)

        if edit_bones[org_chain[0]].parent:
            bone_to_copy = edit_bones[org_chain[0]].parent.name
        else:
            bone_to_copy = self.orientation_bone

        mch_rot_tail = make_mechanism_name('ROT-' + strip_org(self.base_bone))
        mch_rot_tail = copy_bone(self.obj,
                                 bone_to_copy,
                                 assign_name=mch_rot_tail)
        self.bones['tail_mch']['rot_tail_mch'] = mch_rot_tail
        main_chain = self.get_chain_bones(self.base_bone)
        flip_bone(self.obj, mch_rot_tail)
        edit_bones[mch_rot_tail].parent = None
        put_bone(self.obj, mch_rot_tail, edit_bones[main_chain[0]].head)
    def create_def(self):
        super().create_def()

        chain = strip_org(self.base_bone)

        for def_bone in self.bones['def'][chain]:
            flip_bone(self.obj, def_bone)

        self.bones['def'][chain].reverse()
Exemple #3
0
    def create_controls(self):
        bpy.ops.object.mode_set(mode='EDIT')
        edit_bones = self.obj.data.edit_bones

        super().create_controls()

        self.bones['tongue_ctrl'] = {}

        tongue_master_name = strip_org(self.base_bone) + '_master'
        tongue_master_name = copy_bone(self.obj, self.base_bone, assign_name=tongue_master_name)
        flip_bone(self.obj, tongue_master_name)
        self.bones['tongue_ctrl']['tongue_master'] = tongue_master_name
Exemple #4
0
    def create_mch(self):
        bpy.ops.object.mode_set(mode='EDIT')
        edit_bones = self.obj.data.edit_bones

        super().create_mch()

        self.bones['tongue_mch'] = {}
        self.bones['tongue_mch']['tongue_tip'] = []

        for i, mch in enumerate(self.bones['mch'][strip_org(self.base_bone)][:-1]):
            if i == 0:
                edit_bones[mch].length = edit_bones[self.base_bone].length
                flip_bone(self.obj, mch)
                self.bones['tongue_mch']['tongue_tip'].append(mch)
            else:
                put_bone(self.obj, mch, edit_bones[self.base_bone].tail)
                edit_bones[mch].tail = edit_bones[self.base_bone].head
                self.bones['tongue_mch']['tongue_tip'].append(mch)
Exemple #5
0
    def gen_control(self):
        """ Generate the control rig.

        """
        bpy.ops.object.mode_set(mode='EDIT')
        eb = self.obj.data.edit_bones
        #-------------------------
        # Get rest slide position
        a = self.pivot_rest * len(self.org_bones)
        i = floor(a)
        a -= i
        if i == len(self.org_bones):
            i -= 1
            a = 1.0

        pivot_rest_pos = eb[self.org_bones[i]].head.copy()
        pivot_rest_pos += eb[self.org_bones[i]].vector * a

        #----------------------
        # Create controls

        # Create control bones
        controls = []
        for i in self.control_indices:
            name = copy_bone(self.obj, self.org_bones[i],
                             strip_org(self.org_bones[i]))
            controls += [name]

        # Create control parents
        control_parents = []
        for i in self.control_indices[1:-1]:
            name = new_bone(
                self.obj,
                make_mechanism_name("par_" + strip_org(self.org_bones[i])))
            control_parents += [name]

        # Create sub-control bones
        subcontrols = []
        for i in self.control_indices:
            name = new_bone(
                self.obj,
                make_mechanism_name("sub_" + strip_org(self.org_bones[i])))
            subcontrols += [name]

        # Create main control bone
        main_control = new_bone(self.obj, self.params.spine_main_control_name)

        # Create main control WGT bones
        main_wgt1 = new_bone(
            self.obj,
            make_mechanism_name(self.params.spine_main_control_name + ".01"))
        main_wgt2 = new_bone(
            self.obj,
            make_mechanism_name(self.params.spine_main_control_name + ".02"))

        eb = self.obj.data.edit_bones

        # Parent the main control
        eb[main_control].use_connect = False
        eb[main_control].parent = eb[self.org_bones[0]].parent

        # Parent the main WGTs
        eb[main_wgt1].use_connect = False
        eb[main_wgt1].parent = eb[main_control]
        eb[main_wgt2].use_connect = False
        eb[main_wgt2].parent = eb[main_wgt1]

        # Parent the controls and sub-controls
        for name, subname in zip(controls, subcontrols):
            eb[name].use_connect = False
            eb[name].parent = eb[main_control]
            eb[subname].use_connect = False
            eb[subname].parent = eb[name]

        # Parent the control parents
        for name, par_name in zip(controls[1:-1], control_parents):
            eb[par_name].use_connect = False
            eb[par_name].parent = eb[main_control]
            eb[name].parent = eb[par_name]

        # Position the main bone
        put_bone(self.obj, main_control, pivot_rest_pos)
        eb[main_control].length = sum([eb[b].length
                                       for b in self.org_bones]) / 2

        # Position the main WGTs
        eb[main_wgt1].tail = (0.0, 0.0,
                              sum([eb[b].length for b in self.org_bones]) / 4)
        eb[main_wgt2].length = sum([eb[b].length for b in self.org_bones]) / 4
        put_bone(self.obj, main_wgt1, pivot_rest_pos)
        put_bone(self.obj, main_wgt2, pivot_rest_pos)

        # Position the controls and sub-controls
        pos = eb[controls[0]].head.copy()
        for name, subname in zip(controls, subcontrols):
            put_bone(self.obj, name, pivot_rest_pos)
            put_bone(self.obj, subname, pivot_rest_pos)
            eb[subname].length = eb[name].length / 3

        # Position the control parents
        for name, par_name in zip(controls[1:-1], control_parents):
            put_bone(self.obj, par_name, pivot_rest_pos)
            eb[par_name].length = eb[name].length / 2

        #-----------------------------------------
        # Control bone constraints and properties
        bpy.ops.object.mode_set(mode='OBJECT')
        pb = self.obj.pose.bones

        # Lock control locations
        for name in controls:
            bone = pb[name]
            bone.lock_location = True, True, True

        # Main control doesn't use local location
        pb[main_control].bone.use_local_location = False

        # Intermediate controls follow hips and spine
        for name, par_name, i in zip(controls[1:-1], control_parents,
                                     self.control_indices[1:-1]):
            bone = pb[par_name]

            # Custom bend_alpha property
            prop = rna_idprop_ui_prop_get(pb[name], "bend_alpha", create=True)
            pb[name]["bend_alpha"] = i / (len(self.org_bones) - 1
                                          )  # set bend alpha
            prop["min"] = 0.0
            prop["max"] = 1.0
            prop["soft_min"] = 0.0
            prop["soft_max"] = 1.0

            # Custom auto_rotate
            prop = rna_idprop_ui_prop_get(pb[name], "auto_rotate", create=True)
            pb[name]["auto_rotate"] = 1.0
            prop["min"] = 0.0
            prop["max"] = 1.0
            prop["soft_min"] = 0.0
            prop["soft_max"] = 1.0

            # Constraints
            con1 = bone.constraints.new('COPY_TRANSFORMS')
            con1.name = "copy_transforms"
            con1.target = self.obj
            con1.subtarget = subcontrols[0]

            con2 = bone.constraints.new('COPY_TRANSFORMS')
            con2.name = "copy_transforms"
            con2.target = self.obj
            con2.subtarget = subcontrols[-1]

            # Drivers
            fcurve = con1.driver_add("influence")
            driver = fcurve.driver
            driver.type = 'AVERAGE'
            var = driver.variables.new()
            var.name = "auto"
            var.targets[0].id_type = 'OBJECT'
            var.targets[0].id = self.obj
            var.targets[0].data_path = pb[name].path_from_id(
            ) + '["auto_rotate"]'

            fcurve = con2.driver_add("influence")
            driver = fcurve.driver
            driver.type = 'SCRIPTED'
            driver.expression = "alpha * auto"
            var = driver.variables.new()
            var.name = "alpha"
            var.targets[0].id_type = 'OBJECT'
            var.targets[0].id = self.obj
            var.targets[0].data_path = pb[name].path_from_id(
            ) + '["bend_alpha"]'
            var = driver.variables.new()
            var.name = "auto"
            var.targets[0].id_type = 'OBJECT'
            var.targets[0].id = self.obj
            var.targets[0].data_path = pb[name].path_from_id(
            ) + '["auto_rotate"]'

        #-------------------------
        # Create flex spine chain
        bpy.ops.object.mode_set(mode='EDIT')
        flex_bones = []
        flex_subs = []
        prev_bone = None
        for b in self.org_bones:
            # Create bones
            bone = copy_bone(self.obj, b,
                             make_mechanism_name(strip_org(b) + ".flex"))
            sub = new_bone(self.obj,
                           make_mechanism_name(strip_org(b) + ".flex_s"))
            flex_bones += [bone]
            flex_subs += [sub]

            eb = self.obj.data.edit_bones
            bone_e = eb[bone]
            sub_e = eb[sub]

            # Parenting
            bone_e.use_connect = False
            sub_e.use_connect = False
            if prev_bone is None:
                sub_e.parent = eb[controls[0]]
            else:
                sub_e.parent = eb[prev_bone]
            bone_e.parent = sub_e

            # Position
            put_bone(self.obj, sub, bone_e.head)
            sub_e.length = bone_e.length / 4
            if prev_bone is not None:
                sub_e.use_connect = True

            prev_bone = bone

        #----------------------------
        # Create reverse spine chain

        # Create bones/parenting/positioning
        bpy.ops.object.mode_set(mode='EDIT')
        rev_bones = []
        prev_bone = None
        for b in zip(flex_bones, self.org_bones):
            # Create bones
            bone = copy_bone(self.obj, b[1],
                             make_mechanism_name(strip_org(b[1]) + ".reverse"))
            rev_bones += [bone]
            eb = self.obj.data.edit_bones
            bone_e = eb[bone]

            # Parenting
            bone_e.use_connect = False
            bone_e.parent = eb[b[0]]

            # Position
            flip_bone(self.obj, bone)
            bone_e.tail = Vector(eb[b[0]].head)
            #bone_e.head = Vector(eb[b[0]].tail)
            if prev_bone is None:
                put_bone(self.obj, bone, pivot_rest_pos)
            else:
                put_bone(self.obj, bone, eb[prev_bone].tail)

            prev_bone = bone

        # Constraints
        bpy.ops.object.mode_set(mode='OBJECT')
        pb = self.obj.pose.bones
        prev_bone = None
        for bone in rev_bones:
            bone_p = pb[bone]

            con = bone_p.constraints.new('COPY_LOCATION')
            con.name = "copy_location"
            con.target = self.obj
            if prev_bone is None:
                con.subtarget = main_control
            else:
                con.subtarget = prev_bone
                con.head_tail = 1.0
            prev_bone = bone

        #----------------------------------------
        # Constrain original bones to flex spine
        bpy.ops.object.mode_set(mode='OBJECT')
        pb = self.obj.pose.bones

        for obone, fbone in zip(self.org_bones, flex_bones):
            con = pb[obone].constraints.new('COPY_TRANSFORMS')
            con.name = "copy_transforms"
            con.target = self.obj
            con.subtarget = fbone

        #---------------------------
        # Create pivot slide system
        pb = self.obj.pose.bones
        bone_p = pb[self.org_bones[0]]
        main_control_p = pb[main_control]

        # Custom pivot_slide property
        prop = rna_idprop_ui_prop_get(main_control_p,
                                      "pivot_slide",
                                      create=True)
        main_control_p["pivot_slide"] = self.pivot_rest
        prop["min"] = 0.0
        prop["max"] = 1.0
        prop["soft_min"] = 1.0 / len(self.org_bones)
        prop["soft_max"] = 1.0 - (1.0 / len(self.org_bones))

        # Anchor constraints
        con = bone_p.constraints.new('COPY_LOCATION')
        con.name = "copy_location"
        con.target = self.obj
        con.subtarget = rev_bones[0]

        con = pb[main_wgt1].constraints.new('COPY_ROTATION')
        con.name = "copy_rotation"
        con.target = self.obj
        con.subtarget = rev_bones[0]

        # Slide constraints
        i = 1
        tot = len(rev_bones)
        for rb in rev_bones:
            con = bone_p.constraints.new('COPY_LOCATION')
            con.name = "slide." + str(i)
            con.target = self.obj
            con.subtarget = rb
            con.head_tail = 1.0

            # Driver
            fcurve = con.driver_add("influence")
            driver = fcurve.driver
            var = driver.variables.new()
            driver.type = 'AVERAGE'
            var.name = "slide"
            var.targets[0].id_type = 'OBJECT'
            var.targets[0].id = self.obj
            var.targets[0].data_path = main_control_p.path_from_id(
            ) + '["pivot_slide"]'
            mod = fcurve.modifiers[0]
            mod.poly_order = 1
            mod.coefficients[0] = 1 - i
            mod.coefficients[1] = tot

            # Main WGT
            con = pb[main_wgt1].constraints.new('COPY_ROTATION')
            con.name = "slide." + str(i)
            con.target = self.obj
            con.subtarget = rb

            # Driver
            fcurve = con.driver_add("influence")
            driver = fcurve.driver
            var = driver.variables.new()
            driver.type = 'AVERAGE'
            var.name = "slide"
            var.targets[0].id_type = 'OBJECT'
            var.targets[0].id = self.obj
            var.targets[0].data_path = main_control_p.path_from_id(
            ) + '["pivot_slide"]'
            mod = fcurve.modifiers[0]
            mod.poly_order = 1
            mod.coefficients[0] = 1.5 - i
            mod.coefficients[1] = tot

            i += 1

        #----------------------------------
        # Constrain flex spine to controls
        bpy.ops.object.mode_set(mode='OBJECT')
        pb = self.obj.pose.bones

        # Constrain the bones that correspond exactly to the controls
        for i, name in zip(self.control_indices, subcontrols):
            con = pb[flex_subs[i]].constraints.new('COPY_TRANSFORMS')
            con.name = "copy_transforms"
            con.target = self.obj
            con.subtarget = name

        # Constrain the bones in-between the controls
        for i, j, name1, name2 in zip(self.control_indices,
                                      self.control_indices[1:], subcontrols,
                                      subcontrols[1:]):
            if (i + 1) < j:
                for n in range(i + 1, j):
                    bone = pb[flex_subs[n]]
                    # Custom bend_alpha property
                    prop = rna_idprop_ui_prop_get(bone,
                                                  "bend_alpha",
                                                  create=True)
                    bone["bend_alpha"] = (n - i) / (j - i)  # set bend alpha
                    prop["min"] = 0.0
                    prop["max"] = 1.0
                    prop["soft_min"] = 0.0
                    prop["soft_max"] = 1.0

                    con = bone.constraints.new('COPY_TRANSFORMS')
                    con.name = "copy_transforms"
                    con.target = self.obj
                    con.subtarget = name1

                    con = bone.constraints.new('COPY_TRANSFORMS')
                    con.name = "copy_transforms"
                    con.target = self.obj
                    con.subtarget = name2

                    # Driver
                    fcurve = con.driver_add("influence")
                    driver = fcurve.driver
                    var = driver.variables.new()
                    driver.type = 'AVERAGE'
                    var.name = "alpha"
                    var.targets[0].id_type = 'OBJECT'
                    var.targets[0].id = self.obj
                    var.targets[0].data_path = bone.path_from_id(
                    ) + '["bend_alpha"]'

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

        # Control appearance
        # Main
        pb[main_control].custom_shape_transform = pb[main_wgt2]
        w = create_compass_widget(self.obj, main_control)
        if w != None:
            obj_to_bone(w, self.obj, main_wgt2)

        # Spines
        for name, i in zip(controls[1:-1], self.control_indices[1:-1]):
            pb[name].custom_shape_transform = pb[self.org_bones[i]]
            # Create control widgets
            w = create_circle_widget(self.obj,
                                     name,
                                     radius=1.0,
                                     head_tail=0.5,
                                     with_line=True)
            if w != None:
                obj_to_bone(w, self.obj, self.org_bones[i])
        # Hips
        pb[controls[0]].custom_shape_transform = pb[self.org_bones[0]]
        # Create control widgets
        w = create_circle_widget(self.obj,
                                 controls[0],
                                 radius=1.0,
                                 head_tail=0.5,
                                 with_line=True)
        if w != None:
            obj_to_bone(w, self.obj, self.org_bones[0])

        # Ribs
        pb[controls[-1]].custom_shape_transform = pb[self.org_bones[-1]]
        # Create control widgets
        w = create_circle_widget(self.obj,
                                 controls[-1],
                                 radius=1.0,
                                 head_tail=0.5,
                                 with_line=True)
        if w != None:
            obj_to_bone(w, self.obj, self.org_bones[-1])

        # Layers
        pb[main_control].bone.layers = pb[self.org_bones[0]].bone.layers

        return [main_control] + controls
Exemple #6
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]
    def gen_control(self):
        """ Generate the control rig.

        """
        #---------------------------------
        # Create the hip and rib controls
        bpy.ops.object.mode_set(mode='EDIT')

        # Copy org bones
        hip_control = copy_bone(self.obj, self.org_bones[0],
                                strip_org(self.org_bones[0]))
        rib_control = copy_bone(self.obj, self.org_bones[-1],
                                strip_org(self.org_bones[-1]))
        rib_mch = copy_bone(
            self.obj, self.org_bones[-1],
            make_mechanism_name(strip_org(self.org_bones[-1] + ".follow")))
        hinge = copy_bone(
            self.obj, self.org_bones[0],
            make_mechanism_name(strip_org(self.org_bones[-1]) + ".hinge"))

        eb = self.obj.data.edit_bones

        hip_control_e = eb[hip_control]
        rib_control_e = eb[rib_control]
        rib_mch_e = eb[rib_mch]
        hinge_e = eb[hinge]

        # Parenting
        hip_control_e.use_connect = False
        rib_control_e.use_connect = False
        rib_mch_e.use_connect = False
        hinge_e.use_connect = False

        hinge_e.parent = None
        rib_control_e.parent = hinge_e
        rib_mch_e.parent = rib_control_e

        # Position
        flip_bone(self.obj, hip_control)
        flip_bone(self.obj, hinge)

        hinge_e.length /= 2
        rib_mch_e.length /= 2

        put_bone(self.obj, rib_control, hip_control_e.head)
        put_bone(self.obj, rib_mch, hip_control_e.head)

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

        # Switch to object mode
        bpy.ops.object.mode_set(mode='OBJECT')
        pb = self.obj.pose.bones
        hip_control_p = pb[hip_control]
        rib_control_p = pb[rib_control]
        hinge_p = pb[hinge]

        # No translation on rib control
        rib_control_p.lock_location = [True, True, True]

        # Hip does not use local location
        hip_control_p.bone.use_local_location = False

        # Custom hinge property
        prop = rna_idprop_ui_prop_get(rib_control_p, "isolate", create=True)
        rib_control_p["isolate"] = 1.0
        prop["soft_min"] = prop["min"] = 0.0
        prop["soft_max"] = prop["max"] = 1.0

        # Constraints
        con = hinge_p.constraints.new('COPY_LOCATION')
        con.name = "copy_location"
        con.target = self.obj
        con.subtarget = hip_control

        con1 = hinge_p.constraints.new('COPY_ROTATION')
        con1.name = "isolate_off.01"
        con1.target = self.obj
        con1.subtarget = hip_control

        con2 = rib_control_p.constraints.new('COPY_SCALE')
        con2.name = "isolate_off.02"
        con2.target = self.obj
        con2.subtarget = hip_control
        con2.use_offset = True
        con2.target_space = 'LOCAL'
        con2.owner_space = 'LOCAL'

        # Drivers for "isolate_off"
        fcurve = con1.driver_add("influence")
        driver = fcurve.driver
        var = driver.variables.new()
        driver.type = 'AVERAGE'
        var.name = "var"
        var.targets[0].id_type = 'OBJECT'
        var.targets[0].id = self.obj
        var.targets[0].data_path = rib_control_p.path_from_id() + '["isolate"]'
        mod = fcurve.modifiers[0]
        mod.poly_order = 1
        mod.coefficients[0] = 1.0
        mod.coefficients[1] = -1.0

        fcurve = con2.driver_add("influence")
        driver = fcurve.driver
        var = driver.variables.new()
        driver.type = 'AVERAGE'
        var.name = "var"
        var.targets[0].id_type = 'OBJECT'
        var.targets[0].id = self.obj
        var.targets[0].data_path = rib_control_p.path_from_id() + '["isolate"]'
        mod = fcurve.modifiers[0]
        mod.poly_order = 1
        mod.coefficients[0] = 1.0
        mod.coefficients[1] = -1.0

        # Appearence
        hip_control_p.custom_shape_transform = pb[self.org_bones[0]]
        rib_control_p.custom_shape_transform = pb[self.org_bones[-1]]

        #-------------------------
        # Create flex spine chain

        # Create bones/parenting/positiong
        bpy.ops.object.mode_set(mode='EDIT')
        flex_bones = []
        flex_helpers = []
        prev_bone = None
        for b in self.org_bones:
            # Create bones
            bone = copy_bone(self.obj, b,
                             make_mechanism_name(strip_org(b) + ".flex"))
            helper = copy_bone(self.obj, rib_mch,
                               make_mechanism_name(strip_org(b) + ".flex_h"))
            flex_bones += [bone]
            flex_helpers += [helper]

            eb = self.obj.data.edit_bones
            bone_e = eb[bone]
            helper_e = eb[helper]

            # Parenting
            bone_e.use_connect = False
            helper_e.use_connect = False
            if prev_bone == None:
                helper_e.parent = eb[hip_control]
            bone_e.parent = helper_e

            # Position
            put_bone(self.obj, helper, bone_e.head)
            helper_e.length /= 4

            prev_bone = bone

        # Constraints
        bpy.ops.object.mode_set(mode='OBJECT')
        pb = self.obj.pose.bones
        rib_control_p = pb[rib_control]
        rib_mch_p = pb[rib_mch]

        inc = 1.0 / (len(flex_helpers) - 1)
        inf = 1.0 / (len(flex_helpers) - 1)
        for b in zip(flex_helpers[1:], flex_bones[:-1], self.org_bones[1:]):
            bone_p = pb[b[0]]

            # Scale constraints
            con = bone_p.constraints.new('COPY_SCALE')
            con.name = "copy_scale1"
            con.target = self.obj
            con.subtarget = flex_helpers[0]
            con.influence = 1.0

            con = bone_p.constraints.new('COPY_SCALE')
            con.name = "copy_scale2"
            con.target = self.obj
            con.subtarget = rib_mch
            con.influence = inf

            # Bend constraints
            con = bone_p.constraints.new('COPY_ROTATION')
            con.name = "bend1"
            con.target = self.obj
            con.subtarget = flex_helpers[0]
            con.influence = 1.0

            con = bone_p.constraints.new('COPY_ROTATION')
            con.name = "bend2"
            con.target = self.obj
            con.subtarget = rib_mch
            con.influence = inf

            # If not the rib control
            if b[0] != flex_helpers[-1]:
                # Custom bend property
                prop_name = "bend_" + strip_org(b[2])
                prop = rna_idprop_ui_prop_get(rib_control_p,
                                              prop_name,
                                              create=True)
                rib_control_p[prop_name] = inf
                prop["min"] = 0.0
                prop["max"] = 1.0
                prop["soft_min"] = 0.0
                prop["soft_max"] = 1.0

                # Bend driver
                fcurve = con.driver_add("influence")
                driver = fcurve.driver
                var = driver.variables.new()
                driver.type = 'AVERAGE'
                var.name = prop_name
                var.targets[0].id_type = 'OBJECT'
                var.targets[0].id = self.obj
                var.targets[0].data_path = rib_control_p.path_from_id(
                ) + '["' + prop_name + '"]'

            # Location constraint
            con = bone_p.constraints.new('COPY_LOCATION')
            con.name = "copy_location"
            con.target = self.obj
            con.subtarget = b[1]
            con.head_tail = 1.0

            inf += inc

        #----------------------------
        # Create reverse spine chain

        # Create bones/parenting/positioning
        bpy.ops.object.mode_set(mode='EDIT')
        rev_bones = []
        prev_bone = None
        for b in zip(flex_bones, self.org_bones):
            # Create bones
            bone = copy_bone(self.obj, b[1],
                             make_mechanism_name(strip_org(b[1]) + ".reverse"))
            rev_bones += [bone]
            eb = self.obj.data.edit_bones
            bone_e = eb[bone]

            # Parenting
            bone_e.use_connect = False
            bone_e.parent = eb[b[0]]

            # Position
            flip_bone(self.obj, bone)
            bone_e.tail = Vector(eb[b[0]].head)
            #bone_e.head = Vector(eb[b[0]].tail)
            if prev_bone == None:
                pass  # Position base bone wherever you want, for now do nothing (i.e. position at hips)
            else:
                put_bone(self.obj, bone, eb[prev_bone].tail)

            prev_bone = bone

        # Constraints
        bpy.ops.object.mode_set(mode='OBJECT')
        pb = self.obj.pose.bones
        prev_bone = None
        for bone in rev_bones:
            bone_p = pb[bone]

            con = bone_p.constraints.new('COPY_LOCATION')
            con.name = "copy_location"
            con.target = self.obj
            if prev_bone == None:
                con.subtarget = hip_control  # Position base bone wherever you want, for now hips
            else:
                con.subtarget = prev_bone
                con.head_tail = 1.0
            prev_bone = bone

        #---------------------------------------------
        # Constrain org bones to flex bone's rotation
        pb = self.obj.pose.bones
        for b in zip(self.org_bones, flex_bones):
            con = pb[b[0]].constraints.new('COPY_TRANSFORMS')
            con.name = "copy_rotation"
            con.target = self.obj
            con.subtarget = b[1]

        #---------------------------
        # Create pivot slide system
        pb = self.obj.pose.bones
        bone_p = pb[self.org_bones[0]]
        rib_control_p = pb[rib_control]

        # Custom pivot_slide property
        prop = rna_idprop_ui_prop_get(rib_control_p,
                                      "pivot_slide",
                                      create=True)
        rib_control_p["pivot_slide"] = 1.0 / len(self.org_bones)
        prop["min"] = 0.0
        prop["max"] = 1.0
        prop["soft_min"] = 1.0 / len(self.org_bones)
        prop["soft_max"] = 1.0 - (1.0 / len(self.org_bones))

        # Anchor constraint
        con = bone_p.constraints.new('COPY_LOCATION')
        con.name = "copy_location"
        con.target = self.obj
        con.subtarget = rev_bones[0]

        # Slide constraints
        i = 1
        tot = len(rev_bones)
        for rb in rev_bones:
            con = bone_p.constraints.new('COPY_LOCATION')
            con.name = "slide." + str(i)
            con.target = self.obj
            con.subtarget = rb
            con.head_tail = 1.0

            # Driver
            fcurve = con.driver_add("influence")
            driver = fcurve.driver
            var = driver.variables.new()
            driver.type = 'AVERAGE'
            var.name = "slide"
            var.targets[0].id_type = 'OBJECT'
            var.targets[0].id = self.obj
            var.targets[0].data_path = rib_control_p.path_from_id(
            ) + '["pivot_slide"]'
            mod = fcurve.modifiers[0]
            mod.poly_order = 1
            mod.coefficients[0] = 1 - i
            mod.coefficients[1] = tot

            i += 1

        # Create control widgets
        w1 = create_circle_widget(self.obj,
                                  hip_control,
                                  radius=1.0,
                                  head_tail=1.0)
        w2 = create_circle_widget(self.obj,
                                  rib_control,
                                  radius=1.0,
                                  head_tail=0.0)

        if w1 != None:
            obj_to_bone(w1, self.obj, self.org_bones[0])
        if w2 != None:
            obj_to_bone(w2, self.obj, self.org_bones[-1])

        # Return control names
        return hip_control, rib_control
Exemple #8
0
    def gen_control(self):
        """ Generate the control rig.

        """
        bpy.ops.object.mode_set(mode='EDIT')
        eb = self.obj.data.edit_bones
        #-------------------------
        # Get rest slide position
        a = self.pivot_rest * len(self.org_bones)
        i = floor(a)
        a -= i
        if i == len(self.org_bones):
            i -= 1
            a = 1.0

        pivot_rest_pos = eb[self.org_bones[i]].head.copy()
        pivot_rest_pos += eb[self.org_bones[i]].vector * a

        #----------------------
        # Create controls

        # Create control bones
        controls = []
        for i in self.control_indices:
            name = copy_bone(self.obj, self.org_bones[i], strip_org(self.org_bones[i]))
            controls += [name]

        # Create control parents
        control_parents = []
        for i in self.control_indices[1:-1]:
            name = new_bone(self.obj, make_mechanism_name("par_" + strip_org(self.org_bones[i])))
            control_parents += [name]

        # Create sub-control bones
        subcontrols = []
        for i in self.control_indices:
            name = new_bone(self.obj, make_mechanism_name("sub_" + strip_org(self.org_bones[i])))
            subcontrols += [name]

        # Create main control bone
        main_control = new_bone(self.obj, self.params.spine_main_control_name)

        # Create main control WGT bones
        main_wgt1 = new_bone(self.obj, make_mechanism_name(self.params.spine_main_control_name + ".01"))
        main_wgt2 = new_bone(self.obj, make_mechanism_name(self.params.spine_main_control_name + ".02"))

        eb = self.obj.data.edit_bones

        # Parent the main control
        eb[main_control].use_connect = False
        eb[main_control].parent = eb[self.org_bones[0]].parent

        # Parent the main WGTs
        eb[main_wgt1].use_connect = False
        eb[main_wgt1].parent = eb[main_control]
        eb[main_wgt2].use_connect = False
        eb[main_wgt2].parent = eb[main_wgt1]

        # Parent the controls and sub-controls
        for name, subname in zip(controls, subcontrols):
            eb[name].use_connect = False
            eb[name].parent = eb[main_control]
            eb[subname].use_connect = False
            eb[subname].parent = eb[name]

        # Parent the control parents
        for name, par_name in zip(controls[1:-1], control_parents):
            eb[par_name].use_connect = False
            eb[par_name].parent = eb[main_control]
            eb[name].parent = eb[par_name]

        # Position the main bone
        put_bone(self.obj, main_control, pivot_rest_pos)
        eb[main_control].length = sum([eb[b].length for b in self.org_bones]) / 2

        # Position the main WGTs
        eb[main_wgt1].tail = (0.0, 0.0, sum([eb[b].length for b in self.org_bones]) / 4)
        eb[main_wgt2].length = sum([eb[b].length for b in self.org_bones]) / 4
        put_bone(self.obj, main_wgt1, pivot_rest_pos)
        put_bone(self.obj, main_wgt2, pivot_rest_pos)

        # Position the controls and sub-controls
        pos = eb[controls[0]].head.copy()
        for name, subname in zip(controls, subcontrols):
            put_bone(self.obj, name, pivot_rest_pos)
            put_bone(self.obj, subname, pivot_rest_pos)
            eb[subname].length = eb[name].length / 3

        # Position the control parents
        for name, par_name in zip(controls[1:-1], control_parents):
            put_bone(self.obj, par_name, pivot_rest_pos)
            eb[par_name].length = eb[name].length / 2

        #-----------------------------------------
        # Control bone constraints and properties
        bpy.ops.object.mode_set(mode='OBJECT')
        pb = self.obj.pose.bones

        # Lock control locations
        for name in controls:
            bone = pb[name]
            bone.lock_location = True, True, True

        # Main control doesn't use local location
        pb[main_control].bone.use_local_location = False

        # Intermediate controls follow hips and spine
        for name, par_name, i in zip(controls[1:-1], control_parents, self.control_indices[1:-1]):
            bone = pb[par_name]

            # Custom bend_alpha property
            prop = rna_idprop_ui_prop_get(pb[name], "bend_alpha", create=True)
            pb[name]["bend_alpha"] = i / (len(self.org_bones) - 1)  # set bend alpha
            prop["min"] = 0.0
            prop["max"] = 1.0
            prop["soft_min"] = 0.0
            prop["soft_max"] = 1.0

            # Custom auto_rotate
            prop = rna_idprop_ui_prop_get(pb[name], "auto_rotate", create=True)
            pb[name]["auto_rotate"] = 1.0
            prop["min"] = 0.0
            prop["max"] = 1.0
            prop["soft_min"] = 0.0
            prop["soft_max"] = 1.0

            # Constraints
            con1 = bone.constraints.new('COPY_TRANSFORMS')
            con1.name = "copy_transforms"
            con1.target = self.obj
            con1.subtarget = subcontrols[0]

            con2 = bone.constraints.new('COPY_TRANSFORMS')
            con2.name = "copy_transforms"
            con2.target = self.obj
            con2.subtarget = subcontrols[-1]

            # Drivers
            fcurve = con1.driver_add("influence")
            driver = fcurve.driver
            driver.type = 'AVERAGE'
            var = driver.variables.new()
            var.name = "auto"
            var.targets[0].id_type = 'OBJECT'
            var.targets[0].id = self.obj
            var.targets[0].data_path = pb[name].path_from_id() + '["auto_rotate"]'

            fcurve = con2.driver_add("influence")
            driver = fcurve.driver
            driver.type = 'SCRIPTED'
            driver.expression = "alpha * auto"
            var = driver.variables.new()
            var.name = "alpha"
            var.targets[0].id_type = 'OBJECT'
            var.targets[0].id = self.obj
            var.targets[0].data_path = pb[name].path_from_id() + '["bend_alpha"]'
            var = driver.variables.new()
            var.name = "auto"
            var.targets[0].id_type = 'OBJECT'
            var.targets[0].id = self.obj
            var.targets[0].data_path = pb[name].path_from_id() + '["auto_rotate"]'

        #-------------------------
        # Create flex spine chain
        bpy.ops.object.mode_set(mode='EDIT')
        flex_bones = []
        flex_subs = []
        prev_bone = None
        for b in self.org_bones:
            # Create bones
            bone = copy_bone(self.obj, b, make_mechanism_name(strip_org(b) + ".flex"))
            sub = new_bone(self.obj, make_mechanism_name(strip_org(b) + ".flex_s"))
            flex_bones += [bone]
            flex_subs += [sub]

            eb = self.obj.data.edit_bones
            bone_e = eb[bone]
            sub_e = eb[sub]

            # Parenting
            bone_e.use_connect = False
            sub_e.use_connect = False
            if prev_bone is None:
                sub_e.parent = eb[controls[0]]
            else:
                sub_e.parent = eb[prev_bone]
            bone_e.parent = sub_e

            # Position
            put_bone(self.obj, sub, bone_e.head)
            sub_e.length = bone_e.length / 4
            if prev_bone is not None:
                sub_e.use_connect = True

            prev_bone = bone

        #----------------------------
        # Create reverse spine chain

        # Create bones/parenting/positioning
        bpy.ops.object.mode_set(mode='EDIT')
        rev_bones = []
        prev_bone = None
        for b in zip(flex_bones, self.org_bones):
            # Create bones
            bone = copy_bone(self.obj, b[1], make_mechanism_name(strip_org(b[1]) + ".reverse"))
            rev_bones += [bone]
            eb = self.obj.data.edit_bones
            bone_e = eb[bone]

            # Parenting
            bone_e.use_connect = False
            bone_e.parent = eb[b[0]]

            # Position
            flip_bone(self.obj, bone)
            bone_e.tail = Vector(eb[b[0]].head)
            #bone_e.head = Vector(eb[b[0]].tail)
            if prev_bone is None:
                put_bone(self.obj, bone, pivot_rest_pos)
            else:
                put_bone(self.obj, bone, eb[prev_bone].tail)

            prev_bone = bone

        # Constraints
        bpy.ops.object.mode_set(mode='OBJECT')
        pb = self.obj.pose.bones
        prev_bone = None
        for bone in rev_bones:
            bone_p = pb[bone]

            con = bone_p.constraints.new('COPY_LOCATION')
            con.name = "copy_location"
            con.target = self.obj
            if prev_bone is None:
                con.subtarget = main_control
            else:
                con.subtarget = prev_bone
                con.head_tail = 1.0
            prev_bone = bone

        #----------------------------------------
        # Constrain original bones to flex spine
        bpy.ops.object.mode_set(mode='OBJECT')
        pb = self.obj.pose.bones

        for obone, fbone in zip(self.org_bones, flex_bones):
            con = pb[obone].constraints.new('COPY_TRANSFORMS')
            con.name = "copy_transforms"
            con.target = self.obj
            con.subtarget = fbone

        #---------------------------
        # Create pivot slide system
        pb = self.obj.pose.bones
        bone_p = pb[self.org_bones[0]]
        main_control_p = pb[main_control]

        # Custom pivot_slide property
        prop = rna_idprop_ui_prop_get(main_control_p, "pivot_slide", create=True)
        main_control_p["pivot_slide"] = self.pivot_rest
        prop["min"] = 0.0
        prop["max"] = 1.0
        prop["soft_min"] = 1.0 / len(self.org_bones)
        prop["soft_max"] = 1.0 - (1.0 / len(self.org_bones))

        # Anchor constraints
        con = bone_p.constraints.new('COPY_LOCATION')
        con.name = "copy_location"
        con.target = self.obj
        con.subtarget = rev_bones[0]

        con = pb[main_wgt1].constraints.new('COPY_ROTATION')
        con.name = "copy_rotation"
        con.target = self.obj
        con.subtarget = rev_bones[0]

        # Slide constraints
        i = 1
        tot = len(rev_bones)
        for rb in rev_bones:
            con = bone_p.constraints.new('COPY_LOCATION')
            con.name = "slide." + str(i)
            con.target = self.obj
            con.subtarget = rb
            con.head_tail = 1.0

            # Driver
            fcurve = con.driver_add("influence")
            driver = fcurve.driver
            var = driver.variables.new()
            driver.type = 'AVERAGE'
            var.name = "slide"
            var.targets[0].id_type = 'OBJECT'
            var.targets[0].id = self.obj
            var.targets[0].data_path = main_control_p.path_from_id() + '["pivot_slide"]'
            mod = fcurve.modifiers[0]
            mod.poly_order = 1
            mod.coefficients[0] = 1 - i
            mod.coefficients[1] = tot

            # Main WGT
            con = pb[main_wgt1].constraints.new('COPY_ROTATION')
            con.name = "slide." + str(i)
            con.target = self.obj
            con.subtarget = rb

            # Driver
            fcurve = con.driver_add("influence")
            driver = fcurve.driver
            var = driver.variables.new()
            driver.type = 'AVERAGE'
            var.name = "slide"
            var.targets[0].id_type = 'OBJECT'
            var.targets[0].id = self.obj
            var.targets[0].data_path = main_control_p.path_from_id() + '["pivot_slide"]'
            mod = fcurve.modifiers[0]
            mod.poly_order = 1
            mod.coefficients[0] = 1.5 - i
            mod.coefficients[1] = tot

            i += 1

        #----------------------------------
        # Constrain flex spine to controls
        bpy.ops.object.mode_set(mode='OBJECT')
        pb = self.obj.pose.bones

        # Constrain the bones that correspond exactly to the controls
        for i, name in zip(self.control_indices, subcontrols):
            con = pb[flex_subs[i]].constraints.new('COPY_TRANSFORMS')
            con.name = "copy_transforms"
            con.target = self.obj
            con.subtarget = name

        # Constrain the bones in-between the controls
        for i, j, name1, name2 in zip(self.control_indices, self.control_indices[1:], subcontrols, subcontrols[1:]):
            if (i + 1) < j:
                for n in range(i + 1, j):
                    bone = pb[flex_subs[n]]
                    # Custom bend_alpha property
                    prop = rna_idprop_ui_prop_get(bone, "bend_alpha", create=True)
                    bone["bend_alpha"] = (n - i) / (j - i)  # set bend alpha
                    prop["min"] = 0.0
                    prop["max"] = 1.0
                    prop["soft_min"] = 0.0
                    prop["soft_max"] = 1.0

                    con = bone.constraints.new('COPY_TRANSFORMS')
                    con.name = "copy_transforms"
                    con.target = self.obj
                    con.subtarget = name1

                    con = bone.constraints.new('COPY_TRANSFORMS')
                    con.name = "copy_transforms"
                    con.target = self.obj
                    con.subtarget = name2

                    # Driver
                    fcurve = con.driver_add("influence")
                    driver = fcurve.driver
                    var = driver.variables.new()
                    driver.type = 'AVERAGE'
                    var.name = "alpha"
                    var.targets[0].id_type = 'OBJECT'
                    var.targets[0].id = self.obj
                    var.targets[0].data_path = bone.path_from_id() + '["bend_alpha"]'

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

        # Control appearance
        # Main
        pb[main_control].custom_shape_transform = pb[main_wgt2]
        w = create_compass_widget(self.obj, main_control)
        if w != None:
            obj_to_bone(w, self.obj, main_wgt2)

        # Spines
        for name, i in zip(controls[1:-1], self.control_indices[1:-1]):
            pb[name].custom_shape_transform = pb[self.org_bones[i]]
            # Create control widgets
            w = create_circle_widget(self.obj, name, radius=1.0, head_tail=0.5, with_line=True)
            if w != None:
                obj_to_bone(w, self.obj, self.org_bones[i])
        # Hips
        pb[controls[0]].custom_shape_transform = pb[self.org_bones[0]]
        # Create control widgets
        w = create_circle_widget(self.obj, controls[0], radius=1.0, head_tail=0.5, with_line=True)
        if w != None:
            obj_to_bone(w, self.obj, self.org_bones[0])

        # Ribs
        pb[controls[-1]].custom_shape_transform = pb[self.org_bones[-1]]
        # Create control widgets
        w = create_circle_widget(self.obj, controls[-1], radius=1.0, head_tail=0.5, with_line=True)
        if w != None:
            obj_to_bone(w, self.obj, self.org_bones[-1])

        # Layers
        pb[main_control].bone.layers = pb[self.org_bones[0]].bone.layers

        return [main_control] + controls
Exemple #9
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.

        """
        bpy.ops.object.mode_set(mode='EDIT')

        make_rocker = False
        if self.org_bones[5] is not None:
            make_rocker = True

        # Create the bones
        thigh = copy_bone(self.obj, self.org_bones[0], make_mechanism_name(strip_org(insert_before_lr(self.org_bones[0], "_ik"))))
        shin = copy_bone(self.obj, self.org_bones[1], make_mechanism_name(strip_org(insert_before_lr(self.org_bones[1], "_ik"))))

        foot = copy_bone(self.obj, self.org_bones[2], strip_org(insert_before_lr(self.org_bones[2], "_ik")))
        foot_ik_target = copy_bone(self.obj, self.org_bones[2], make_mechanism_name(strip_org(insert_before_lr(self.org_bones[2], "_ik_target"))))
        pole = copy_bone(self.obj, self.org_bones[0], strip_org(insert_before_lr(self.org_bones[0], "_pole")))

        toe = copy_bone(self.obj, self.org_bones[3], strip_org(self.org_bones[3]))
        toe_parent = copy_bone(self.obj, self.org_bones[2], make_mechanism_name(strip_org(self.org_bones[3] + ".parent")))
        toe_parent_socket1 = copy_bone(self.obj, self.org_bones[2], make_mechanism_name(strip_org(self.org_bones[3] + ".socket1")))
        toe_parent_socket2 = copy_bone(self.obj, self.org_bones[2], make_mechanism_name(strip_org(self.org_bones[3] + ".socket2")))

        foot_roll = copy_bone(self.obj, self.org_bones[4], strip_org(insert_before_lr(self.org_bones[2], "_roll")))
        roll1 = copy_bone(self.obj, self.org_bones[4], make_mechanism_name(strip_org(self.org_bones[2] + ".roll.01")))
        roll2 = copy_bone(self.obj, self.org_bones[4], make_mechanism_name(strip_org(self.org_bones[2] + ".roll.02")))

        if make_rocker:
            rocker1 = copy_bone(self.obj, self.org_bones[5], make_mechanism_name(strip_org(self.org_bones[2] + ".rocker.01")))
            rocker2 = copy_bone(self.obj, self.org_bones[5], make_mechanism_name(strip_org(self.org_bones[2] + ".rocker.02")))

        visfoot = copy_bone(self.obj, self.org_bones[2], "VIS-" + strip_org(insert_before_lr(self.org_bones[2], "_ik")))
        vispole = copy_bone(self.obj, self.org_bones[1], "VIS-" + strip_org(insert_before_lr(self.org_bones[0], "_pole")))

        # Get edit bones
        eb = self.obj.data.edit_bones

        org_foot_e = eb[self.org_bones[2]]
        thigh_e = eb[thigh]
        shin_e = eb[shin]
        foot_e = eb[foot]
        foot_ik_target_e = eb[foot_ik_target]
        pole_e = eb[pole]
        toe_e = eb[toe]
        toe_parent_e = eb[toe_parent]
        toe_parent_socket1_e = eb[toe_parent_socket1]
        toe_parent_socket2_e = eb[toe_parent_socket2]
        foot_roll_e = eb[foot_roll]
        roll1_e = eb[roll1]
        roll2_e = eb[roll2]
        if make_rocker:
            rocker1_e = eb[rocker1]
            rocker2_e = eb[rocker2]
        visfoot_e = eb[visfoot]
        vispole_e = eb[vispole]

        # Parenting
        shin_e.parent = thigh_e

        foot_e.use_connect = False
        foot_e.parent = None
        foot_ik_target_e.use_connect = False
        foot_ik_target_e.parent = roll2_e

        pole_e.use_connect = False
        pole_e.parent = foot_e

        toe_e.parent = toe_parent_e
        toe_parent_e.use_connect = False
        toe_parent_e.parent = toe_parent_socket1_e
        toe_parent_socket1_e.use_connect = False
        toe_parent_socket1_e.parent = roll1_e
        toe_parent_socket2_e.use_connect = False
        toe_parent_socket2_e.parent = eb[self.org_bones[2]]

        foot_roll_e.use_connect = False
        foot_roll_e.parent = foot_e

        roll1_e.use_connect = False
        roll1_e.parent = foot_e

        roll2_e.use_connect = False
        roll2_e.parent = roll1_e

        visfoot_e.use_connect = False
        visfoot_e.parent = None

        vispole_e.use_connect = False
        vispole_e.parent = None

        if make_rocker:
            rocker1_e.use_connect = False
            rocker2_e.use_connect = False

            roll1_e.parent = rocker2_e
            rocker2_e.parent = rocker1_e
            rocker1_e.parent = foot_e

        # Misc
        foot_e.use_local_location = False

        visfoot_e.hide_select = True
        vispole_e.hide_select = True

        # Positioning
        vec = Vector(toe_e.vector)
        vec.normalize()
        foot_e.tail = foot_e.head + (vec * foot_e.length)
        foot_e.roll = toe_e.roll

        v1 = shin_e.tail - thigh_e.head

        if 'X' in self.primary_rotation_axis or 'Y' in self.primary_rotation_axis:
            v2 = v1.cross(shin_e.x_axis)
            if (v2 * shin_e.z_axis) > 0.0:
                v2 *= -1.0
        else:
            v2 = v1.cross(shin_e.z_axis)
            if (v2 * shin_e.x_axis) < 0.0:
                v2 *= -1.0
        v2.normalize()
        v2 *= v1.length

        if '-' in self.primary_rotation_axis:
            v2 *= -1

        pole_e.head = shin_e.head + v2
        pole_e.tail = pole_e.head + (Vector((0, 1, 0)) * (v1.length / 8))
        pole_e.roll = 0.0

        flip_bone(self.obj, toe_parent_socket1)
        flip_bone(self.obj, toe_parent_socket2)
        toe_parent_socket1_e.head = Vector(org_foot_e.tail)
        toe_parent_socket2_e.head = Vector(org_foot_e.tail)
        toe_parent_socket1_e.tail = Vector(org_foot_e.tail) + (Vector((0, 0, 1)) * foot_e.length / 2)
        toe_parent_socket2_e.tail = Vector(org_foot_e.tail) + (Vector((0, 0, 1)) * foot_e.length / 3)
        toe_parent_socket2_e.roll = toe_parent_socket1_e.roll

        tail = Vector(roll1_e.tail)
        roll1_e.tail = Vector(org_foot_e.tail)
        roll1_e.tail = Vector(org_foot_e.tail)
        roll1_e.head = tail
        roll2_e.head = Vector(org_foot_e.tail)
        foot_roll_e.head = Vector(org_foot_e.tail)
        put_bone(self.obj, foot_roll, roll1_e.head)
        foot_roll_e.length /= 2

        roll_axis = roll1_e.vector.cross(org_foot_e.vector)
        align_x_axis(self.obj, roll1, roll_axis)
        align_x_axis(self.obj, roll2, roll_axis)
        foot_roll_e.roll = roll2_e.roll

        visfoot_e.tail = visfoot_e.head + Vector((0, 0, v1.length / 32))
        vispole_e.tail = vispole_e.head + Vector((0, 0, v1.length / 32))

        if make_rocker:
            d = toe_e.y_axis.dot(rocker1_e.x_axis)
            if d >= 0.0:
                flip_bone(self.obj, rocker2)
            else:
                flip_bone(self.obj, rocker1)

        # Weird alignment issues.  Fix.
        toe_parent_e.head = Vector(org_foot_e.head)
        toe_parent_e.tail = Vector(org_foot_e.tail)
        toe_parent_e.roll = org_foot_e.roll

        foot_e.head = Vector(org_foot_e.head)

        foot_ik_target_e.head = Vector(org_foot_e.head)
        foot_ik_target_e.tail = Vector(org_foot_e.tail)

        # Determine the pole offset value
        plane = (shin_e.tail - thigh_e.head).normalized()
        vec1 = thigh_e.x_axis.normalized()
        vec2 = (pole_e.head - thigh_e.head).normalized()
        pole_offset = angle_on_plane(plane, vec1, vec2)

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

        # thigh_p = pb[thigh]  # UNUSED
        shin_p = pb[shin]
        foot_p = pb[foot]
        pole_p = pb[pole]
        foot_roll_p = pb[foot_roll]
        roll1_p = pb[roll1]
        roll2_p = pb[roll2]
        if make_rocker:
            rocker1_p = pb[rocker1]
            rocker2_p = pb[rocker2]
        toe_p = pb[toe]
        toe_parent_p = pb[toe_parent]
        toe_parent_socket1_p = pb[toe_parent_socket1]
        visfoot_p = pb[visfoot]
        vispole_p = pb[vispole]

        # Set the knee to only bend on the primary axis.
        if 'X' in self.primary_rotation_axis:
            shin_p.lock_ik_y = True
            shin_p.lock_ik_z = True
        elif 'Y' in self.primary_rotation_axis:
            shin_p.lock_ik_x = True
            shin_p.lock_ik_z = True
        else:
            shin_p.lock_ik_x = True
            shin_p.lock_ik_y = True

        # Foot roll control only rotates on x-axis, or x and y if rocker.
        foot_roll_p.rotation_mode = 'XYZ'
        if make_rocker:
            foot_roll_p.lock_rotation = False, False, True
        else:
            foot_roll_p.lock_rotation = False, True, True
        foot_roll_p.lock_location = True, True, True
        foot_roll_p.lock_scale = True, True, True

        # roll and rocker bones set to euler rotation
        roll1_p.rotation_mode = 'XYZ'
        roll2_p.rotation_mode = 'XYZ'
        if make_rocker:
            rocker1_p.rotation_mode = 'XYZ'
            rocker2_p.rotation_mode = 'XYZ'

        # Pole target only translates
        pole_p.lock_location = False, False, False
        pole_p.lock_rotation = True, True, True
        pole_p.lock_rotation_w = True
        pole_p.lock_scale = True, True, True

        # Set up custom properties
        if self.switch == True:
            prop = rna_idprop_ui_prop_get(foot_p, "ikfk_switch", create=True)
            foot_p["ikfk_switch"] = 0.0
            prop["soft_min"] = prop["min"] = 0.0
            prop["soft_max"] = prop["max"] = 1.0

        # Bend direction hint
        if self.bend_hint:
            con = shin_p.constraints.new('LIMIT_ROTATION')
            con.name = "bend_hint"
            con.owner_space = 'LOCAL'
            if self.primary_rotation_axis == 'X':
                con.use_limit_x = True
                con.min_x = pi / 10
                con.max_x = pi / 10
            elif self.primary_rotation_axis == '-X':
                con.use_limit_x = True
                con.min_x = -pi / 10
                con.max_x = -pi / 10
            elif self.primary_rotation_axis == 'Y':
                con.use_limit_y = True
                con.min_y = pi / 10
                con.max_y = pi / 10
            elif self.primary_rotation_axis == '-Y':
                con.use_limit_y = True
                con.min_y = -pi / 10
                con.max_y = -pi / 10
            elif self.primary_rotation_axis == 'Z':
                con.use_limit_z = True
                con.min_z = pi / 10
                con.max_z = pi / 10
            elif self.primary_rotation_axis == '-Z':
                con.use_limit_z = True
                con.min_z = -pi / 10
                con.max_z = -pi / 10

        # IK Constraint
        con = shin_p.constraints.new('IK')
        con.name = "ik"
        con.target = self.obj
        con.subtarget = foot_ik_target
        con.pole_target = self.obj
        con.pole_subtarget = pole
        con.pole_angle = pole_offset
        con.chain_count = 2

        # toe_parent constraint
        con = toe_parent_socket1_p.constraints.new('COPY_LOCATION')
        con.name = "copy_location"
        con.target = self.obj
        con.subtarget = toe_parent_socket2

        con = toe_parent_socket1_p.constraints.new('COPY_SCALE')
        con.name = "copy_scale"
        con.target = self.obj
        con.subtarget = toe_parent_socket2

        con = toe_parent_socket1_p.constraints.new('COPY_TRANSFORMS')  # drive with IK switch
        con.name = "fk"
        con.target = self.obj
        con.subtarget = toe_parent_socket2

        fcurve = con.driver_add("influence")
        driver = fcurve.driver
        var = driver.variables.new()
        driver.type = 'AVERAGE'
        var.name = "var"
        var.targets[0].id_type = 'OBJECT'
        var.targets[0].id = self.obj
        var.targets[0].data_path = foot_p.path_from_id() + '["ikfk_switch"]'
        mod = fcurve.modifiers[0]
        mod.poly_order = 1
        mod.coefficients[0] = 1.0
        mod.coefficients[1] = -1.0

        # Foot roll drivers
        fcurve = roll1_p.driver_add("rotation_euler", 0)
        driver = fcurve.driver
        var = driver.variables.new()
        driver.type = 'SCRIPTED'
        driver.expression = "min(0,var)"
        var.name = "var"
        var.targets[0].id_type = 'OBJECT'
        var.targets[0].id = self.obj
        var.targets[0].data_path = foot_roll_p.path_from_id() + '.rotation_euler[0]'

        fcurve = roll2_p.driver_add("rotation_euler", 0)
        driver = fcurve.driver
        var = driver.variables.new()
        driver.type = 'SCRIPTED'
        driver.expression = "max(0,var)"
        var.name = "var"
        var.targets[0].id_type = 'OBJECT'
        var.targets[0].id = self.obj
        var.targets[0].data_path = foot_roll_p.path_from_id() + '.rotation_euler[0]'

        if make_rocker:
            fcurve = rocker1_p.driver_add("rotation_euler", 0)
            driver = fcurve.driver
            var = driver.variables.new()
            driver.type = 'SCRIPTED'
            driver.expression = "max(0,-var)"
            var.name = "var"
            var.targets[0].id_type = 'OBJECT'
            var.targets[0].id = self.obj
            var.targets[0].data_path = foot_roll_p.path_from_id() + '.rotation_euler[1]'

            fcurve = rocker2_p.driver_add("rotation_euler", 0)
            driver = fcurve.driver
            var = driver.variables.new()
            driver.type = 'SCRIPTED'
            driver.expression = "max(0,var)"
            var.name = "var"
            var.targets[0].id_type = 'OBJECT'
            var.targets[0].id = self.obj
            var.targets[0].data_path = foot_roll_p.path_from_id() + '.rotation_euler[1]'

        # Constrain org bones to controls
        con = pb[self.org_bones[0]].constraints.new('COPY_TRANSFORMS')
        con.name = "ik"
        con.target = self.obj
        con.subtarget = thigh
        if self.switch == True:
            # IK/FK switch driver
            fcurve = con.driver_add("influence")
            driver = fcurve.driver
            var = driver.variables.new()
            driver.type = 'AVERAGE'
            var.name = "var"
            var.targets[0].id_type = 'OBJECT'
            var.targets[0].id = self.obj
            var.targets[0].data_path = foot_p.path_from_id() + '["ikfk_switch"]'

        con = pb[self.org_bones[1]].constraints.new('COPY_TRANSFORMS')
        con.name = "ik"
        con.target = self.obj
        con.subtarget = shin
        if self.switch == True:
            # IK/FK switch driver
            fcurve = con.driver_add("influence")
            driver = fcurve.driver
            var = driver.variables.new()
            driver.type = 'AVERAGE'
            var.name = "var"
            var.targets[0].id_type = 'OBJECT'
            var.targets[0].id = self.obj
            var.targets[0].data_path = foot_p.path_from_id() + '["ikfk_switch"]'

        con = pb[self.org_bones[2]].constraints.new('COPY_TRANSFORMS')
        con.name = "ik"
        con.target = self.obj
        con.subtarget = foot_ik_target
        if self.switch == True:
            # IK/FK switch driver
            fcurve = con.driver_add("influence")
            driver = fcurve.driver
            var = driver.variables.new()
            driver.type = 'AVERAGE'
            var.name = "var"
            var.targets[0].id_type = 'OBJECT'
            var.targets[0].id = self.obj
            var.targets[0].data_path = foot_p.path_from_id() + '["ikfk_switch"]'

        con = pb[self.org_bones[3]].constraints.new('COPY_TRANSFORMS')
        con.name = "copy_transforms"
        con.target = self.obj
        con.subtarget = toe

        # VIS foot constraints
        con = visfoot_p.constraints.new('COPY_LOCATION')
        con.name = "copy_loc"
        con.target = self.obj
        con.subtarget = self.org_bones[2]

        con = visfoot_p.constraints.new('STRETCH_TO')
        con.name = "stretch_to"
        con.target = self.obj
        con.subtarget = foot
        con.volume = 'NO_VOLUME'
        con.rest_length = visfoot_p.length

        # VIS pole constraints
        con = vispole_p.constraints.new('COPY_LOCATION')
        con.name = "copy_loc"
        con.target = self.obj
        con.subtarget = self.org_bones[1]

        con = vispole_p.constraints.new('STRETCH_TO')
        con.name = "stretch_to"
        con.target = self.obj
        con.subtarget = pole
        con.volume = 'NO_VOLUME'
        con.rest_length = vispole_p.length

        # Set layers if specified
        if self.layers:
            foot_p.bone.layers = self.layers
            pole_p.bone.layers = self.layers
            foot_roll_p.bone.layers = self.layers
            visfoot_p.bone.layers = self.layers
            vispole_p.bone.layers = self.layers

            toe_p.bone.layers = [(i[0] or i[1]) for i in zip(toe_p.bone.layers, self.layers)]  # Both FK and IK layers

        # Create widgets
        create_line_widget(self.obj, vispole)
        create_line_widget(self.obj, visfoot)
        create_sphere_widget(self.obj, pole)
        create_circle_widget(self.obj, toe, radius=0.7, head_tail=0.5)

        ob = create_widget(self.obj, foot)
        if ob != None:
            verts = [(0.7, 1.5, 0.0), (0.7, -0.25, 0.0), (-0.7, -0.25, 0.0), (-0.7, 1.5, 0.0), (0.7, 0.723, 0.0), (-0.7, 0.723, 0.0), (0.7, 0.0, 0.0), (-0.7, 0.0, 0.0)]
            edges = [(1, 2), (0, 3), (0, 4), (3, 5), (4, 6), (1, 6), (5, 7), (2, 7)]
            mesh = ob.data
            mesh.from_pydata(verts, edges, [])
            mesh.update()

            mod = ob.modifiers.new("subsurf", 'SUBSURF')
            mod.levels = 2

        ob = create_widget(self.obj, foot_roll)
        if ob != None:
            verts = [(0.3999999761581421, 0.766044557094574, 0.6427875757217407), (0.17668449878692627, 3.823702598992895e-08, 3.2084670920085046e-08), (-0.17668461799621582, 9.874240447516058e-08, 8.285470443070153e-08), (-0.39999961853027344, 0.7660449147224426, 0.6427879333496094), (0.3562471270561218, 0.6159579753875732, 0.5168500542640686), (-0.35624682903289795, 0.6159582138061523, 0.5168502926826477), (0.20492683351039886, 0.09688037633895874, 0.0812922865152359), (-0.20492687821388245, 0.0968804731965065, 0.08129236847162247)]
            edges = [(1, 2), (0, 3), (0, 4), (3, 5), (1, 6), (4, 6), (2, 7), (5, 7)]
            mesh = ob.data
            mesh.from_pydata(verts, edges, [])
            mesh.update()

            mod = ob.modifiers.new("subsurf", 'SUBSURF')
            mod.levels = 2

        return [thigh, shin, foot, pole, foot_roll, foot_ik_target]
    def generate(self):
        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,
        }
Exemple #11
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.

        """
        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]