def copy_properties(pose_bone_1, pose_bone_2):
    for key in pose_bone_1.keys():
        if key != "_RNA_UI":
            prop1 = rna_idprop_ui_prop_get(pose_bone_1, key, create=False)
            pose_bone_2[key] = pose_bone_1[key]
            if prop1:
                prop2 = rna_idprop_ui_prop_get(pose_bone_2, key, create=True)
                for key in prop1.keys():
                    prop2[key] = prop1[key]
    def execute(self, context):
        from rna_prop_ui import rna_idprop_ui_prop_get

        data_path = self.data_path
        item = eval("context.%s" % data_path)

        def unique_name(names):
            prop = self.prop_name
            prop_new = prop
            i = 1
            while prop_new in names:
                prop_new = prop + str(i)
                i += 1

            return prop_new

        prop = unique_name(item.keys())

        item[prop] = self.default_value

        prop_type = type(item[prop])

        # not essential, but without this we get [#31661]
        prop_ui = rna_idprop_ui_prop_get(item, prop)  # create the prop_ui
        prop_ui["soft_min"] = prop_ui["min"] = 0.0
        prop_ui["soft_max"] = prop_ui["max"] = 1.0
        # if prop_type in {float, int}:
        # prop_ui["soft_min"] = prop_ui["min"] = prop_type(self.default_min)
        # prop_ui["soft_max"] = prop_ui["max"] = prop_type(self.default_max)

        return {"FINISHED"}
Beispiel #3
0
    def execute(self, context):
        ob = context.active_object
        prop = self.prop
        global ob_prop

        if len(self.new_prop) > 0:
            prop = self.new_prop
            if prop[0] != "/":
                prop = "/" + prop

                # Create property
            ob_prop[prop] = True if self.is_bool else 0.0

            # Limit to [0, 1]
            prop_ui = rna_idprop_ui_prop_get(ob_prop, prop, create=True)
            prop_ui["soft_min"] = False if self.is_bool else 0.0
            prop_ui["soft_max"] = True if self.is_bool else 1.0

        driver = ob.animation_data.drivers[self.driver_id].driver
        driver.type = "SUM"

        var = driver.variables[0]
        var.type = "SINGLE_PROP"

        target = var.targets[0]
        target.id_type = "OBJECT"
        target.id = ob_prop
        target.data_path = '["' + prop + '"]'

        return {"FINISHED"}
Beispiel #4
0
    def drivers_and_props( self, all_bones ):
        
        bpy.ops.object.mode_set(mode ='OBJECT')
        pb = self.obj.pose.bones
        
        # Referencing all relevant bones
        torso_name = all_bones['torso']['ctrl']
        pb_torso = pb[torso_name]
        
        ribs_mch_rot_names = all_bones['back']['mch_rot_bones']
        neck_mch_rot_names = all_bones['neck']['mch_rot_bones']
        head_mch_rot_names = all_bones['head']['mch_rot_bones']
        
        owner_mch_rot_bones = [ ribs_mch_rot_names[0], neck_mch_rot_names[0], head_mch_rot_names[0] ]
        
        hips_mch_drv_name  = all_bones['hips']['mch_drv']
        back_mch_drv_names = all_bones['back']['mch_drv_bones']
        neck_mch_drv_names = all_bones['neck']['mch_drv_bones']
        head_mch_drv_name  = all_bones['head']['mch_drv']
        
        mch_drv_bones = [ hips_mch_drv_name ] + back_mch_drv_names + neck_mch_drv_names + [ head_mch_drv_name ]
        
        # Setting the torso's props
        props_list = [ "ribs_follow", "neck_follow", "head_follow", "IK/FK" ]
        
        for prop in props_list:
            
            if prop == 'neck_follow':
                pb_torso[prop] = 0.5
            else:
                pb_torso[prop] = 0.0

            prop = rna_idprop_ui_prop_get( pb_torso, prop )
            prop["min"] = 0.0
            prop["max"] = 1.0
            prop["soft_min"] = 0.0
            prop["soft_max"] = 1.0
            prop["description"] = prop
        
        # driving the follow rotation switches for ribs neck and head
        for bone, prop, in zip( owner_mch_rot_bones, props_list[:-1] ):
            drv = pb[ bone ].constraints[ 1 ].driver_add("influence").driver
            drv.type='SUM'
            
            var = drv.variables.new()
            var.name = prop
            var.type = "SINGLE_PROP"
            var.targets[0].id = self.obj
            var.targets[0].data_path = pb_torso.path_from_id() + '['+ '"' + prop + '"' + ']'
        
        # driving the fk switch
        for bone in mch_drv_bones:
            drv = pb[ bone ].constraints[ -1 ].driver_add("influence").driver
            drv.type='SUM'
            
            var = drv.variables.new()
            var.name = "fk_switch"
            var.type = "SINGLE_PROP"
            var.targets[0].id = self.obj
            var.targets[0].data_path = pb_torso.path_from_id() + '["IK/FK"]'
def set_prop_constraint(obj, prop, minimum, maximum):
    obj_name = obj.name
    data_path = "data.objects[obj_name]"
    item = eval("bpy.%s" % data_path)
    prop_type = type(item[prop])
    prop_ui = rna_idprop_ui_prop_get(item, prop)
    
    if prop_type in (float, int):
        prop_ui['soft_min'] = prop_ui['min'] = prop_type(minimum)
        prop_ui['soft_max'] = prop_ui['max'] = prop_type(maximum)
Beispiel #6
0
    def create_parent( self ):

        org_bones = self.org_bones

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

        name = get_bone_name( strip_org( org_bones[0] ), 'mch', 'parent' )

        mch = copy_bone( self.obj, org_bones[0], name )
        orient_bone( self, eb[mch], 'y' )
        eb[ mch ].length = eb[ org_bones[0] ].length / 4

        eb[ mch ].parent = eb[ org_bones[0] ].parent

        eb[ mch ].roll = 0.0

        # Constraints
        make_constraint( self, mch, {
            'constraint'  : 'COPY_ROTATION',
            'subtarget'   : 'root'
        })

        make_constraint( self, mch, {
            'constraint'  : 'COPY_SCALE',
            'subtarget'   : 'root'
        })

        # Limb Follow Driver
        pb = self.obj.pose.bones

        name = 'FK_limb_follow'

        pb[ mch ][ name ] = 0.0
        prop = rna_idprop_ui_prop_get( pb[ mch ], name, create = True )

        prop["min"]         = 0.0
        prop["max"]         = 1.0
        prop["soft_min"]    = 0.0
        prop["soft_max"]    = 1.0
        prop["description"] = name

        drv = pb[ mch ].constraints[ 0 ].driver_add("influence").driver

        drv.type = 'AVERAGE'
        var = drv.variables.new()
        var.name = name
        var.type = "SINGLE_PROP"
        var.targets[0].id = self.obj
        var.targets[0].data_path = pb[ mch ].path_from_id() + \
                                   '[' + '"' + name + '"' + ']'

        return mch
Beispiel #7
0
    def create_drivers(self, bones):
        bpy.ops.object.mode_set(mode='OBJECT')
        pb = self.obj.pose.bones

        # Setting the torso's props
        torso = pb[bones['pivot']['ctrl']]

        props = []
        owners = []

        if self.use_head:
            props += ["head_follow"]
            owners += [bones['neck']['mch_head']]
            if bones['neck']['mch_neck']:
                props += ["neck_follow"]
                owners += [bones['neck']['mch_neck']]
        if self.use_tail:
            props += ["tail_follow"]
            owners += [bones['tail']['mch_tail']]

        for prop in props:
            if prop == 'neck_follow':
                torso[prop] = 0.5
            else:
                torso[prop] = 0.0

            prop = rna_idprop_ui_prop_get(torso, prop, create=True)
            prop["min"] = 0.0
            prop["max"] = 1.0
            prop["soft_min"] = 0.0
            prop["soft_max"] = 1.0
            prop["description"] = prop

        # driving the follow rotation switches for neck and head
        for bone, prop, in zip(owners, props):
            # Add driver to copy rotation constraint
            drv = pb[bone].constraints[0].driver_add("influence").driver
            drv.type = 'AVERAGE'

            var = drv.variables.new()
            var.name = prop
            var.type = "SINGLE_PROP"
            var.targets[0].id = self.obj
            var.targets[0].data_path = \
                torso.path_from_id() + '[' + '"' + prop + '"' + ']'

            drv_modifier = self.obj.animation_data.drivers[-1].modifiers[0]

            drv_modifier.mode = 'POLYNOMIAL'
            drv_modifier.poly_order = 1
            drv_modifier.coefficients[0] = 1.0
            drv_modifier.coefficients[1] = -1.0
Beispiel #8
0
    def execute(self, context):
        data_path = self.data_path
        value = self.value
        prop = self.property

        prop_old = getattr(self, "_last_prop", [None])[0]

        if prop_old is None:
            self.report({'ERROR'}, "Direct execution not supported")
            return {'CANCELLED'}

        try:
            value_eval = eval(value)
        except:
            value_eval = value

        # First remove
        item = eval("context.%s" % data_path)

        rna_idprop_ui_prop_clear(item, prop_old)
        exec_str = "del item['%s']" % prop_old
        # print(exec_str)
        exec(exec_str)

        # Reassign
        exec_str = "item['%s'] = %s" % (prop, repr(value_eval))
        # print(exec_str)
        exec(exec_str)
        self._last_prop[:] = [prop]

        prop_type = type(item[prop])

        prop_ui = rna_idprop_ui_prop_get(item, prop)

        if prop_type in {float, int}:

            prop_ui['soft_min'] = prop_ui['min'] = prop_type(self.min)
            prop_ui['soft_max'] = prop_ui['max'] = prop_type(self.max)

        prop_ui['description'] = self.description

        # otherwise existing buttons which reference freed
        # memory may crash blender [#26510]
        # context.area.tag_redraw()
        for win in context.window_manager.windows:
            for area in win.screen.areas:
                area.tag_redraw()

        return {'FINISHED'}
Beispiel #9
0
    def invoke(self, context, event):

        self._last_prop = [self.property]

        item = eval("context.%s" % self.data_path)

        # setup defaults
        prop_ui = rna_idprop_ui_prop_get(item, self.property, False)  # dont create
        if prop_ui:
            self.min = prop_ui.get("min", -1000000000)
            self.max = prop_ui.get("max", 1000000000)
            self.description = prop_ui.get("description", "")

        wm = context.window_manager
        return wm.invoke_props_dialog(self)
Beispiel #10
0
def _onTypeChange(self, context):
	ob = self.id_data
	for cat, props in properties.items():
		if cat == self.type:
			for prop, dom in props.items():
				ob[prop] = 0.0
				prop_ui = rna_idprop_ui_prop_get(ob, prop, create=True)
				prop_ui['min'] = float(dom[0])
				prop_ui['max'] = float(dom[1])
		else:
			# remove values from other categories
			for prop in props.keys():
				try:	del ob[prop]
				except:		pass
				try: del ob['_RNA_UI'][prop]
				except: pass
    def org_parenting_and_switch( self, org, ik, fk, parent ):
        bpy.ops.object.mode_set(mode ='EDIT')
        eb = self.obj.data.edit_bones
        # re-parent ORGs in a connected chain
        for i,o in enumerate(org):
            if i > 0:
                eb[o].parent = eb[ org[i-1] ]
                if i <= 2:
                    eb[o].use_connect = True

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

        # Create ik/fk switch property
        pb_parent['IK/FK']  = 0.0
        prop = rna_idprop_ui_prop_get( pb_parent, 'IK/FK', create=True )
        prop["min"]         = 0.0
        prop["max"]         = 1.0
        prop["soft_min"]    = 0.0
        prop["soft_max"]    = 1.0
        prop["description"] = 'IK/FK Switch'

        # Constrain org to IK and FK bones
        iks =  [ ik['ctrl']['limb'] ]
        iks += [ ik[k] for k in [ 'mch_ik', 'mch_target'] ]

        for o, i, f in zip( org, iks, fk ):
            make_constraint( self, o, {
                'constraint'  : 'COPY_TRANSFORMS',
                'subtarget'   : i
            })
            make_constraint( self, o, {
                'constraint'  : 'COPY_TRANSFORMS',
                'subtarget'   : f
            })
    
            # Add driver to relevant constraint
            drv = pb[o].constraints[-1].driver_add("influence").driver
            drv.type = 'AVERAGE'
            
            var = drv.variables.new()
            var.name = prop.name
            var.type = "SINGLE_PROP"
            var.targets[0].id = self.obj
            var.targets[0].data_path = \
                pb_parent.path_from_id() + '['+ '"' + prop.name + '"' + ']'
    def create_parent(self):

        org_bones = self.org_bones

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

        name = get_bone_name(strip_org(org_bones[0]), "mch", "parent")

        mch = copy_bone(self.obj, org_bones[0], name)
        orient_bone(self, eb[mch], "y")
        eb[mch].length = eb[org_bones[0]].length / 4

        eb[mch].parent = eb[org_bones[0]].parent

        eb[mch].roll = 0.0

        # Constraints
        make_constraint(self, mch, {"constraint": "COPY_ROTATION", "subtarget": "root"})

        make_constraint(self, mch, {"constraint": "COPY_SCALE", "subtarget": "root"})

        # Limb Follow Driver
        pb = self.obj.pose.bones

        name = "FK_limb_follow"

        pb[mch][name] = 0.0
        prop = rna_idprop_ui_prop_get(pb[mch], name, create=True)

        prop["min"] = 0.0
        prop["max"] = 1.0
        prop["soft_min"] = 0.0
        prop["soft_max"] = 1.0
        prop["description"] = name

        drv = pb[mch].constraints[0].driver_add("influence").driver

        drv.type = "AVERAGE"
        var = drv.variables.new()
        var.name = name
        var.type = "SINGLE_PROP"
        var.targets[0].id = self.obj
        var.targets[0].data_path = pb[mch].path_from_id() + "[" + '"' + name + '"' + "]"

        return mch
Beispiel #13
0
    def invoke(self, context, event):
        data_path = self.data_path

        if not data_path:
            self.report({'ERROR'}, "Data path not set")
            return {'CANCELLED'}

        self._last_prop = [self.property]

        item = eval("context.%s" % data_path)

        # setup defaults
        prop_ui = rna_idprop_ui_prop_get(item, self.property, False)  # dont create
        if prop_ui:
            self.min = prop_ui.get("min", -1000000000)
            self.max = prop_ui.get("max", 1000000000)
            self.description = prop_ui.get("description", "")

        wm = context.window_manager
        return wm.invoke_props_dialog(self)
    def org_parenting_and_switch(self, org, ik, fk, parent):
        bpy.ops.object.mode_set(mode="EDIT")
        eb = self.obj.data.edit_bones
        # re-parent ORGs in a connected chain
        for i, o in enumerate(org):
            if i > 0:
                eb[o].parent = eb[org[i - 1]]
                if i <= len(org) - 1:
                    eb[o].use_connect = True

        bpy.ops.object.mode_set(mode="OBJECT")
        pb = self.obj.pose.bones
        pb_parent = pb[parent]

        # Create ik/fk switch property
        pb_parent["IK/FK"] = 0.0
        prop = rna_idprop_ui_prop_get(pb_parent, "IK/FK", create=True)
        prop["min"] = 0.0
        prop["max"] = 1.0
        prop["soft_min"] = 0.0
        prop["soft_max"] = 1.0
        prop["description"] = "IK/FK Switch"

        # Constrain org to IK and FK bones
        iks = [ik["ctrl"]["limb"]]
        iks += [ik[k] for k in ["mch_ik", "mch_target"]]

        for o, i, f in zip(org, iks, fk):
            make_constraint(self, o, {"constraint": "COPY_TRANSFORMS", "subtarget": i})
            make_constraint(self, o, {"constraint": "COPY_TRANSFORMS", "subtarget": f})

            # Add driver to relevant constraint
            drv = pb[o].constraints[-1].driver_add("influence").driver
            drv.type = "AVERAGE"

            var = drv.variables.new()
            var.name = prop.name
            var.type = "SINGLE_PROP"
            var.targets[0].id = self.obj
            var.targets[0].data_path = pb_parent.path_from_id() + "[" + '"' + prop.name + '"' + "]"
Beispiel #15
0
    def execute(self, context):
        data_path = self.data_path
        value = self.value
        prop = self.property
        prop_old = self._last_prop[0]

        try:
            value_eval = eval(value)
        except:
            value_eval = value

        # First remove
        item = eval("context.%s" % data_path)

        rna_idprop_ui_prop_clear(item, prop_old)
        exec_str = "del item['%s']" % prop_old
        # print(exec_str)
        exec(exec_str)

        # Reassign
        exec_str = "item['%s'] = %s" % (prop, repr(value_eval))
        # print(exec_str)
        exec(exec_str)
        self._last_prop[:] = [prop]

        prop_type = type(item[prop])

        prop_ui = rna_idprop_ui_prop_get(item, prop)

        if prop_type in (float, int):

            prop_ui['soft_min'] = prop_ui['min'] = prop_type(self.min)
            prop_ui['soft_max'] = prop_ui['max'] = prop_type(self.max)

        prop_ui['description'] = self.description

        return {'FINISHED'}
Beispiel #16
0
    def create_drivers(self, bones):

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

        ctrl = pb[bones['ik']['ctrl']['terminal'][-1]]

        props  = [ "IK_follow", "root/parent" ]

        for prop in props:
            if prop == 'IK_follow':

                ctrl[prop]=True
                rna_prop = rna_idprop_ui_prop_get( ctrl, prop, create=True )
                rna_prop["min"]         = False
                rna_prop["max"]         = True
                rna_prop["description"] = prop

                drv = ctrl.constraints[ 0 ].driver_add("mute").driver
                drv.type = 'AVERAGE'

                var = drv.variables.new()
                var.name = prop
                var.type = "SINGLE_PROP"
                var.targets[0].id = self.obj
                var.targets[0].data_path = \
                ctrl.path_from_id() + '['+ '"' + prop + '"' + ']'

                drv_modifier = self.obj.animation_data.drivers[-1].modifiers[0]

                drv_modifier.mode            = 'POLYNOMIAL'
                drv_modifier.poly_order      = 1
                drv_modifier.coefficients[0] = 1.0
                drv_modifier.coefficients[1] = -1.0

                drv = ctrl.constraints[ 1 ].driver_add("mute").driver
                drv.type = 'AVERAGE'

                var = drv.variables.new()
                var.name = prop
                var.type = "SINGLE_PROP"
                var.targets[0].id = self.obj
                var.targets[0].data_path = \
                ctrl.path_from_id() + '['+ '"' + prop + '"' + ']'

                drv_modifier = self.obj.animation_data.drivers[-1].modifiers[0]

                drv_modifier.mode            = 'POLYNOMIAL'
                drv_modifier.poly_order      = 1
                drv_modifier.coefficients[0] = 1.0
                drv_modifier.coefficients[1] = -1.0

            else:
                ctrl[prop]=0.0
                rna_prop = rna_idprop_ui_prop_get( ctrl, prop, create=True )
                rna_prop["min"]         = 0.0
                rna_prop["max"]         = 1.0
                rna_prop["soft_min"]    = 0.0
                rna_prop["soft_max"]    = 1.0
                rna_prop["description"] = prop

                drv = ctrl.constraints[ 0 ].driver_add("influence").driver
                drv.type = 'AVERAGE'

                var = drv.variables.new()
                var.name = prop
                var.type = "SINGLE_PROP"
                var.targets[0].id = self.obj
                var.targets[0].data_path = \
                ctrl.path_from_id() + '['+ '"' + prop + '"' + ']'

                drv_modifier = self.obj.animation_data.drivers[-1].modifiers[0]

                drv_modifier.mode            = 'POLYNOMIAL'
                drv_modifier.poly_order      = 1
                drv_modifier.coefficients[0] = 1.0
                drv_modifier.coefficients[1] = -1.0

                drv = ctrl.constraints[ 1 ].driver_add("influence").driver
                drv.type = 'AVERAGE'

                var = drv.variables.new()
                var.name = prop
                var.type = "SINGLE_PROP"
                var.targets[0].id = self.obj
                var.targets[0].data_path = \
                ctrl.path_from_id() + '['+ '"' + prop + '"' + ']'
Beispiel #17
0
    def generate(self):
        bpy.ops.object.mode_set(mode='EDIT')

        # Create non-scaling parent bone
        if self.org_parent is not None:
            loc = Vector(self.obj.data.edit_bones[self.org_bones[0]].head)
            parent = make_nonscaling_child(self.obj, self.org_parent, loc, "_ik")
            if self.pole_parent is None:
                self.pole_parent = parent
        else:
            parent = None

        # Create the bones
        ulimb = copy_bone(self.obj, self.org_bones[0], make_mechanism_name(strip_org(insert_before_lr(self.org_bones[0], ".ik"))))
        flimb = copy_bone(self.obj, self.org_bones[1], make_mechanism_name(strip_org(insert_before_lr(self.org_bones[1], ".ik"))))
        elimb = copy_bone(self.obj, self.org_bones[2], strip_org(insert_before_lr(self.org_bones[2], ".ik")))
        elimb_mch = copy_bone(self.obj, self.org_bones[2], make_mechanism_name(strip_org(self.org_bones[2])))

        ulimb_nostr = copy_bone(self.obj, self.org_bones[0], make_mechanism_name(strip_org(insert_before_lr(self.org_bones[0], ".nostr.ik"))))
        flimb_nostr = copy_bone(self.obj, self.org_bones[1], make_mechanism_name(strip_org(insert_before_lr(self.org_bones[1], ".nostr.ik"))))

        ulimb_str = copy_bone(self.obj, self.org_bones[0], make_mechanism_name(strip_org(insert_before_lr(self.org_bones[0], ".stretch.ik"))))
        flimb_str = copy_bone(self.obj, self.org_bones[1], make_mechanism_name(strip_org(insert_before_lr(self.org_bones[1], ".stretch.ik"))))

        pole_target_name = self.pole_target_base_name + "." + insert_before_lr(self.org_bones[0], ".ik").split(".", 1)[1]
        pole = copy_bone(self.obj, self.org_bones[0], pole_target_name)
        if self.pole_parent == self.org_bones[2]:
            self.pole_parent = elimb_mch
        if self.pole_parent is not None:
            pole_par = copy_bone(self.obj, self.pole_parent, make_mechanism_name(insert_before_lr(pole_target_name, "_parent")))

        viselimb = 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.ik")))

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

        if parent is not None:
            parent_e = eb[parent]
        ulimb_e = eb[ulimb]
        flimb_e = eb[flimb]
        elimb_e = eb[elimb]
        elimb_mch_e = eb[elimb_mch]
        ulimb_nostr_e = eb[ulimb_nostr]
        flimb_nostr_e = eb[flimb_nostr]
        ulimb_str_e = eb[ulimb_str]
        flimb_str_e = eb[flimb_str]
        pole_e = eb[pole]
        if self.pole_parent is not None:
            pole_par_e = eb[pole_par]
        viselimb_e = eb[viselimb]
        vispole_e = eb[vispole]

        # Parenting
        ulimb_e.use_connect = False
        ulimb_nostr_e.use_connect = False
        if parent is not None:
            ulimb_e.parent = parent_e
            ulimb_nostr_e.parent = parent_e

        flimb_e.parent = ulimb_e
        flimb_nostr_e.parent = ulimb_nostr_e

        elimb_e.use_connect = False
        elimb_e.parent = None

        elimb_mch_e.use_connect = False
        elimb_mch_e.parent = elimb_e

        ulimb_str_e.use_connect = False
        ulimb_str_e.parent = ulimb_e.parent

        flimb_str_e.use_connect = False
        flimb_str_e.parent = ulimb_e.parent

        pole_e.use_connect = False
        if self.pole_parent is not None:
            pole_par_e.parent = None
            pole_e.parent = pole_par_e

        viselimb_e.use_connect = False
        viselimb_e.parent = None

        vispole_e.use_connect = False
        vispole_e.parent = None

        # Misc
        elimb_e.use_local_location = False

        viselimb_e.hide_select = True
        vispole_e.hide_select = True

        # Positioning
        v1 = flimb_e.tail - ulimb_e.head
        if 'X' in self.primary_rotation_axis or 'Y' in self.primary_rotation_axis:
            v2 = v1.cross(flimb_e.x_axis)
            if (v2 @ flimb_e.z_axis) > 0.0:
                v2 *= -1.0
        else:
            v2 = v1.cross(flimb_e.z_axis)
            if (v2 @ flimb_e.x_axis) < 0.0:
                v2 *= -1.0
        v2.normalize()
        v2 *= v1.length

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

        pole_e.head = flimb_e.head + v2
        pole_e.tail = pole_e.head + (Vector((0, 1, 0)) * (v1.length / 8))
        pole_e.roll = 0.0
        if parent is not None:
            pole_par_e.length *= 0.75

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

        # Determine the pole offset value
        plane = (flimb_e.tail - ulimb_e.head).normalized()
        vec1 = ulimb_e.x_axis.normalized()
        vec2 = (pole_e.head - ulimb_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

        ulimb_p = pb[ulimb]
        flimb_p = pb[flimb]
        elimb_p = pb[elimb]
        ulimb_nostr_p = pb[ulimb_nostr]
        flimb_nostr_p = pb[flimb_nostr]
        ulimb_str_p = pb[ulimb_str]
        flimb_str_p = pb[flimb_str]
        pole_p = pb[pole]
        if self.pole_parent is not None:
            pole_par_p = pb[pole_par]
        viselimb_p = pb[viselimb]
        vispole_p = pb[vispole]

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

        # Limb stretches
        ulimb_nostr_p.ik_stretch = 0.0
        flimb_nostr_p.ik_stretch = 0.0

        # This next bit is weird.  The values calculated cause
        # ulimb and flimb to preserve their relative lengths
        # while stretching.
        l1 = ulimb_p.length
        l2 = flimb_p.length
        if l1 < l2:
            ulimb_p.ik_stretch = (l1 ** (1 / 3)) / (l2 ** (1 / 3))
            flimb_p.ik_stretch = 1.0
        else:
            ulimb_p.ik_stretch = 1.0
            flimb_p.ik_stretch = (l2 ** (1 / 3)) / (l1 ** (1 / 3))

        # 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 is True:
            prop = rna_idprop_ui_prop_get(elimb_p, "ikfk_switch", create=True)
            elimb_p["ikfk_switch"] = 0.0
            prop["soft_min"] = prop["min"] = 0.0
            prop["soft_max"] = prop["max"] = 1.0

        if self.pole_parent is not None:
            prop = rna_idprop_ui_prop_get(pole_p, "follow", create=True)
            pole_p["follow"] = 1.0
            prop["soft_min"] = prop["min"] = 0.0
            prop["soft_max"] = prop["max"] = 1.0

        prop = rna_idprop_ui_prop_get(elimb_p, "stretch_length", create=True)
        elimb_p["stretch_length"] = 1.0
        prop["min"] = 0.05
        prop["max"] = 20.0
        prop["soft_min"] = 0.25
        prop["soft_max"] = 4.0

        prop = rna_idprop_ui_prop_get(elimb_p, "auto_stretch", create=True)
        elimb_p["auto_stretch"] = 1.0
        prop["soft_min"] = prop["min"] = 0.0
        prop["soft_max"] = prop["max"] = 1.0

        # Stretch parameter drivers
        def add_stretch_drivers(pose_bone):
            driver = pose_bone.driver_add("scale", 1).driver
            var = driver.variables.new()
            var.name = "stretch_length"
            var.targets[0].id_type = 'OBJECT'
            var.targets[0].id = self.obj
            var.targets[0].data_path = elimb_p.path_from_id() + '["stretch_length"]'
            driver.type = 'SCRIPTED'
            driver.expression = "stretch_length"

            driver = pose_bone.driver_add("scale", 0).driver
            var = driver.variables.new()
            var.name = "stretch_length"
            var.targets[0].id_type = 'OBJECT'
            var.targets[0].id = self.obj
            var.targets[0].data_path = elimb_p.path_from_id() + '["stretch_length"]'
            driver.type = 'SCRIPTED'
            driver.expression = "stretch_length"

            driver = pose_bone.driver_add("scale", 2).driver
            var = driver.variables.new()
            var.name = "stretch_length"
            var.targets[0].id_type = 'OBJECT'
            var.targets[0].id = self.obj
            var.targets[0].data_path = elimb_p.path_from_id() + '["stretch_length"]'
            driver.type = 'SCRIPTED'
            driver.expression = "stretch_length"
        add_stretch_drivers(ulimb_nostr_p)

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

        # Constrain normal IK chain to no-stretch IK chain
        con = ulimb_p.constraints.new('COPY_TRANSFORMS')
        con.name = "pre_stretch"
        con.target = self.obj
        con.subtarget = ulimb_nostr

        con = flimb_p.constraints.new('COPY_TRANSFORMS')
        con.name = "pre_stretch"
        con.target = self.obj
        con.subtarget = flimb_nostr

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

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

        # Driver to enable/disable auto stretching IK chain
        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 = elimb_p.path_from_id() + '["auto_stretch"]'

        # Stretch bone constraints
        con = ulimb_str_p.constraints.new('COPY_TRANSFORMS')
        con.name = "anchor"
        con.target = self.obj
        con.subtarget = ulimb
        con = ulimb_str_p.constraints.new('MAINTAIN_VOLUME')
        con.name = "stretch"
        con.owner_space = 'LOCAL'

        con = flimb_str_p.constraints.new('COPY_TRANSFORMS')
        con.name = "anchor"
        con.target = self.obj
        con.subtarget = flimb
        con = flimb_str_p.constraints.new('MAINTAIN_VOLUME')
        con.name = "stretch"
        con.owner_space = 'LOCAL'

        # Pole target parent
        if self.pole_parent is not None:
            con = pole_par_p.constraints.new('COPY_TRANSFORMS')
            con.name = "parent"
            con.target = self.obj
            con.subtarget = self.pole_parent

            driver = con.driver_add("influence").driver
            var = driver.variables.new()
            var.name = "follow"
            var.targets[0].id_type = 'OBJECT'
            var.targets[0].id = self.obj
            var.targets[0].data_path = pole_p.path_from_id() + '["follow"]'
            driver.type = 'SUM'

        # Constrain org bones
        con = pb[self.org_bones[0]].constraints.new('COPY_TRANSFORMS')
        con.name = "ik"
        con.target = self.obj
        con.subtarget = ulimb_str
        if self.switch is 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 = elimb_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 = flimb_str
        if self.switch is 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 = elimb_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 = elimb_mch
        if self.switch is 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 = elimb_p.path_from_id() + '["ikfk_switch"]'

        # VIS limb-end constraints
        con = viselimb_p.constraints.new('COPY_LOCATION')
        con.name = "copy_loc"
        con.target = self.obj
        con.subtarget = self.org_bones[2]

        con = viselimb_p.constraints.new('STRETCH_TO')
        con.name = "stretch_to"
        con.target = self.obj
        con.subtarget = elimb
        con.volume = 'NO_VOLUME'
        con.rest_length = viselimb_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:
            elimb_p.bone.layers = self.layers
            pole_p.bone.layers = self.layers
            viselimb_p.bone.layers = self.layers
            vispole_p.bone.layers = self.layers

        # Create widgets
        create_line_widget(self.obj, vispole)
        create_line_widget(self.obj, viselimb)
        create_sphere_widget(self.obj, pole)

        ob = create_widget(self.obj, elimb)
        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 [ulimb, flimb, elimb, elimb_mch, pole, vispole, viselimb]
    def gen_control(self):
        """ Generate the control rig.

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

        # Create bones
        neck_ctrl = copy_bone(self.obj, self.org_bones[0], strip_org(self.org_bones[0]))
        neck_follow = copy_bone(self.obj, self.org_bones[-1], make_mechanism_name(strip_org(self.org_bones[0] + ".follow")))
        neck_child = new_bone(self.obj, make_mechanism_name(strip_org(self.org_bones[0] + ".child")))

        head_ctrl = copy_bone(self.obj, self.org_bones[-1], strip_org(self.org_bones[-1]))
        head_mch = new_bone(self.obj, make_mechanism_name(strip_org(self.org_bones[-1])))
        if self.isolate:
            head_socket1 = copy_bone(self.obj, self.org_bones[-1], make_mechanism_name(strip_org(self.org_bones[-1] + ".socket1")))
            head_socket2 = copy_bone(self.obj, self.org_bones[-1], make_mechanism_name(strip_org(self.org_bones[-1] + ".socket2")))

        # Create neck chain bones
        neck = []
        helpers = []
        for name in self.org_bones:
            neck += [copy_bone(self.obj, name, make_mechanism_name(strip_org(name)))]
            helpers += [copy_bone(self.obj, neck_child, make_mechanism_name(strip_org(name + ".02")))]

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

        neck_ctrl_e = eb[neck_ctrl]
        neck_follow_e = eb[neck_follow]
        neck_child_e = eb[neck_child]
        head_ctrl_e = eb[head_ctrl]
        head_mch_e = eb[head_mch]
        if self.isolate:
            head_socket1_e = eb[head_socket1]
            head_socket2_e = eb[head_socket2]

        # Parenting
        head_ctrl_e.use_connect = False
        head_ctrl_e.parent = neck_ctrl_e.parent
        head_mch_e.use_connect = False
        head_mch_e.parent = head_ctrl_e

        if self.isolate:
            head_socket1_e.use_connect = False
            head_socket1_e.parent = neck_ctrl_e.parent

            head_socket2_e.use_connect = False
            head_socket2_e.parent = None

            head_ctrl_e.parent = head_socket2_e

        for (name1, name2) in zip(neck, helpers):
            eb[name1].use_connect = False
            eb[name1].parent = eb[name2]
            eb[name2].use_connect = False
            eb[name2].parent = neck_ctrl_e.parent

        neck_follow_e.use_connect = False
        neck_follow_e.parent = neck_ctrl_e.parent
        neck_child_e.use_connect = False
        neck_child_e.parent = neck_ctrl_e
        neck_ctrl_e.parent = neck_follow_e

        # Position
        put_bone(self.obj, neck_follow, neck_ctrl_e.head)
        put_bone(self.obj, neck_child, neck_ctrl_e.head)
        put_bone(self.obj, head_ctrl, neck_ctrl_e.head)
        put_bone(self.obj, head_mch, neck_ctrl_e.head)
        head_mch_e.length = head_ctrl_e.length / 2
        neck_child_e.length = neck_ctrl_e.length / 2

        if self.isolate:
            put_bone(self.obj, head_socket1, neck_ctrl_e.head)
            head_mch_e.length /= 2

            put_bone(self.obj, head_socket2, neck_ctrl_e.head)
            head_mch_e.length /= 3

        for (name1, name2) in zip(neck, helpers):
            put_bone(self.obj, name2, eb[name1].head)
            eb[name2].length = eb[name1].length / 2

        # Switch to object mode
        bpy.ops.object.mode_set(mode='OBJECT')
        pb = self.obj.pose.bones
        neck_ctrl_p = pb[neck_ctrl]
        neck_follow_p = pb[neck_follow]
        # neck_child_p = pb[neck_child]  # UNUSED
        head_ctrl_p = pb[head_ctrl]
        if self.isolate:
            # head_socket1_p = pb[head_socket1]  # UNUSED
            head_socket2_p = pb[head_socket2]

        # Custom bone appearance
        neck_ctrl_p.custom_shape_transform = pb[self.org_bones[(len(self.org_bones) - 1) // 2]]
        head_ctrl_p.custom_shape_transform = pb[self.org_bones[-1]]

        # Custom properties
        prop = rna_idprop_ui_prop_get(head_ctrl_p, "inf_extent", create=True)
        head_ctrl_p["inf_extent"] = 0.5
        prop["min"] = 0.0
        prop["max"] = 1.0
        prop["soft_min"] = 0.0
        prop["soft_max"] = 1.0

        prop = rna_idprop_ui_prop_get(head_ctrl_p, "neck_follow", create=True)
        head_ctrl_p["neck_follow"] = 1.0
        prop["min"] = 0.0
        prop["max"] = 2.0
        prop["soft_min"] = 0.0
        prop["soft_max"] = 1.0

        if self.isolate:
            prop = rna_idprop_ui_prop_get(head_ctrl_p, "isolate", create=True)
            head_ctrl_p["isolate"] = 0.0
            prop["min"] = 0.0
            prop["max"] = 1.0
            prop["soft_min"] = 0.0
            prop["soft_max"] = 1.0

        # Constraints

        # Neck follow
        con = neck_follow_p.constraints.new('COPY_ROTATION')
        con.name = "copy_rotation"
        con.target = self.obj
        con.subtarget = head_ctrl

        fcurve = con.driver_add("influence")
        driver = fcurve.driver
        var = driver.variables.new()
        driver.type = 'SCRIPTED'
        var.name = "follow"
        var.targets[0].id_type = 'OBJECT'
        var.targets[0].id = self.obj
        var.targets[0].data_path = head_ctrl_p.path_from_id() + '["neck_follow"]'
        driver.expression = "follow / 2"

        # Isolate
        if self.isolate:
            con = head_socket2_p.constraints.new('COPY_LOCATION')
            con.name = "copy_location"
            con.target = self.obj
            con.subtarget = head_socket1

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

            fcurve = con.driver_add("influence")
            driver = fcurve.driver
            var = driver.variables.new()
            driver.type = 'SCRIPTED'
            var.name = "isolate"
            var.targets[0].id_type = 'OBJECT'
            var.targets[0].id = self.obj
            var.targets[0].data_path = head_ctrl_p.path_from_id() + '["isolate"]'
            driver.expression = "1.0 - isolate"

        # Neck chain
        first = True
        prev = None
        i = 0
        l = len(neck)
        for (name1, name2, org_name) in zip(neck, helpers, self.org_bones):
            con = pb[org_name].constraints.new('COPY_TRANSFORMS')
            con.name = "copy_transforms"
            con.target = self.obj
            con.subtarget = name1

            n_con = pb[name2].constraints.new('COPY_TRANSFORMS')
            n_con.name = "neck"
            n_con.target = self.obj
            n_con.subtarget = neck_child

            h_con = pb[name2].constraints.new('COPY_TRANSFORMS')
            h_con.name = "head"
            h_con.target = self.obj
            h_con.subtarget = head_mch

            con = pb[name2].constraints.new('COPY_LOCATION')
            con.name = "anchor"
            con.target = self.obj
            if first:
                con.subtarget = neck_ctrl
            else:
                con.subtarget = prev
                con.head_tail = 1.0

            # Drivers
            n = (i + 1) / l

            # Neck influence
            fcurve = n_con.driver_add("influence")
            driver = fcurve.driver
            var = driver.variables.new()
            driver.type = 'SCRIPTED'
            var.name = "ext"
            var.targets[0].id_type = 'OBJECT'
            var.targets[0].id = self.obj
            var.targets[0].data_path = head_ctrl_p.path_from_id() + '["inf_extent"]'
            driver.expression = "1.0 if (%.4f > (1.0-ext) or (1.0-ext) == 0.0) else (%.4f / (1.0-ext))" % (n, n)

            # Head influence
            if (i + 1) == l:
                h_con.influence = 1.0
            else:
                fcurve = h_con.driver_add("influence")
                driver = fcurve.driver
                var = driver.variables.new()
                driver.type = 'SCRIPTED'
                var.name = "ext"
                var.targets[0].id_type = 'OBJECT'
                var.targets[0].id = self.obj
                var.targets[0].data_path = head_ctrl_p.path_from_id() + '["inf_extent"]'
                driver.expression = "0.0 if (%.4f <= (1.0-ext)) else ((%.4f - (1.0-ext)) / ext)" % (n, n)

            first = False
            prev = name1
            i += 1

        # Create control widgets
        create_circle_widget(self.obj, neck_ctrl, radius=1.0, head_tail=0.5, bone_transform_name=self.org_bones[(len(self.org_bones) - 1) // 2])
        create_circle_widget(self.obj, head_ctrl, radius=1.0, head_tail=0.5, bone_transform_name=self.org_bones[-1])

        # Return control bones
        return (head_ctrl, neck_ctrl)
def build_crane_rig(context):
    # Define some useful variables:
    boneLayer = (False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False)  
        
    # Add the new armature object:
    bpy.ops.object.armature_add()
    rig = context.active_object
    
    #it will try to name the rig "Dolly_Rig" but if that name exists it will add .000 to the name
    if "Crane_Rig" not in context.scene.objects:
        rig.name = "Crane_Rig"
    else:
        rig.name = "Crane_Rig.000"
    rig["rig_id"] = "Crane_Rig"
    
    bpy.ops.object.mode_set(mode='EDIT')
    
    # Remove default bone:
    bones = rig.data.edit_bones
    bones.remove(bones[0])
    
    # Add new bones:
    root = bones.new("Root")
    root.tail = (0.0, 0.0, -5.0)
   
    ctrlAimChild = bones.new("AIM_child")
    ctrlAimChild.head = (0.0, 10.0, 1.0)
    ctrlAimChild.tail = (0.0, 12.0, 1.0)
    ctrlAimChild.layers = boneLayer
    
    ctrlAim = bones.new("AIM")
    ctrlAim.head = (0.0, 10.0, 1.0)
    ctrlAim.tail = (0.0, 12.0, 1.0)
    
    ctrl = bones.new("CTRL")
    ctrl.head = (0.0, 1.0, 1.0)
    ctrl.tail = (0.0, 3.0, 1.0)
    
    arm = bones.new("Crane_Arm")
    arm.head = (0.0, 0.0, 1.0)
    arm.tail = (0.0, 1.0, 1.0)
    
    height = bones.new("Height")
    height.head = (0.0, 0.0, 0.0)
    height.tail = (0.0, 0.0, 1.0)
    
    
    # Setup hierarchy:
    ctrl.parent = arm
    ctrl.use_inherit_rotation = False
    ctrl.use_inherit_scale = False
        
    arm.parent = height
    arm.use_inherit_scale = False
        
    height.parent = root
    ctrlAim.parent = root
    ctrlAimChild.parent = ctrlAim
    
    #change display to BBone: it just looks nicer 
    bpy.context.object.data.draw_type = 'BBONE'
    #change display to wire for object
    bpy.context.object.draw_type = 'WIRE'
    

    # jump into pose mode and change bones to euler
    bpy.ops.object.mode_set(mode='POSE')
    for x in bpy.context.object.pose.bones:
        x.rotation_mode = 'XYZ'
        
    
    
    #lock the relevant loc, rot and scale
    bpy.context.object.pose.bones["Crane_Arm"].lock_rotation = [False, True, False]
    bpy.context.object.pose.bones["Crane_Arm"].lock_scale = [True, False, True]
    bpy.context.object.pose.bones["Height"].lock_location = [True, True, True]
    bpy.context.object.pose.bones["Height"].lock_rotation = [True, True, True]
    bpy.context.object.pose.bones["Height"].lock_scale = [True, False, True]
    
    
    #add the custom bone shapes
    bpy.context.object.pose.bones["Root"].custom_shape = bpy.data.objects["WDGT_Camera_Root"]  #add the widget as custom shape
    bpy.context.object.data.bones["Root"].show_wire = True                              #set the wireframe checkbox to true
    bpy.context.object.pose.bones["AIM"].custom_shape = bpy.data.objects["WDGT_AIM"] 
    bpy.context.object.data.bones["AIM"].show_wire = True 
    bpy.context.object.pose.bones["AIM"].custom_shape_transform = bpy.data.objects[rig.name].pose.bones["AIM_child"] #sets the "At" field to the child
    bpy.context.object.pose.bones["CTRL"].custom_shape = bpy.data.objects["WDGT_CTRL"] 
    bpy.context.object.data.bones["CTRL"].show_wire = True 
    
    #jump into object mode
    bpy.ops.object.mode_set(mode='OBJECT')
    
    # Add constraints to bones:
    con = rig.pose.bones['AIM_child'].constraints.new('COPY_ROTATION')
    con.target = rig
    con.subtarget = "CTRL"
       
    con = rig.pose.bones['CTRL'].constraints.new('TRACK_TO')
    con.target = rig
    con.subtarget = "AIM"
    con.use_target_z = True
    
    #Add custom Bone property to CTRL bone
    ob = bpy.context.object.pose.bones['CTRL']  
    prop = rna_idprop_ui_prop_get(ob,"Lock", create=True)
    ob["Lock"] = 1.0
    prop["soft_min"] = prop["min"] = 0.0
    prop["soft_max"] = prop["max"] = 1.0
    
   
    #Add Driver to Lock/Unlock Camera from Aim Target
    rig = bpy.context.scene.objects.active
    pose_bone = bpy.data.objects[rig.name].pose.bones['CTRL']
    
    constraint = pose_bone.constraints["Track To"]
    inf_driver = constraint.driver_add('influence')
    inf_driver.driver.type = 'SCRIPTED'
    var = inf_driver.driver.variables.new()
    var.name = 'var'
    var.type = 'SINGLE_PROP'
    
    #Target the Custom bone property
    var.targets[0].id = bpy.data.objects[rig.name]
    var.targets[0].data_path = 'pose.bones["CTRL"]["Lock"]'
    inf_driver.driver.expression = 'var'
        
    # Add the camera object:
    bpy.ops.object.mode_set(mode='OBJECT')
    
    bpy.ops.object.camera_add(view_align=False, enter_editmode=False, location=(0,0,0), rotation=(0,0,0))
    cam = bpy.context.active_object
    
    #this will name the Camera Object
    if 'Crane_Camera' not in context.scene.objects:
        cam.name = "Crane_Camera"        
    else:
        cam.name = "Crane_Camera.000"
    
    #this will name the camera Data Object
    if "Crane_Camera" not in bpy.context.scene.objects.data.camera:
        cam.data.name = "Crane_Camera"    
    else:
        cam.data.name = "Crane_Camera.000"
    
    cam_data_name = bpy.context.object.data.name
    bpy.data.cameras[cam_data_name].draw_size = 1.0 
    cam.rotation_euler[0] = 1.5708 #rotate the camera 90 degrees in x
    cam.location = (0.0, -2.0, 0.0) #move the camera to the correct postion
    cam.parent = rig
    cam.parent_type = "BONE"
    cam.parent_bone = "CTRL"
    
    #Set new camera as active camera 
    bpy.context.scene.camera = cam
    
    #make the camera non-selectable (this can be unlocked in the UI)
    bpy.context.object.hide_select = True
    
    #make the rig the active object before finishing
    bpy.context.scene.objects.active =  rig
    cam.select = False
    rig.select = True
    
    return rig
    def create_drivers(self, bones):

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

        ctrl = pb[bones["ik"]["mch_hand"][0]]

        props = ["IK_follow", "root/parent"]

        for prop in props:
            if prop == "IK_follow":

                ctrl[prop] = True
                rna_prop = rna_idprop_ui_prop_get(ctrl, prop, create=True)
                rna_prop["min"] = False
                rna_prop["max"] = True
                rna_prop["description"] = prop

                drv = ctrl.constraints[0].driver_add("mute").driver
                drv.type = "AVERAGE"

                var = drv.variables.new()
                var.name = prop
                var.type = "SINGLE_PROP"
                var.targets[0].id = self.obj
                var.targets[0].data_path = ctrl.path_from_id() + "[" + '"' + prop + '"' + "]"

                drv_modifier = self.obj.animation_data.drivers[-1].modifiers[0]

                drv_modifier.mode = "POLYNOMIAL"
                drv_modifier.poly_order = 1
                drv_modifier.coefficients[0] = 1.0
                drv_modifier.coefficients[1] = -1.0

                if len(ctrl.constraints) > 1:
                    drv = ctrl.constraints[1].driver_add("mute").driver
                    drv.type = "AVERAGE"

                    var = drv.variables.new()
                    var.name = prop
                    var.type = "SINGLE_PROP"
                    var.targets[0].id = self.obj
                    var.targets[0].data_path = ctrl.path_from_id() + "[" + '"' + prop + '"' + "]"

                    drv_modifier = self.obj.animation_data.drivers[-1].modifiers[0]

                    drv_modifier.mode = "POLYNOMIAL"
                    drv_modifier.poly_order = 1
                    drv_modifier.coefficients[0] = 1.0
                    drv_modifier.coefficients[1] = -1.0

            elif len(ctrl.constraints) > 1:
                ctrl[prop] = 0.0
                rna_prop = rna_idprop_ui_prop_get(ctrl, prop, create=True)
                rna_prop["min"] = 0.0
                rna_prop["max"] = 1.0
                rna_prop["soft_min"] = 0.0
                rna_prop["soft_max"] = 1.0
                rna_prop["description"] = prop

                # drv = ctrl.constraints[ 0 ].driver_add("influence").driver
                # drv.type = 'AVERAGE'
                #
                # var = drv.variables.new()
                # var.name = prop
                # var.type = "SINGLE_PROP"
                # var.targets[0].id = self.obj
                # var.targets[0].data_path = \
                # ctrl.path_from_id() + '['+ '"' + prop + '"' + ']'
                #
                # drv_modifier = self.obj.animation_data.drivers[-1].modifiers[0]
                #
                # drv_modifier.mode            = 'POLYNOMIAL'
                # drv_modifier.poly_order      = 1
                # drv_modifier.coefficients[0] = 1.0
                # drv_modifier.coefficients[1] = -1.0

                drv = ctrl.constraints[1].driver_add("influence").driver
                drv.type = "AVERAGE"

                var = drv.variables.new()
                var.name = prop
                var.type = "SINGLE_PROP"
                var.targets[0].id = self.obj
                var.targets[0].data_path = ctrl.path_from_id() + "[" + '"' + prop + '"' + "]"
Beispiel #21
0
    def generate(self):
        bpy.ops.object.mode_set(mode='EDIT')

        # Create non-scaling parent bone
        if self.org_parent is not None:
            loc = Vector(self.obj.data.edit_bones[self.org_bones[0]].head)
            parent = make_nonscaling_child(self.obj, self.org_parent, loc, "_rh")
        else:
            parent = None

        if not self.use_complex_limb:
            # Simple rig

            # Create bones
            ulimb = copy_bone(self.obj, self.org_bones[0], make_deformer_name(strip_org(self.org_bones[0])))
            flimb = copy_bone(self.obj, self.org_bones[1], make_deformer_name(strip_org(self.org_bones[1])))
            elimb = copy_bone(self.obj, self.org_bones[2], make_deformer_name(strip_org(self.org_bones[2])))

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

            ulimb_e = eb[ulimb]
            flimb_e = eb[flimb]
            elimb_e = eb[elimb]

            # Parenting
            elimb_e.parent = flimb_e
            elimb_e.use_connect = True

            flimb_e.parent = ulimb_e
            flimb_e.use_connect = True

            if parent is not None:
                elimb_e.use_connect = False
                ulimb_e.parent = eb[parent]

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

            ulimb_p = pb[ulimb]
            flimb_p = pb[flimb]
            elimb_p = pb[elimb]

            # Constrain def bones to org bones
            con = ulimb_p.constraints.new('COPY_TRANSFORMS')
            con.name = "def"
            con.target = self.obj
            con.subtarget = self.org_bones[0]

            con = flimb_p.constraints.new('COPY_TRANSFORMS')
            con.name = "def"
            con.target = self.obj
            con.subtarget = self.org_bones[1]

            con = elimb_p.constraints.new('COPY_TRANSFORMS')
            con.name = "def"
            con.target = self.obj
            con.subtarget = self.org_bones[2]

            return []
        else:
            # Complex rig

            # Get the .R or .L off the end of the upper limb name if it exists
            lr = self.org_bones[0].split(".", 1)
            if len(lr) == 1:
                lr = ""
            else:
                lr = lr[1]

            # Create bones
            # Deformation bones
            ulimb1 = copy_bone(self.obj, self.org_bones[0], make_deformer_name(strip_org(insert_before_lr(self.org_bones[0], ".01"))))
            ulimb2 = copy_bone(self.obj, self.org_bones[0], make_deformer_name(strip_org(insert_before_lr(self.org_bones[0], ".02"))))
            flimb1 = copy_bone(self.obj, self.org_bones[1], make_deformer_name(strip_org(insert_before_lr(self.org_bones[1], ".01"))))
            flimb2 = copy_bone(self.obj, self.org_bones[1], make_deformer_name(strip_org(insert_before_lr(self.org_bones[1], ".02"))))
            elimb = copy_bone(self.obj, self.org_bones[2], make_deformer_name(strip_org(self.org_bones[2])))

            # Bones for switchable smooth bbone transition at elbow/knee
            ulimb2_smoother = copy_bone(self.obj, self.org_bones[1], make_mechanism_name(strip_org(insert_before_lr(self.org_bones[0], "_smth.02"))))
            flimb1_smoother = copy_bone(self.obj, self.org_bones[0], make_mechanism_name(strip_org(insert_before_lr(self.org_bones[1], "_smth.01"))))
            flimb1_pos = copy_bone(self.obj, self.org_bones[1], make_mechanism_name(strip_org(insert_before_lr(self.org_bones[1], ".01"))))

            # Elbow/knee junction bone
            junc = copy_bone(self.obj, self.org_bones[1], make_mechanism_name(strip_org(insert_before_lr(self.org_bones[1], ".junc"))))

            # Hose controls
            uhoseend = new_bone(self.obj, strip_org(insert_before_lr(self.org_bones[0], "_hose_end")))
            uhose = new_bone(self.obj, strip_org(insert_before_lr(self.org_bones[0], "_hose")))
            jhose = new_bone(self.obj, self.junc_base_name + "_hose." + lr)
            fhose = new_bone(self.obj, strip_org(insert_before_lr(self.org_bones[1], "_hose")))
            fhoseend = new_bone(self.obj, strip_org(insert_before_lr(self.org_bones[1], "_hose_end")))

            # Hose control parents
            uhoseend_par = copy_bone(self.obj, self.org_bones[0], make_mechanism_name(strip_org(insert_before_lr(uhoseend, "_p"))))
            uhose_par = copy_bone(self.obj, self.org_bones[0], make_mechanism_name(strip_org(insert_before_lr(uhose, "_p"))))
            jhose_par = copy_bone(self.obj, junc, make_mechanism_name(strip_org(insert_before_lr(jhose, "_p"))))
            fhose_par = copy_bone(self.obj, self.org_bones[1], make_mechanism_name(strip_org(insert_before_lr(fhose, "_p"))))
            fhoseend_par = copy_bone(self.obj, self.org_bones[1], make_mechanism_name(strip_org(insert_before_lr(fhoseend, "_p"))))

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

            if parent is not None:
                parent_e = eb[parent]
            else:
                parent_e = None

            ulimb1_e = eb[ulimb1]
            ulimb2_e = eb[ulimb2]
            flimb1_e = eb[flimb1]
            flimb2_e = eb[flimb2]
            elimb_e = eb[elimb]

            ulimb2_smoother_e = eb[ulimb2_smoother]
            flimb1_smoother_e = eb[flimb1_smoother]
            flimb1_pos_e = eb[flimb1_pos]

            junc_e = eb[junc]

            uhoseend_e = eb[uhoseend]
            uhose_e = eb[uhose]
            jhose_e = eb[jhose]
            fhose_e = eb[fhose]
            fhoseend_e = eb[fhoseend]

            uhoseend_par_e = eb[uhoseend_par]
            uhose_par_e = eb[uhose_par]
            jhose_par_e = eb[jhose_par]
            fhose_par_e = eb[fhose_par]
            fhoseend_par_e = eb[fhoseend_par]

            # Parenting
            if parent is not None:
                ulimb1_e.use_connect = False
                ulimb1_e.parent = parent_e

            ulimb2_e.use_connect = False
            ulimb2_e.parent = eb[self.org_bones[0]]

            ulimb2_smoother_e.use_connect = True
            ulimb2_smoother_e.parent = ulimb2_e

            flimb1_e.use_connect = True
            flimb1_e.parent = flimb1_smoother_e

            flimb1_smoother_e.use_connect = False
            flimb1_smoother_e.parent = flimb1_pos_e

            flimb1_pos_e.use_connect = False
            flimb1_pos_e.parent = eb[self.org_bones[1]]

            flimb2_e.use_connect = False
            flimb2_e.parent = eb[self.org_bones[1]]

            elimb_e.use_connect = False
            elimb_e.parent = eb[self.org_bones[2]]

            junc_e.use_connect = False
            junc_e.parent = eb[self.org_bones[0]]

            uhoseend_e.use_connect = False
            uhoseend_e.parent = uhoseend_par_e

            uhose_e.use_connect = False
            uhose_e.parent = uhose_par_e

            jhose_e.use_connect = False
            jhose_e.parent = jhose_par_e

            fhose_e.use_connect = False
            fhose_e.parent = fhose_par_e

            fhoseend_e.use_connect = False
            fhoseend_e.parent = fhoseend_par_e

            uhoseend_par_e.use_connect = False
            uhoseend_par_e.parent = parent_e

            uhose_par_e.use_connect = False
            uhose_par_e.parent = parent_e

            jhose_par_e.use_connect = False
            jhose_par_e.parent = parent_e

            fhose_par_e.use_connect = False
            fhose_par_e.parent = parent_e

            fhoseend_par_e.use_connect = False
            fhoseend_par_e.parent = parent_e

            # Positioning
            ulimb1_e.length *= 0.5
            ulimb2_e.head = Vector(ulimb1_e.tail)
            flimb1_e.length *= 0.5
            flimb2_e.head = Vector(flimb1_e.tail)
            align_bone_roll(self.obj, flimb2, elimb)

            ulimb2_smoother_e.tail = Vector(flimb1_e.tail)
            ulimb2_smoother_e.roll = flimb1_e.roll

            flimb1_smoother_e.head = Vector(ulimb1_e.tail)
            flimb1_pos_e.length *= 0.5

            junc_e.length *= 0.2

            uhoseend_par_e.length *= 0.25
            uhose_par_e.length *= 0.25
            jhose_par_e.length *= 0.15
            fhose_par_e.length *= 0.25
            fhoseend_par_e.length *= 0.25
            put_bone(self.obj, uhoseend_par, Vector(ulimb1_e.head))
            put_bone(self.obj, uhose_par, Vector(ulimb1_e.tail))
            put_bone(self.obj, jhose_par, Vector(ulimb2_e.tail))
            put_bone(self.obj, fhose_par, Vector(flimb1_e.tail))
            put_bone(self.obj, fhoseend_par, Vector(flimb2_e.tail))

            put_bone(self.obj, uhoseend, Vector(ulimb1_e.head))
            put_bone(self.obj, uhose, Vector(ulimb1_e.tail))
            put_bone(self.obj, jhose, Vector(ulimb2_e.tail))
            put_bone(self.obj, fhose, Vector(flimb1_e.tail))
            put_bone(self.obj, fhoseend, Vector(flimb2_e.tail))

            if 'X' in self.primary_rotation_axis:
                upoint = Vector(ulimb1_e.z_axis)
                fpoint = Vector(flimb1_e.z_axis)
            elif 'Z' in self.primary_rotation_axis:
                upoint = Vector(ulimb1_e.x_axis)
                fpoint = Vector(flimb1_e.x_axis)
            else:  # Y
                upoint = Vector(ulimb1_e.z_axis)
                fpoint = Vector(flimb1_e.z_axis)

            if '-' not in self.primary_rotation_axis:
                upoint *= -1
                fpoint *= -1

            if 'Y' in self.primary_rotation_axis:
                uside = Vector(ulimb1_e.x_axis)
                fside = Vector(flimb1_e.x_axis)
            else:
                uside = Vector(ulimb1_e.y_axis) * -1
                fside = Vector(flimb1_e.y_axis) * -1

            uhoseend_e.tail = uhoseend_e.head + upoint
            uhose_e.tail = uhose_e.head + upoint
            jhose_e.tail = fhose_e.head + upoint + fpoint
            fhose_e.tail = fhose_e.head + fpoint
            fhoseend_e.tail = fhoseend_e.head + fpoint

            align_bone_z_axis(self.obj, uhoseend, uside)
            align_bone_z_axis(self.obj, uhose, uside)
            align_bone_z_axis(self.obj, jhose, uside + fside)
            align_bone_z_axis(self.obj, fhose, fside)
            align_bone_z_axis(self.obj, fhoseend, fside)

            l = 0.125 * (ulimb1_e.length + ulimb2_e.length + flimb1_e.length + flimb2_e.length)
            uhoseend_e.length = l
            uhose_e.length = l
            jhose_e.length = l
            fhose_e.length = l
            fhoseend_e.length = l

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

            ulimb1_p = pb[ulimb1]
            ulimb2_p = pb[ulimb2]
            flimb1_p = pb[flimb1]
            flimb2_p = pb[flimb2]
            elimb_p = pb[elimb]

            ulimb2_smoother_p = pb[ulimb2_smoother]
            flimb1_smoother_p = pb[flimb1_smoother]
            flimb1_pos_p = pb[flimb1_pos]

            junc_p = pb[junc]

            uhoseend_p = pb[uhoseend]
            uhose_p = pb[uhose]
            jhose_p = pb[jhose]
            fhose_p = pb[fhose]
            fhoseend_p = pb[fhoseend]

            #uhoseend_par_p = pb[uhoseend_par]
            uhose_par_p = pb[uhose_par]
            jhose_par_p = pb[jhose_par]
            fhose_par_p = pb[fhose_par]
            fhoseend_par_p = pb[fhoseend_par]

            # Lock axes
            uhose_p.lock_rotation = (True, True, True)
            uhose_p.lock_rotation_w = True
            uhose_p.lock_scale = (True, True, True)

            jhose_p.lock_rotation = (True, True, True)
            jhose_p.lock_rotation_w = True
            jhose_p.lock_scale = (True, True, True)

            fhose_p.lock_rotation = (True, True, True)
            fhose_p.lock_rotation_w = True
            fhose_p.lock_scale = (True, True, True)

            # B-bone settings
            ulimb2_p.bone.bbone_segments = 16
            ulimb2_p.bone.bbone_easein = 0.0
            ulimb2_p.bone.bbone_easeout = 1.0

            ulimb2_smoother_p.bone.bbone_segments = 16
            ulimb2_smoother_p.bone.bbone_easein = 1.0
            ulimb2_smoother_p.bone.bbone_easeout = 0.0

            flimb1_p.bone.bbone_segments = 16
            flimb1_p.bone.bbone_easein = 1.0
            flimb1_p.bone.bbone_easeout = 0.0

            flimb1_smoother_p.bone.bbone_segments = 16
            flimb1_smoother_p.bone.bbone_easein = 0.0
            flimb1_smoother_p.bone.bbone_easeout = 1.0

            # Custom properties
            prop = rna_idprop_ui_prop_get(jhose_p, "smooth_bend", create=True)
            jhose_p["smooth_bend"] = 0.0
            prop["soft_min"] = prop["min"] = 0.0
            prop["soft_max"] = prop["max"] = 1.0

            # Constraints
            con = ulimb1_p.constraints.new('COPY_LOCATION')
            con.name = "anchor"
            con.target = self.obj
            con.subtarget = uhoseend
            con = ulimb1_p.constraints.new('COPY_SCALE')
            con.name = "anchor"
            con.target = self.obj
            con.subtarget = self.org_bones[0]
            con = ulimb1_p.constraints.new('DAMPED_TRACK')
            con.name = "track"
            con.target = self.obj
            con.subtarget = uhose
            con = ulimb1_p.constraints.new('STRETCH_TO')
            con.name = "track"
            con.target = self.obj
            con.subtarget = uhose
            con.volume = 'NO_VOLUME'

            con = ulimb2_p.constraints.new('COPY_LOCATION')
            con.name = "anchor"
            con.target = self.obj
            con.subtarget = uhose
            con = ulimb2_p.constraints.new('DAMPED_TRACK')
            con.name = "track"
            con.target = self.obj
            con.subtarget = jhose
            con = ulimb2_p.constraints.new('STRETCH_TO')
            con.name = "track"
            con.target = self.obj
            con.subtarget = jhose
            con.volume = 'NO_VOLUME'

            con = ulimb2_smoother_p.constraints.new('COPY_TRANSFORMS')
            con.name = "smoother"
            con.target = self.obj
            con.subtarget = flimb1_pos
            fcurve = con.driver_add("influence")
            driver = fcurve.driver
            var = driver.variables.new()
            driver.type = 'SUM'
            var.name = "var"
            var.targets[0].id_type = 'OBJECT'
            var.targets[0].id = self.obj
            var.targets[0].data_path = jhose_p.path_from_id() + '["smooth_bend"]'

            con = flimb1_pos_p.constraints.new('COPY_LOCATION')
            con.name = "anchor"
            con.target = self.obj
            con.subtarget = jhose
            con = flimb1_pos_p.constraints.new('DAMPED_TRACK')
            con.name = "track"
            con.target = self.obj
            con.subtarget = fhose
            con = flimb1_pos_p.constraints.new('STRETCH_TO')
            con.name = "track"
            con.target = self.obj
            con.subtarget = fhose
            con.volume = 'NO_VOLUME'

            con = flimb1_p.constraints.new('COPY_TRANSFORMS')
            con.name = "position"
            con.target = self.obj
            con.subtarget = flimb1_pos

            con = flimb1_smoother_p.constraints.new('COPY_TRANSFORMS')
            con.name = "smoother"
            con.target = self.obj
            con.subtarget = ulimb2
            fcurve = con.driver_add("influence")
            driver = fcurve.driver
            var = driver.variables.new()
            driver.type = 'SUM'
            var.name = "var"
            var.targets[0].id_type = 'OBJECT'
            var.targets[0].id = self.obj
            var.targets[0].data_path = jhose_p.path_from_id() + '["smooth_bend"]'
            con = flimb1_smoother_p.constraints.new('STRETCH_TO')
            con.name = "track"
            con.target = self.obj
            con.subtarget = jhose
            con.volume = 'NO_VOLUME'

            con = flimb2_p.constraints.new('COPY_LOCATION')
            con.name = "anchor"
            con.target = self.obj
            con.subtarget = fhose
            con = flimb2_p.constraints.new('COPY_ROTATION')
            con.name = "twist"
            con.target = self.obj
            con.subtarget = elimb
            con = flimb2_p.constraints.new('DAMPED_TRACK')
            con.name = "track"
            con.target = self.obj
            con.subtarget = fhoseend
            con = flimb2_p.constraints.new('STRETCH_TO')
            con.name = "track"
            con.target = self.obj
            con.subtarget = fhoseend
            con.volume = 'NO_VOLUME'

            con = junc_p.constraints.new('COPY_TRANSFORMS')
            con.name = "bend"
            con.target = self.obj
            con.subtarget = self.org_bones[1]
            con.influence = 0.5

            con = uhose_par_p.constraints.new('COPY_ROTATION')
            con.name = "follow"
            con.target = self.obj
            con.subtarget = self.org_bones[0]
            con.influence = 1.0
            con = uhose_par_p.constraints.new('COPY_LOCATION')
            con.name = "anchor"
            con.target = self.obj
            con.subtarget = self.org_bones[0]
            con.influence = 1.0
            con = uhose_par_p.constraints.new('COPY_LOCATION')
            con.name = "anchor"
            con.target = self.obj
            con.subtarget = jhose
            con.influence = 0.5

            con = jhose_par_p.constraints.new('COPY_ROTATION')
            con.name = "follow"
            con.target = self.obj
            con.subtarget = junc
            con.influence = 1.0
            con = jhose_par_p.constraints.new('COPY_LOCATION')
            con.name = "anchor"
            con.target = self.obj
            con.subtarget = junc
            con.influence = 1.0

            con = fhose_par_p.constraints.new('COPY_ROTATION')
            con.name = "follow"
            con.target = self.obj
            con.subtarget = self.org_bones[1]
            con.influence = 1.0
            con = fhose_par_p.constraints.new('COPY_LOCATION')
            con.name = "anchor"
            con.target = self.obj
            con.subtarget = jhose
            con.influence = 1.0
            con = fhose_par_p.constraints.new('COPY_LOCATION')
            con.name = "anchor"
            con.target = self.obj
            con.subtarget = self.org_bones[2]
            con.influence = 0.5

            con = fhoseend_par_p.constraints.new('COPY_ROTATION')
            con.name = "follow"
            con.target = self.obj
            con.subtarget = self.org_bones[1]
            con.influence = 1.0
            con = fhoseend_par_p.constraints.new('COPY_LOCATION')
            con.name = "anchor"
            con.target = self.obj
            con.subtarget = self.org_bones[2]
            con.influence = 1.0

            # Layers
            if self.layers:
                uhoseend_p.bone.layers = self.layers
                uhose_p.bone.layers = self.layers
                jhose_p.bone.layers = self.layers
                fhose_p.bone.layers = self.layers
                fhoseend_p.bone.layers = self.layers
            else:
                layers = list(pb[self.org_bones[0]].bone.layers)
                uhoseend_p.bone.layers = layers
                uhose_p.bone.layers = layers
                jhose_p.bone.layers = layers
                fhose_p.bone.layers = layers
                fhoseend_p.bone.layers = layers

            # Create widgets
            create_sphere_widget(self.obj, uhoseend)
            create_sphere_widget(self.obj, uhose)
            create_sphere_widget(self.obj, jhose)
            create_sphere_widget(self.obj, fhose)
            create_sphere_widget(self.obj, fhoseend)

            return [uhoseend, uhose, jhose, fhose, fhoseend]
Beispiel #22
0
    def create_def(self, tweaks):
        org_bones = self.org_bones

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

        def_bones = []
        for i, org in enumerate(org_bones):

            if i < len(org_bones) - 1:
                # Create segments if specified
                for j in range(self.segments):
                    name = get_bone_name(strip_org(org), 'def')
                    def_name = copy_bone(self.obj, org, name)

                    eb[def_name].length /= self.segments

                    # If we have more than one segments, place the 2nd and
                    # onwards on the tail of the previous bone
                    if j > 0:
                        put_bone(self.obj, def_name, eb[def_bones[-1]].tail)

                    def_bones += [def_name]
            else:
                name = get_bone_name(strip_org(org), 'def')
                def_name = copy_bone(self.obj, org, name)
                def_bones.append(def_name)

        # Parent deform bones
        for i, b in enumerate(def_bones):
            if i > 0:  # For all bones but the first (which has no parent)
                eb[b].parent = eb[def_bones[i - 1]]  # to previous
                eb[b].use_connect = True

        # Constraint def to tweaks
        for d, t in zip(def_bones, tweaks):
            tidx = tweaks.index(t)

            make_constraint(self, d, {
                'constraint': 'COPY_TRANSFORMS',
                'subtarget': t
            })

            if tidx != len(tweaks) - 1:
                make_constraint(self, d, {
                    'constraint': 'DAMPED_TRACK',
                    'subtarget': tweaks[tidx + 1],
                })

                make_constraint(self, d, {
                    'constraint': 'STRETCH_TO',
                    'subtarget': tweaks[tidx + 1],
                })

        # Create bbone segments
        for bone in def_bones[:-1]:
            self.obj.data.bones[bone].bbone_segments = self.bbones

        self.obj.data.bones[def_bones[0]].bbone_in = 0.0
        self.obj.data.bones[def_bones[-2]].bbone_out = 0.0
        self.obj.data.bones[def_bones[-1]].bbone_in = 0.0
        self.obj.data.bones[def_bones[-1]].bbone_out = 0.0

        # Rubber hose drivers
        pb = self.obj.pose.bones
        for i, t in enumerate(tweaks[1:-1]):
            # Create custom property on tweak bone to control rubber hose
            name = 'rubber_tweak'

            if i == trunc(len(tweaks[1:-1]) / 2):
                pb[t][name] = 0.0
            else:
                pb[t][name] = 1.0

            prop = rna_idprop_ui_prop_get(pb[t], name, create=True)

            prop["min"] = 0.0
            prop["max"] = 2.0
            prop["soft_min"] = 0.0
            prop["soft_max"] = 1.0
            prop["description"] = name

        for j, d in enumerate(def_bones[:-1]):
            drvs = {}
            if j != 0:
                tidx = j
                drvs[tidx] = self.obj.data.bones[d].driver_add(
                    "bbone_in").driver

            if j != len(def_bones[:-1]) - 1:
                tidx = j + 1
                drvs[tidx] = self.obj.data.bones[d].driver_add(
                    "bbone_out").driver

            for d in drvs:
                drv = drvs[d]
                name = 'rubber_tweak'
                drv.type = 'AVERAGE'
                var = drv.variables.new()
                var.name = name
                var.type = "SINGLE_PROP"
                var.targets[0].id = self.obj
                var.targets[0].data_path = pb[tweaks[d]].path_from_id() + \
                                           '[' + '"' + name + '"' + ']'

        return def_bones
Beispiel #23
0
    def generate(self):
        context = self.context
        metarig = self.metarig
        scene = self.scene
        id_store = self.id_store
        view_layer = self.view_layer
        t = Timer()

        self.usable_collections = list_layer_collections(
            view_layer.layer_collection, selectable=True)

        if self.layer_collection not in self.usable_collections:
            metarig_collections = filter_layer_collections_by_object(
                self.usable_collections, self.metarig)
            self.layer_collection = (metarig_collections +
                                     [view_layer.layer_collection])[0]
            self.collection = self.layer_collection.collection

        bpy.ops.object.mode_set(mode='OBJECT')

        #------------------------------------------
        # Create/find the rig object and set it up
        obj = self.__create_rig_object()

        # Get rid of anim data in case the rig already existed
        print("Clear rig animation data.")

        obj.animation_data_clear()
        obj.data.animation_data_clear()

        select_object(context, obj, deselect_all=True)

        #------------------------------------------
        # Create Group widget
        self.__create_widget_group()

        t.tick("Create main WGTS: ")

        #------------------------------------------
        # Get parented objects to restore later
        childs = {}  # {object: bone}
        for child in obj.children:
            childs[child] = child.parent_bone

        #------------------------------------------
        # Copy bones from metarig to obj (adds ORG_PREFIX)
        self.__duplicate_rig()

        obj.data.use_mirror_x = False

        t.tick("Duplicate rig: ")

        #------------------------------------------
        # Put the rig_name in the armature custom properties
        rna_idprop_ui_prop_get(obj.data, "rig_id", create=True)
        obj.data["rig_id"] = self.rig_id

        self.script = rig_ui_template.ScriptGenerator(self)

        #------------------------------------------
        bpy.ops.object.mode_set(mode='OBJECT')

        self.instantiate_rig_tree()

        t.tick("Instantiate rigs: ")

        #------------------------------------------
        bpy.ops.object.mode_set(mode='OBJECT')

        self.invoke_initialize()

        t.tick("Initialize rigs: ")

        #------------------------------------------
        bpy.ops.object.mode_set(mode='EDIT')

        self.invoke_prepare_bones()

        t.tick("Prepare bones: ")

        #------------------------------------------
        bpy.ops.object.mode_set(mode='OBJECT')
        bpy.ops.object.mode_set(mode='EDIT')

        self.__create_root_bone()

        self.invoke_generate_bones()

        t.tick("Generate bones: ")

        #------------------------------------------
        bpy.ops.object.mode_set(mode='OBJECT')
        bpy.ops.object.mode_set(mode='EDIT')

        self.invoke_parent_bones()

        self.__parent_bones_to_root()

        t.tick("Parent bones: ")

        #------------------------------------------
        bpy.ops.object.mode_set(mode='OBJECT')

        self.invoke_configure_bones()

        t.tick("Configure bones: ")

        #------------------------------------------
        bpy.ops.object.mode_set(mode='OBJECT')

        self.invoke_preapply_bones()

        t.tick("Preapply bones: ")

        #------------------------------------------
        bpy.ops.object.mode_set(mode='EDIT')

        self.invoke_apply_bones()

        t.tick("Apply bones: ")

        #------------------------------------------
        bpy.ops.object.mode_set(mode='OBJECT')

        self.invoke_rig_bones()

        t.tick("Rig bones: ")

        #------------------------------------------
        bpy.ops.object.mode_set(mode='OBJECT')

        create_root_widget(obj, "root")

        self.invoke_generate_widgets()

        t.tick("Generate widgets: ")

        #------------------------------------------
        bpy.ops.object.mode_set(mode='OBJECT')

        self.__lock_transforms()
        self.__assign_layers()
        self.__compute_visible_layers()
        self.__restore_driver_vars()

        t.tick("Assign layers: ")

        #------------------------------------------
        bpy.ops.object.mode_set(mode='OBJECT')

        self.invoke_finalize()

        t.tick("Finalize: ")

        #------------------------------------------
        bpy.ops.object.mode_set(mode='OBJECT')

        self.__assign_widgets()

        # Create Selection Sets
        create_selection_sets(obj, metarig)

        # Create Bone Groups
        create_bone_groups(obj, metarig, self.layer_group_priorities)

        t.tick("The rest: ")

        #----------------------------------
        # Deconfigure
        bpy.ops.object.mode_set(mode='OBJECT')
        obj.data.pose_position = 'POSE'

        # Restore parent to bones
        for child, sub_parent in childs.items():
            if sub_parent in obj.pose.bones:
                mat = child.matrix_world.copy()
                child.parent_bone = sub_parent
                child.matrix_world = mat

        #----------------------------------
        # Restore active collection
        view_layer.active_layer_collection = self.layer_collection
    def generate(self):
        """ Generate the rig.
            Do NOT modify any of the original bones, except for adding constraints.
            The main armature should be selected and active before this is called.

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

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

        hand = copy_bone(self.obj, self.org_bones[2], strip_org(insert_before_lr(self.org_bones[2], "_ik")))
        pole = copy_bone(self.obj, self.org_bones[0], strip_org(insert_before_lr(self.org_bones[0], "_pole")))

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

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

        uarm_e = eb[uarm]
        farm_e = eb[farm]
        hand_e = eb[hand]
        pole_e = eb[pole]
        vishand_e = eb[vishand]
        vispole_e = eb[vispole]

        # Parenting
        farm_e.parent = uarm_e

        hand_e.use_connect = False
        hand_e.parent = None

        pole_e.use_connect = False

        vishand_e.use_connect = False
        vishand_e.parent = None

        vispole_e.use_connect = False
        vispole_e.parent = None

        # Misc
        hand_e.use_local_location = False

        vishand_e.hide_select = True
        vispole_e.hide_select = True

        # Positioning
        v1 = farm_e.tail - uarm_e.head
        if 'X' in self.primary_rotation_axis or 'Y' in self.primary_rotation_axis:
            v2 = v1.cross(farm_e.x_axis)
            if (v2 * farm_e.z_axis) > 0.0:
                v2 *= -1.0
        else:
            v2 = v1.cross(farm_e.z_axis)
            if (v2 * farm_e.x_axis) < 0.0:
                v2 *= -1.0
        v2.normalize()
        v2 *= v1.length

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

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

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

        # Determine the pole offset value
        plane = (farm_e.tail - uarm_e.head).normalize()
        vec1 = uarm_e.x_axis.normalize()
        vec2 = (pole_e.head - uarm_e.head).normalize()
        pole_offset = angle_on_plane(plane, vec1, vec2)

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

        uarm_p = pb[uarm]
        farm_p = pb[farm]
        hand_p = pb[hand]
        pole_p = pb[pole]
        vishand_p = pb[vishand]
        vispole_p = pb[vispole]

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

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

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

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

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

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

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

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

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

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

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

        # Set layers if specified
        if self.layers:
            hand_p.bone.layers = self.layers
            pole_p.bone.layers = self.layers
            vishand_p.bone.layers = self.layers
            vispole_p.bone.layers = self.layers

        # Create widgets
        create_line_widget(self.obj, vispole)
        create_line_widget(self.obj, vishand)
        create_sphere_widget(self.obj, pole)

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

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

        return [hand, pole]
Beispiel #25
0
    def create_paw(self, bones):

        org_bones = list([self.org_bones[0]] +
                         connected_children_names(self.obj, self.org_bones[0]))

        bones['ik']['ctrl']['terminal'] = []

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

        # Create IK paw control
        ctrl = get_bone_name(org_bones[2], 'ctrl', 'ik')
        ctrl = copy_bone(self.obj, org_bones[2], ctrl)

        # clear parent (so that rigify will parent to root)
        eb[ctrl].parent = None
        eb[ctrl].use_connect = False

        # MCH for ik control
        ctrl_socket = copy_bone(
            self.obj, org_bones[2],
            get_bone_name(org_bones[2], 'mch', 'ik_socket'))
        eb[ctrl_socket].tail = eb[ctrl_socket].head + 0.8 * (
            eb[ctrl_socket].tail - eb[ctrl_socket].head)
        eb[ctrl_socket].parent = None
        eb[ctrl].parent = eb[ctrl_socket]

        ctrl_root = copy_bone(self.obj, org_bones[2],
                              get_bone_name(org_bones[2], 'mch', 'ik_root'))
        eb[ctrl_root].tail = eb[ctrl_root].head + 0.7 * (eb[ctrl_root].tail -
                                                         eb[ctrl_root].head)
        eb[ctrl_root].use_connect = False
        eb[ctrl_root].parent = eb['root']

        if eb[org_bones[0]].parent:
            paw_parent = eb[org_bones[0]].parent
            ctrl_parent = copy_bone(
                self.obj, org_bones[2],
                get_bone_name(org_bones[2], 'mch', 'ik_parent'))
            eb[ctrl_parent].tail = eb[ctrl_parent].head + 0.6 * (
                eb[ctrl_parent].tail - eb[ctrl_parent].head)
            eb[ctrl_parent].use_connect = False
            eb[ctrl_parent].parent = eb[org_bones[0]].parent
        else:
            paw_parent = None

        # Create heel control bone
        heel = get_bone_name(org_bones[2], 'ctrl', 'heel_ik')
        heel = copy_bone(self.obj, org_bones[2], heel)

        # clear parent
        eb[heel].parent = None
        eb[heel].use_connect = False

        # Parent
        eb[heel].parent = eb[ctrl]
        eb[heel].use_connect = False

        flip_bone(self.obj, heel)

        eb[bones['ik']['mch_target']].parent = eb[heel]
        eb[bones['ik']['mch_target']].use_connect = False

        # Reset control position and orientation
        l = eb[ctrl].length
        orient_bone(self, eb[ctrl], 'y', reverse=True)
        eb[ctrl].length = l

        # Set up constraints

        # Constrain ik ctrl to root / parent

        make_constraint(self, ctrl_socket, {
            'constraint': 'COPY_TRANSFORMS',
            'subtarget': ctrl_root,
        })

        if paw_parent:
            make_constraint(
                self, ctrl_socket, {
                    'constraint': 'COPY_TRANSFORMS',
                    'subtarget': ctrl_parent,
                    'influence': 0.0,
                })

        # Constrain mch target bone to the ik control and mch stretch
        make_constraint(
            self, bones['ik']['mch_target'], {
                'constraint': 'COPY_LOCATION',
                'subtarget': bones['ik']['mch_str'],
                'head_tail': 1.0
            })

        # Constrain mch ik stretch bone to the ik control
        make_constraint(self, bones['ik']['mch_str'], {
            'constraint': 'DAMPED_TRACK',
            'subtarget': heel,
            'head_tail': 1.0
        })
        make_constraint(self, bones['ik']['mch_str'], {
            'constraint': 'STRETCH_TO',
            'subtarget': heel,
            'head_tail': 1.0
        })
        make_constraint(
            self, bones['ik']['mch_str'], {
                'constraint': 'LIMIT_SCALE',
                'use_min_y': True,
                'use_max_y': True,
                'max_y': 1.05,
                'owner_space': 'LOCAL'
            })

        # Create ik/fk switch property
        pb = self.obj.pose.bones
        pb_parent = pb[bones['parent']]

        pb_parent['IK_Strertch'] = 1.0
        prop = rna_idprop_ui_prop_get(pb_parent, 'IK_Strertch', create=True)
        prop["min"] = 0.0
        prop["max"] = 1.0
        prop["soft_min"] = 0.0
        prop["soft_max"] = 1.0
        prop["description"] = 'IK Stretch'

        # Add driver to limit scale constraint influence
        b = bones['ik']['mch_str']
        drv = pb[b].constraints[-1].driver_add("influence").driver
        drv.type = 'AVERAGE'

        var = drv.variables.new()
        var.name = prop.name
        var.type = "SINGLE_PROP"
        var.targets[0].id = self.obj
        var.targets[0].data_path = \
            pb_parent.path_from_id() + '['+ '"' + prop.name + '"' + ']'

        drv_modifier = self.obj.animation_data.drivers[-1].modifiers[0]

        drv_modifier.mode = 'POLYNOMIAL'
        drv_modifier.poly_order = 1
        drv_modifier.coefficients[0] = 1.0
        drv_modifier.coefficients[1] = -1.0

        # Create paw widget
        create_foot_widget(self.obj, ctrl, bone_transform_name=None)

        # Create heel ctrl locks
        pb[heel].lock_location = True, True, True

        # Add ballsocket widget to heel
        create_ballsocket_widget(self.obj, heel, bone_transform_name=None)

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

        if len(org_bones) >= 4:
            # Create toes control bone
            toes = get_bone_name(org_bones[3], 'ctrl')
            toes = copy_bone(self.obj, org_bones[3], toes)

            eb[toes].use_connect = False
            eb[toes].parent = eb[org_bones[3]]

            # Create toes mch bone
            toes_mch = get_bone_name(org_bones[3], 'mch')
            toes_mch = copy_bone(self.obj, org_bones[3], toes_mch)

            eb[toes_mch].use_connect = False
            eb[toes_mch].parent = eb[ctrl]

            eb[toes_mch].length /= 4

            # Constrain 4th ORG to toes MCH bone
            make_constraint(self, org_bones[3], {
                'constraint': 'COPY_TRANSFORMS',
                'subtarget': toes_mch
            })

            make_constraint(self, bones['def'][-1], {
                'constraint': 'DAMPED_TRACK',
                'subtarget': toes,
                'head_tail': 1
            })
            make_constraint(self, bones['def'][-1], {
                'constraint': 'STRETCH_TO',
                'subtarget': toes,
                'head_tail': 1
            })

            # Find IK/FK switch property
            pb = self.obj.pose.bones
            prop = rna_idprop_ui_prop_get(pb[bones['parent']], 'IK/FK')

            # Add driver to limit scale constraint influence
            b = org_bones[3]
            drv = pb[b].constraints[-1].driver_add("influence").driver
            drv.type = 'AVERAGE'

            var = drv.variables.new()
            var.name = prop.name
            var.type = "SINGLE_PROP"
            var.targets[0].id = self.obj
            var.targets[0].data_path = \
                pb_parent.path_from_id() + '['+ '"' + prop.name + '"' + ']'

            drv_modifier = self.obj.animation_data.drivers[-1].modifiers[0]

            drv_modifier.mode = 'POLYNOMIAL'
            drv_modifier.poly_order = 1
            drv_modifier.coefficients[0] = 1.0
            drv_modifier.coefficients[1] = -1.0

            # Create toe circle widget
            create_circle_widget(self.obj, toes, radius=0.4, head_tail=0.5)

            bones['ik']['ctrl']['terminal'] += [toes]

        bones['ik']['ctrl']['terminal'] += [heel, ctrl]

        if paw_parent:
            bones['ik']['mch_foot'] = [ctrl_socket, ctrl_root, ctrl_parent]
        else:
            bones['ik']['mch_foot'] = [ctrl_socket, ctrl_root]

        return bones
Beispiel #26
0
def copy_bone(armature, bone_name, assign_name=''):
    """ Makes a copy of the given bone in the given armature object.
        Returns the resulting bone's name.
    """
    print("copy_bone:  Copying " + bone_name + " to " + assign_name)
    #if bone_name not in obj.data.bones:
    if bone_name not in armature.data.edit_bones:
        raise utilities.MetarigError(
            "copy_bone(): bone '%s' not found, cannot copy it" % bone_name)

    if armature == bpy.context.active_object and bpy.context.mode == 'EDIT_ARMATURE':
        if assign_name == '':
            assign_name = bone_name
        # Copy the edit bone
        edit_bone_1 = armature.data.edit_bones[bone_name]
        edit_bone_2 = armature.data.edit_bones.new(assign_name)
        bone_name_1 = bone_name
        bone_name_2 = edit_bone_2.name

        edit_bone_2.parent = edit_bone_1.parent
        edit_bone_2.use_connect = edit_bone_1.use_connect

        # Copy edit bone attributes
        edit_bone_2.layers = list(edit_bone_1.layers)

        edit_bone_2.head = Vector(edit_bone_1.head)
        edit_bone_2.tail = Vector(edit_bone_1.tail)
        edit_bone_2.roll = edit_bone_1.roll

        edit_bone_2.use_inherit_rotation = edit_bone_1.use_inherit_rotation
        edit_bone_2.use_inherit_scale = edit_bone_1.use_inherit_scale
        edit_bone_2.use_local_location = edit_bone_1.use_local_location

        edit_bone_2.use_deform = edit_bone_1.use_deform
        edit_bone_2.bbone_segments = edit_bone_1.bbone_segments
        edit_bone_2.bbone_easein = edit_bone_1.bbone_easein
        edit_bone_2.bbone_easeout = edit_bone_1.bbone_easeout

        bpy.ops.object.mode_set(mode='OBJECT')

        # Get the pose bones
        pose_bone_1 = armature.pose.bones[bone_name_1]
        pose_bone_2 = armature.pose.bones[bone_name_2]

        # Copy pose bone attributes
        pose_bone_2.rotation_mode = pose_bone_1.rotation_mode
        pose_bone_2.rotation_axis_angle = tuple(
            pose_bone_1.rotation_axis_angle)
        pose_bone_2.rotation_euler = tuple(pose_bone_1.rotation_euler)
        pose_bone_2.rotation_quaternion = tuple(
            pose_bone_1.rotation_quaternion)

        pose_bone_2.lock_location = tuple(pose_bone_1.lock_location)
        pose_bone_2.lock_scale = tuple(pose_bone_1.lock_scale)
        pose_bone_2.lock_rotation = tuple(pose_bone_1.lock_rotation)
        pose_bone_2.lock_rotation_w = pose_bone_1.lock_rotation_w
        pose_bone_2.lock_rotations_4d = pose_bone_1.lock_rotations_4d

        # Copy custom properties
        for key in pose_bone_1.keys():
            if key != "_RNA_UI" \
            and key != "rigify_parameters" \
            and key != "rigify_type":
                prop1 = rna_idprop_ui_prop_get(pose_bone_1, key, create=False)
                prop2 = rna_idprop_ui_prop_get(pose_bone_2, key, create=True)
                pose_bone_2[key] = pose_bone_1[key]
                for key in prop1.keys():
                    prop2[key] = prop1[key]

        bpy.ops.object.mode_set(mode='EDIT')
        print("copy_bone:  End copy")
        return bone_name_2
    else:
        raise utilities.MetarigError("Cannot copy bones outside of edit mode")
Beispiel #27
0
    def execute(self, context):
        sc = bpy.context.scene
        mode = bpy.context.mode

        BONE_LENGTH = 0.5
        PARENT_NAME = 'Parent'
        CAMERA_NAME = 'Camera'
        LEFT_CORNER_NAME = 'Left Corner'
        RIGHT_CORNER_NAME = 'Right Corner'
        CENTER_NAME = 'Center'

        # Create camera
        camera = bpy.data.cameras.new(CAMERA_NAME)
        camera.lens = 170.0
        camera_obj = bpy.data.objects.new(CAMERA_NAME, camera)
        sc.collection.objects.link(camera_obj)

        # Create armature
        camera_rig = bpy.data.armatures.new('Camera Rig')
        camera_rig_object = bpy.data.objects.new('Camera Rig', camera_rig)
        sc.collection.objects.link(camera_rig_object)
        camera_rig_object.location = sc.cursor.location

        bpy.context.view_layer.objects.active = camera_rig_object

        bpy.ops.object.mode_set(mode='EDIT')
        eb = camera_rig.edit_bones
        parent_bone = eb.new(PARENT_NAME)
        parent_bone.tail = Vector((0.0, 0.0, BONE_LENGTH))

        camera_bone = eb.new('Camera')
        camera_bone.tail = Vector((0.0, 0.0, BONE_LENGTH))
        camera_bone.parent = parent_bone

        corners = camera.view_frame(scene=sc)[1:3]

        left_corner = eb.new(LEFT_CORNER_NAME)
        left_corner.head = (parent_bone.matrix @ corners[1]).normalized() * 10
        left_corner.tail = left_corner.head + Vector((0.0, 0.0, BONE_LENGTH))
        left_corner.parent = parent_bone

        right_corner = eb.new(RIGHT_CORNER_NAME)
        right_corner.head = (parent_bone.matrix @ corners[0]).normalized() * 10
        right_corner.tail = right_corner.head + Vector((0.0, 0.0, BONE_LENGTH))
        right_corner.parent = parent_bone

        corner_distance_x = (left_corner.head - right_corner.head).length
        corner_distance_y = -left_corner.head.z
        corner_distance_z = left_corner.head.y

        center = eb.new(CENTER_NAME)
        center.head = ((right_corner.head + left_corner.head) / 2.0)
        center.tail = center.head + Vector((0.0, 0.0, BONE_LENGTH))
        center.parent = parent_bone
        center.layers = [layer == 31 for layer in range(32)]

        bpy.ops.object.mode_set(mode='POSE')
        bones = camera_rig_object.data.bones
        pb = camera_rig_object.pose.bones

        # Bone drivers
        center_drivers = pb[CENTER_NAME].driver_add("location")

        # Center X driver
        d = center_drivers[0].driver
        d.type = 'AVERAGE'

        for corner in ('left', 'right'):
            var = d.variables.new()
            var.name = corner
            var.type = 'TRANSFORMS'
            var.targets[0].id = camera_rig_object
            var.targets[0].bone_target = corner.capitalize() + ' Corner'
            var.targets[0].transform_type = 'LOC_X'
            var.targets[0].transform_space = 'TRANSFORM_SPACE'

        # Center Y driver
        d = center_drivers[1].driver
        d.type = 'SCRIPTED'

        d.expression = '({distance_x} - (left_x-right_x))*(res_y/res_x)/2 + (left_y + right_y)/2'.format(
            distance_x=corner_distance_x)

        for direction in ('x', 'y'):
            for corner in ('left', 'right'):
                var = d.variables.new()
                var.name = '%s_%s' % (corner, direction)
                var.type = 'TRANSFORMS'
                var.targets[0].id = camera_rig_object
                var.targets[0].bone_target = corner.capitalize() + ' Corner'
                var.targets[0].transform_type = 'LOC_' + direction.upper()
                var.targets[0].transform_space = 'TRANSFORM_SPACE'

            var = d.variables.new()
            var.name = 'res_' + direction
            var.type = 'SINGLE_PROP'
            var.targets[0].id_type = 'SCENE'
            var.targets[0].id = sc
            var.targets[0].data_path = 'render.resolution_' + direction

        # Center Z driver
        d = center_drivers[2].driver
        d.type = 'AVERAGE'

        for corner in ('left', 'right'):
            var = d.variables.new()
            var.name = corner
            var.type = 'TRANSFORMS'
            var.targets[0].id = camera_rig_object
            var.targets[0].bone_target = corner.capitalize() + ' Corner'
            var.targets[0].transform_type = 'LOC_Z'
            var.targets[0].transform_space = 'TRANSFORM_SPACE'

        # Bone constraints
        con = pb[CAMERA_NAME].constraints.new('DAMPED_TRACK')
        con.target = camera_rig_object
        con.subtarget = CENTER_NAME
        con.track_axis = 'TRACK_NEGATIVE_Z'

        # Bone Display
        left_shape = create_corner_shape(LEFT_CORNER_NAME, reverse=True)
        bones[LEFT_CORNER_NAME].show_wire = True
        pb[LEFT_CORNER_NAME].custom_shape = left_shape

        right_shape = create_corner_shape(RIGHT_CORNER_NAME)
        bones[RIGHT_CORNER_NAME].show_wire = True
        pb[RIGHT_CORNER_NAME].custom_shape = right_shape

        parent_shape = create_circle_shape(PARENT_NAME)
        bones[PARENT_NAME].show_wire = True
        pb[PARENT_NAME].custom_shape = parent_shape

        camera_shape = create_circle_shape(CAMERA_NAME)
        bones[CAMERA_NAME].show_wire = True
        pb[CAMERA_NAME].custom_shape = camera_shape
        pb[CAMERA_NAME].custom_shape_scale = 0.7

        # Bone transforms
        pb[LEFT_CORNER_NAME].rotation_mode = 'XYZ'
        pb[LEFT_CORNER_NAME].lock_rotation = (True, ) * 3

        pb[RIGHT_CORNER_NAME].rotation_mode = 'XYZ'
        pb[RIGHT_CORNER_NAME].lock_rotation = (True, ) * 3

        pb[PARENT_NAME].rotation_mode = 'XYZ'

        pb[CAMERA_NAME].rotation_mode = 'XYZ'
        pb[CAMERA_NAME].lock_rotation = (True, ) * 3
        pb[CAMERA_NAME].lock_scale = (True, ) * 3

        # Camera settings
        camera_rig_object['rotation_shift'] = 0.0
        prop = rna_idprop_ui_prop_get(camera_rig_object,
                                      'rotation_shift',
                                      create=True)

        prop["min"] = 0.0
        prop["max"] = 1.0
        prop["soft_min"] = 0.0
        prop["soft_max"] = 1.0
        prop["description"] = 'rotation_shift'

        # Rotation / shift switch
        d = con.driver_add('influence').driver
        d.expression = '1 - rotation_shift'

        var = d.variables.new()
        var.name = 'rotation_shift'
        var.type = 'SINGLE_PROP'
        var.targets[0].id_type = 'OBJECT'
        var.targets[0].id = camera_rig_object
        var.targets[0].data_path = '["rotation_shift"]'

        # Focal length driver
        d = camera.driver_add('lens').driver
        d.expression = 'abs({distance_z} - (left_z + right_z)/2 + cam_z) * size / frame_width'.format(
            distance_z=corner_distance_z)

        var = d.variables.new()
        var.name = 'frame_width'
        var.type = 'LOC_DIFF'
        var.targets[0].id = camera_rig_object
        var.targets[0].bone_target = LEFT_CORNER_NAME
        var.targets[0].transform_space = 'WORLD_SPACE'
        var.targets[1].id = camera_rig_object
        var.targets[1].bone_target = RIGHT_CORNER_NAME
        var.targets[1].transform_space = 'WORLD_SPACE'

        for corner in ('left', 'right'):
            var = d.variables.new()
            var.name = corner + '_z'
            var.type = 'TRANSFORMS'
            var.targets[0].id = camera_rig_object
            var.targets[0].bone_target = corner.capitalize() + ' Corner'
            var.targets[0].transform_type = 'LOC_Z'
            var.targets[0].transform_space = 'TRANSFORM_SPACE'

        var = d.variables.new()
        var.name = 'cam_z'
        var.type = 'TRANSFORMS'
        var.targets[0].id = camera_rig_object
        var.targets[0].bone_target = CAMERA_NAME
        var.targets[0].transform_type = 'LOC_Z'
        var.targets[0].transform_space = 'TRANSFORM_SPACE'

        var = d.variables.new()
        var.name = 'size'
        var.type = 'SINGLE_PROP'
        var.targets[0].id_type = 'CAMERA'
        var.targets[0].id = camera
        var.targets[0].data_path = 'sensor_width'

        # Orthographic scale driver
        d = camera.driver_add('ortho_scale').driver
        d.expression = 'abs({distance_x} - (left_x - right_x))'.format(
            distance_x=corner_distance_x)

        for corner in ('left', 'right'):
            var = d.variables.new()
            var.name = corner + '_x'
            var.type = 'TRANSFORMS'
            var.targets[0].id = camera_rig_object
            var.targets[0].bone_target = corner.capitalize() + ' Corner'
            var.targets[0].transform_type = 'LOC_X'
            var.targets[0].transform_space = 'TRANSFORM_SPACE'

        # Shift driver X
        d = camera.driver_add('shift_x').driver

        d.expression = 'rotation_shift * (((left_x + right_x)/2 - cam_x) * lens / abs({distance_z} - (left_z + right_z)/2) / sensor_width)'.format(
            distance_z=corner_distance_z)

        var = d.variables.new()
        var.name = 'rotation_shift'
        var.type = 'SINGLE_PROP'
        var.targets[0].id_type = 'OBJECT'
        var.targets[0].id = camera_rig_object
        var.targets[0].data_path = '["rotation_shift"]'

        for direction in ('x', 'z'):
            for corner in ('left', 'right'):
                var = d.variables.new()
                var.name = '%s_%s' % (corner, direction)
                var.type = 'TRANSFORMS'
                var.targets[0].id = camera_rig_object
                var.targets[0].bone_target = corner.capitalize() + ' Corner'
                var.targets[0].transform_type = 'LOC_' + direction.upper()
                var.targets[0].transform_space = 'TRANSFORM_SPACE'

        var = d.variables.new()
        var.name = 'cam_x'
        var.type = 'TRANSFORMS'
        var.targets[0].id = camera_rig_object
        var.targets[0].bone_target = CAMERA_NAME
        var.targets[0].transform_type = 'LOC_X'
        var.targets[0].transform_space = 'TRANSFORM_SPACE'

        var = d.variables.new()
        var.name = 'lens'
        var.type = 'SINGLE_PROP'
        var.targets[0].id_type = 'CAMERA'
        var.targets[0].id = camera
        var.targets[0].data_path = 'lens'

        var = d.variables.new()
        var.name = 'sensor_width'
        var.type = 'SINGLE_PROP'
        var.targets[0].id_type = 'CAMERA'
        var.targets[0].id = camera
        var.targets[0].data_path = 'sensor_width'

        # Shift driver Y
        d = camera.driver_add('shift_y').driver

        d.expression = 'rotation_shift * -(({distance_y} - (left_y + right_y)/2 - cam_y) * lens / abs({distance_z} - (left_z + right_z)/2) / sensor_width - (res_y/res_x)/2)'.format(
            distance_y=corner_distance_y, distance_z=corner_distance_z)

        var = d.variables.new()
        var.name = 'rotation_shift'
        var.type = 'SINGLE_PROP'
        var.targets[0].id_type = 'OBJECT'
        var.targets[0].id = camera_rig_object
        var.targets[0].data_path = '["rotation_shift"]'

        for direction in ('y', 'z'):
            for corner in ('left', 'right'):
                var = d.variables.new()
                var.name = '%s_%s' % (corner, direction)
                var.type = 'TRANSFORMS'
                var.targets[0].id = camera_rig_object
                var.targets[0].bone_target = corner.capitalize() + ' Corner'
                var.targets[0].transform_type = 'LOC_' + direction.upper()
                var.targets[0].transform_space = 'TRANSFORM_SPACE'

        for direction in ('x', 'y'):
            var = d.variables.new()
            var.name = 'res_' + direction
            var.type = 'SINGLE_PROP'
            var.targets[0].id_type = 'SCENE'
            var.targets[0].id = sc
            var.targets[0].data_path = 'render.resolution_' + direction

        var = d.variables.new()
        var.name = 'cam_y'
        var.type = 'TRANSFORMS'
        var.targets[0].id = camera_rig_object
        var.targets[0].bone_target = CAMERA_NAME
        var.targets[0].transform_type = 'LOC_Y'
        var.targets[0].transform_space = 'TRANSFORM_SPACE'

        var = d.variables.new()
        var.name = 'lens'
        var.type = 'SINGLE_PROP'
        var.targets[0].id_type = 'CAMERA'
        var.targets[0].id = camera
        var.targets[0].data_path = 'lens'

        var = d.variables.new()
        var.name = 'sensor_width'
        var.type = 'SINGLE_PROP'
        var.targets[0].id_type = 'CAMERA'
        var.targets[0].id = camera
        var.targets[0].data_path = 'sensor_width'

        # Parent camera object to rig
        camera_obj.parent = camera_rig_object
        camera_obj.parent_type = 'BONE'
        camera_obj.parent_bone = 'Camera'
        camera_obj.location.y = -BONE_LENGTH
        camera_obj.lock_location = (True, ) * 3
        camera_obj.lock_rotation = (True, ) * 3
        camera_obj.lock_scale = (True, ) * 3

        bpy.ops.object.mode_set(mode='OBJECT')

        return {"FINISHED"}
Beispiel #28
0
def create_arm(cls, bones):
    org_bones = cls.org_bones

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

    ctrl = get_bone_name(org_bones[2], 'ctrl', 'ik')

    # Create IK arm control
    ctrl = copy_bone(cls.obj, org_bones[2], ctrl)

    # clear parent (so that rigify will parent to root)
    eb[ctrl].parent = None
    eb[ctrl].use_connect = False

    # Parent
    eb[bones['ik']['mch_target']].parent = eb[ctrl]
    eb[bones['ik']['mch_target']].use_connect = False

    # Set up constraints
    # Constrain mch target bone to the ik control and mch stretch

    make_constraint(
        cls, bones['ik']['mch_target'], {
            'constraint': 'COPY_LOCATION',
            'subtarget': bones['ik']['mch_str'],
            'head_tail': 1.0
        })

    # Constrain mch ik stretch bone to the ik control
    make_constraint(cls, bones['ik']['mch_str'], {
        'constraint': 'DAMPED_TRACK',
        'subtarget': ctrl,
    })
    make_constraint(cls, bones['ik']['mch_str'], {
        'constraint': 'STRETCH_TO',
        'subtarget': ctrl,
    })
    make_constraint(
        cls, bones['ik']['mch_str'], {
            'constraint': 'LIMIT_SCALE',
            'use_min_y': True,
            'use_max_y': True,
            'max_y': 1.05,
            'owner_space': 'LOCAL'
        })

    pb = cls.obj.pose.bones

    # Modify rotation mode for ik and tweak controls
    pb[bones['ik']['ctrl']['limb']].rotation_mode = 'ZXY'

    for b in bones['tweak']['ctrl']:
        pb[b].rotation_mode = 'ZXY'

    # Create ik/fk switch property
    pb_parent = pb[bones['parent']]

    pb_parent['IK_Strertch'] = 1.0
    prop = rna_idprop_ui_prop_get(pb_parent, 'IK_Strertch', create=True)
    prop["min"] = 0.0
    prop["max"] = 1.0
    prop["soft_min"] = 0.0
    prop["soft_max"] = 1.0
    prop["description"] = 'IK Stretch'

    # Add driver to limit scale constraint influence
    b = bones['ik']['mch_str']
    drv = pb[b].constraints[-1].driver_add("influence").driver
    drv.type = 'SUM'

    var = drv.variables.new()
    var.name = prop.name
    var.type = "SINGLE_PROP"
    var.targets[0].id = cls.obj
    var.targets[0].data_path = \
        pb_parent.path_from_id() + '['+ '"' + prop.name + '"' + ']'

    drv_modifier = cls.obj.animation_data.drivers[-1].modifiers[0]

    drv_modifier.mode = 'POLYNOMIAL'
    drv_modifier.poly_order = 1
    drv_modifier.coefficients[0] = 1.0
    drv_modifier.coefficients[1] = -1.0

    # Create hand widget
    create_hand_widget(cls.obj, ctrl, bone_transform_name=None)

    bones['ik']['ctrl']['terminal'] = [ctrl]

    return bones
Beispiel #29
0
def create_arm( cls, bones ):
    org_bones = cls.org_bones
    
    bpy.ops.object.mode_set(mode='EDIT')
    eb = cls.obj.data.edit_bones

    ctrl = get_bone_name( org_bones[2], 'ctrl', 'ik' )
    
    # Create IK arm control
    ctrl = copy_bone( cls.obj, org_bones[2], ctrl )

    # clear parent (so that rigify will parent to root) 
    eb[ ctrl ].parent      = None
    eb[ ctrl ].use_connect = False

    # Parent 
    eb[ bones['ik']['mch_target'] ].parent      = eb[ ctrl ]
    eb[ bones['ik']['mch_target'] ].use_connect = False
    
    # Set up constraints
    # Constrain mch target bone to the ik control and mch stretch
   
    make_constraint( cls, bones['ik']['mch_target'], {
        'constraint'  : 'COPY_LOCATION',
        'subtarget'   : bones['ik']['mch_str'],
        'head_tail'   : 1.0
    })

    # Constrain mch ik stretch bone to the ik control
    make_constraint( cls, bones['ik']['mch_str'], {
        'constraint'  : 'DAMPED_TRACK',
        'subtarget'   : ctrl,
    })
    make_constraint( cls, bones['ik']['mch_str'], {
        'constraint'  : 'STRETCH_TO',
        'subtarget'   : ctrl,
    })
    make_constraint( cls, bones['ik']['mch_str'], {
        'constraint'  : 'LIMIT_SCALE',
        'use_min_y'   : True,
        'use_max_y'   : True,
        'max_y'       : 1.05,
        'owner_space' : 'LOCAL'
    })

    pb = cls.obj.pose.bones

    # Modify rotation mode for ik and tweak controls
    pb[bones['ik']['ctrl']['limb']].rotation_mode = 'ZXY'

    for b in bones['tweak']['ctrl']:
        pb[b].rotation_mode = 'ZXY'

    # Create ik/fk switch property
    pb_parent = pb[ bones['parent'] ]
    
    pb_parent['IK_Strertch'] = 1.0
    prop = rna_idprop_ui_prop_get( pb_parent, 'IK_Strertch', create=True )
    prop["min"]         = 0.0
    prop["max"]         = 1.0
    prop["soft_min"]    = 0.0
    prop["soft_max"]    = 1.0
    prop["description"] = 'IK Stretch'

    # Add driver to limit scale constraint influence
    b        = bones['ik']['mch_str']
    drv      = pb[b].constraints[-1].driver_add("influence").driver
    drv.type = 'SUM'
    
    var = drv.variables.new()
    var.name = prop.name
    var.type = "SINGLE_PROP"
    var.targets[0].id = cls.obj
    var.targets[0].data_path = \
        pb_parent.path_from_id() + '['+ '"' + prop.name + '"' + ']'

    drv_modifier = cls.obj.animation_data.drivers[-1].modifiers[0]
    
    drv_modifier.mode            = 'POLYNOMIAL'
    drv_modifier.poly_order      = 1
    drv_modifier.coefficients[0] = 1.0
    drv_modifier.coefficients[1] = -1.0

    # Create hand widget
    create_hand_widget(cls.obj, ctrl, bone_transform_name=None)

    bones['ik']['ctrl']['terminal'] = [ ctrl ]

    return bones
    def generate(self):
        org_bones = self.org_bones

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

        self.orient_org_bones()

        # Bone name lists
        ctrl_chain = []
        def_chain = []
        mch_chain = []
        mch_drv_chain = []

        # Create ctrl master bone
        org_name = self.org_bones[0]
        temp_name = strip_org(self.org_bones[0])

        if temp_name[-2:] == '.L' or temp_name[-2:] == '.R':
            suffix = temp_name[-2:]
            master_name = temp_name[:-2] + "_master" + suffix
        else:
            master_name = temp_name + "_master"
        master_name = copy_bone(self.obj, org_name, master_name)
        ctrl_bone_master = eb[master_name]

        # Parenting bug fix ??
        ctrl_bone_master.use_connect = False
        ctrl_bone_master.parent = None

        ctrl_bone_master.tail += (eb[org_bones[-1]].tail - eb[org_name].head) * 1.25

        for bone in org_bones:
            eb[bone].use_connect = False
            if org_bones.index(bone) != 0:
                eb[bone].parent = None

        # Creating the bone chains
        for i in range(len(self.org_bones)):

            name = self.org_bones[i]
            ctrl_name = strip_org(name)

            # Create control bones
            ctrl_bone = copy_bone(self.obj, name, ctrl_name)
            ctrl_bone_e = eb[ctrl_name]

            # Create deformation bones
            def_name = make_deformer_name(ctrl_name)
            def_bone = copy_bone(self.obj, name, def_name)

            # Create mechanism bones
            mch_name = make_mechanism_name(ctrl_name)
            mch_bone = copy_bone(self.obj, name, mch_name)

            # Create mechanism driver bones
            drv_name = make_mechanism_name(ctrl_name) + "_drv"
            mch_bone_drv = copy_bone(self.obj, name, drv_name)

            # Adding to lists
            ctrl_chain += [ctrl_bone]
            def_chain += [def_bone]
            mch_chain += [mch_bone]
            mch_drv_chain += [mch_bone_drv]

        # Restoring org chain parenting
        for bone in org_bones[1:]:
            eb[bone].parent = eb[org_bones[org_bones.index(bone) - 1]]

        # Parenting the master bone to the first org
        ctrl_bone_master = eb[master_name]
        ctrl_bone_master.parent = eb[org_bones[0]]

        # Parenting chain bones
        for i in range(len(self.org_bones)):
            # Edit bone references
            def_bone_e = eb[def_chain[i]]
            ctrl_bone_e = eb[ctrl_chain[i]]
            mch_bone_e = eb[mch_chain[i]]
            mch_bone_drv_e = eb[mch_drv_chain[i]]

            if i == 0:
                # First ctl bone
                ctrl_bone_e.parent = mch_bone_drv_e
                ctrl_bone_e.use_connect = False
                # First def bone
                def_bone_e.parent = eb[self.org_bones[i]].parent
                def_bone_e.use_connect = False
                # First mch bone
                mch_bone_e.parent = eb[self.org_bones[i]].parent
                mch_bone_e.use_connect = False
                # First mch driver bone
                mch_bone_drv_e.parent = eb[self.org_bones[i]].parent
                mch_bone_drv_e.use_connect = False
            else:
                # The rest
                ctrl_bone_e.parent = mch_bone_drv_e
                ctrl_bone_e.use_connect = False

                def_bone_e.parent = eb[def_chain[i-1]]
                def_bone_e.use_connect = True

                mch_bone_drv_e.parent = eb[ctrl_chain[i-1]]
                mch_bone_drv_e.use_connect = False

                # Parenting mch bone
                mch_bone_e.parent = ctrl_bone_e
                mch_bone_e.use_connect = False

        # Creating tip control bone
        tip_name = copy_bone(self.obj, org_bones[-1], temp_name)
        ctrl_bone_tip = eb[tip_name]
        flip_bone(self.obj, tip_name)
        ctrl_bone_tip.length /= 2

        ctrl_bone_tip.parent = eb[ctrl_chain[-1]]

        bpy.ops.object.mode_set(mode='OBJECT')

        pb = self.obj.pose.bones

        # Setting pose bones locks
        pb_master = pb[master_name]
        pb_master.lock_scale = True, False, True

        pb[tip_name].lock_scale = True, True, True
        pb[tip_name].lock_rotation = True, True, True
        pb[tip_name].lock_rotation_w = True

        pb_master['finger_curve'] = 0.0
        prop = rna_idprop_ui_prop_get(pb_master, 'finger_curve')
        prop["min"] = 0.0
        prop["max"] = 1.0
        prop["soft_min"] = 0.0
        prop["soft_max"] = 1.0
        prop["description"] = "Rubber hose finger cartoon effect"

        # Pose settings
        for org, ctrl, deform, mch, mch_drv in zip(self.org_bones, ctrl_chain, def_chain, mch_chain, mch_drv_chain):

            # Constraining the deform bones
            con = pb[deform].constraints.new('COPY_TRANSFORMS')
            con.target = self.obj
            con.subtarget = mch

            # Constraining the mch bones
            if mch_chain.index(mch) == 0:
                con = pb[mch].constraints.new('COPY_LOCATION')
                con.target = self.obj
                con.subtarget = ctrl

                con = pb[mch].constraints.new('COPY_SCALE')
                con.target = self.obj
                con.subtarget = ctrl

                con = pb[mch].constraints.new('DAMPED_TRACK')
                con.target = self.obj
                con.subtarget = ctrl_chain[ctrl_chain.index(ctrl)+1]

                con = pb[mch].constraints.new('STRETCH_TO')
                con.target = self.obj
                con.subtarget = ctrl_chain[ctrl_chain.index(ctrl)+1]
                con.volume = 'NO_VOLUME'

            elif mch_chain.index(mch) == len(mch_chain) - 1:
                con = pb[mch].constraints.new('DAMPED_TRACK')
                con.target = self.obj
                con.subtarget = tip_name

                con = pb[mch].constraints.new('STRETCH_TO')
                con.target = self.obj
                con.subtarget = tip_name
                con.volume = 'NO_VOLUME'
            else:
                con = pb[mch].constraints.new('DAMPED_TRACK')
                con.target = self.obj
                con.subtarget = ctrl_chain[ctrl_chain.index(ctrl)+1]

                con = pb[mch].constraints.new('STRETCH_TO')
                con.target = self.obj
                con.subtarget = ctrl_chain[ctrl_chain.index(ctrl)+1]
                con.volume = 'NO_VOLUME'

            # Constraining and driving mch driver bones
            pb[mch_drv].rotation_mode = 'YZX'

            if mch_drv_chain.index(mch_drv) == 0:
                # Constraining to master bone
                con = pb[mch_drv].constraints.new('COPY_LOCATION')
                con.target = self.obj
                con.subtarget = master_name

                con = pb[mch_drv].constraints.new('COPY_ROTATION')
                con.target = self.obj
                con.subtarget = master_name
                con.target_space = 'LOCAL'
                con.owner_space = 'LOCAL'

            else:
                # Match axis to expression
                options = {
                    "automatic": {"axis": 0,
                                  "expr": '(1-sy)*pi'},
                    "X": {"axis": 0,
                          "expr": '(1-sy)*pi'},
                    "-X": {"axis": 0,
                           "expr": '-((1-sy)*pi)'},
                    "Y": {"axis": 1,
                          "expr": '(1-sy)*pi'},
                    "-Y": {"axis": 1,
                           "expr": '-((1-sy)*pi)'},
                    "Z": {"axis": 2,
                          "expr": '(1-sy)*pi'},
                    "-Z": {"axis": 2,
                           "expr": '-((1-sy)*pi)'}
                }

                axis = self.params.primary_rotation_axis

                # Drivers
                drv = pb[mch_drv].driver_add("rotation_euler", options[axis]["axis"]).driver
                drv.type = 'SCRIPTED'
                drv.expression = options[axis]["expr"]
                drv_var = drv.variables.new()
                drv_var.name = 'sy'
                drv_var.type = "SINGLE_PROP"
                drv_var.targets[0].id = self.obj
                drv_var.targets[0].data_path = pb[master_name].path_from_id() + '.scale.y'

            # Setting bone curvature setting, custom property, and drivers
            def_bone = self.obj.data.bones[deform]

            def_bone.bbone_segments = 8
            drv = def_bone.driver_add("bbone_easein").driver    # Ease in

            drv.type='SUM'
            drv_var = drv.variables.new()
            drv_var.name = "curvature"
            drv_var.type = "SINGLE_PROP"
            drv_var.targets[0].id = self.obj
            drv_var.targets[0].data_path = pb_master.path_from_id() + '["finger_curve"]'

            drv = def_bone.driver_add("bbone_easeout").driver   # Ease out

            drv.type='SUM'
            drv_var = drv.variables.new()
            drv_var.name = "curvature"
            drv_var.type = "SINGLE_PROP"
            drv_var.targets[0].id = self.obj
            drv_var.targets[0].data_path = pb_master.path_from_id() + '["finger_curve"]'

            # Assigning shapes to control bones
            create_circle_widget(self.obj, ctrl, radius=0.3, head_tail=0.5)

        # Create ctrl master widget
        w = create_widget(self.obj, master_name)
        if w is not None:
            mesh = w.data
            verts = [(0, 0, 0), (0, 1, 0), (0.05, 1, 0), (0.05, 1.1, 0), (-0.05, 1.1, 0), (-0.05, 1, 0)]
            if 'Z' in self.params.primary_rotation_axis:
                # Flip x/z coordinates
                temp = []
                for v in verts:
                    temp += [(v[2], v[1], v[0])]
                verts = temp
            edges = [(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 1)]
            mesh.from_pydata(verts, edges, [])
            mesh.update()

        # Create tip control widget
        create_circle_widget(self.obj, tip_name, radius=0.3, head_tail=0.0)

        # Create UI
        controls_string = ", ".join(
            ["'" + x + "'" for x in ctrl_chain]
            ) + ", " + "'" + master_name + "'"
        return [script % (controls_string, master_name, 'finger_curve')]
Beispiel #31
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')

        # Create the control bones
        uarm = copy_bone(self.obj, self.org_bones[0], strip_org(self.org_bones[0]))
        farm = copy_bone(self.obj, self.org_bones[1], strip_org(self.org_bones[1]))
        hand = copy_bone(self.obj, self.org_bones[2], strip_org(self.org_bones[2]))

        # Create the hinge bones
        if self.org_parent != None:
            hinge = copy_bone(self.obj, self.org_parent, make_mechanism_name(uarm + ".hinge"))
            socket1 = copy_bone(self.obj, uarm, make_mechanism_name(uarm + ".socket1"))
            socket2 = copy_bone(self.obj, uarm, make_mechanism_name(uarm + ".socket2"))

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

        uarm_e = eb[uarm]
        farm_e = eb[farm]
        hand_e = eb[hand]

        if self.org_parent != None:
            hinge_e = eb[hinge]
            socket1_e = eb[socket1]
            socket2_e = eb[socket2]

        # Parenting
        farm_e.parent = uarm_e
        hand_e.parent = farm_e

        if self.org_parent != None:
            hinge_e.use_connect = False
            socket1_e.use_connect = False
            socket2_e.use_connect = False

            uarm_e.parent = hinge_e
            hinge_e.parent = socket2_e
            socket2_e.parent = None

        # Positioning
        if self.org_parent != None:
            center = (hinge_e.head + hinge_e.tail) / 2
            hinge_e.head = center
            socket1_e.length /= 4
            socket2_e.length /= 3

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

        uarm_p = pb[uarm]
        farm_p = pb[farm]
        hand_p = pb[hand]
        if self.org_parent != None:
            hinge_p = pb[hinge]

        if self.org_parent != None:
            # socket1_p = pb[socket1]  # UNUSED
            socket2_p = pb[socket2]

        # Set the elbow to only bend on the x-axis.
        farm_p.rotation_mode = 'XYZ'
        if 'X' in self.primary_rotation_axis:
            farm_p.lock_rotation = (False, True, True)
        elif 'Y' in self.primary_rotation_axis:
            farm_p.lock_rotation = (True, False, True)
        else:
            farm_p.lock_rotation = (True, True, False)

        # Hinge transforms are locked, for auto-ik
        if self.org_parent != None:
            hinge_p.lock_location = True, True, True
            hinge_p.lock_rotation = True, True, True
            hinge_p.lock_rotation_w = True
            hinge_p.lock_scale = True, True, True

        # Set up custom properties
        if self.org_parent != None:
            prop = rna_idprop_ui_prop_get(uarm_p, "isolate", create=True)
            uarm_p["isolate"] = 0.0
            prop["soft_min"] = prop["min"] = 0.0
            prop["soft_max"] = prop["max"] = 1.0

        # Hinge constraints / drivers
        if self.org_parent != None:
            con = socket2_p.constraints.new('COPY_LOCATION')
            con.name = "copy_location"
            con.target = self.obj
            con.subtarget = socket1

            con = socket2_p.constraints.new('COPY_TRANSFORMS')
            con.name = "isolate_off"
            con.target = self.obj
            con.subtarget = socket1

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

        # Constrain org bones to controls
        con = pb[self.org_bones[0]].constraints.new('COPY_TRANSFORMS')
        con.name = "fk"
        con.target = self.obj
        con.subtarget = uarm

        con = pb[self.org_bones[1]].constraints.new('COPY_TRANSFORMS')
        con.name = "fk"
        con.target = self.obj
        con.subtarget = farm

        con = pb[self.org_bones[2]].constraints.new('COPY_TRANSFORMS')
        con.name = "fk"
        con.target = self.obj
        con.subtarget = hand

        # Set layers if specified
        if self.layers:
            uarm_p.bone.layers = self.layers
            farm_p.bone.layers = self.layers
            hand_p.bone.layers = self.layers

        # Create control widgets
        create_limb_widget(self.obj, uarm)
        create_limb_widget(self.obj, farm)

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

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

        return [uarm, farm, hand]
Beispiel #32
0
def generate_rig(context, metarig):
    """ Generates a rig from a metarig.

    """
    t = Timer()

    # Random string with time appended so that
    # different rigs don't collide id's
    rig_id = random_id(16)

    # Initial configuration
    # mode_orig = context.mode  # UNUSED
    rest_backup = metarig.data.pose_position
    metarig.data.pose_position = 'REST'

    bpy.ops.object.mode_set(mode='OBJECT')

    scene = context.scene

    #------------------------------------------
    # Create/find the rig object and set it up

    # Check if the generated rig already exists, so we can
    # regenerate in the same object.  If not, create a new
    # object to generate the rig in.
    print("Fetch rig.")
    try:
        name = metarig["rig_object_name"]
    except KeyError:
        name = "rig"

    try:
        obj = scene.objects[name]
    except KeyError:
        obj = bpy.data.objects.new(name, bpy.data.armatures.new(name))
        obj.draw_type = 'WIRE'
        scene.objects.link(obj)

    obj.data.pose_position = 'POSE'

    # Get rid of anim data in case the rig already existed
    print("Clear rig animation data.")
    obj.animation_data_clear()

    # Select generated rig object
    metarig.select = False
    obj.select = True
    scene.objects.active = obj

    # Remove all bones from the generated rig armature.
    bpy.ops.object.mode_set(mode='EDIT')
    for bone in obj.data.edit_bones:
        obj.data.edit_bones.remove(bone)
    bpy.ops.object.mode_set(mode='OBJECT')

    # Create temporary duplicates for merging
    temp_rig_1 = metarig.copy()
    temp_rig_1.data = metarig.data.copy()
    scene.objects.link(temp_rig_1)

    temp_rig_2 = metarig.copy()
    temp_rig_2.data = obj.data
    scene.objects.link(temp_rig_2)

    # Select the temp rigs for merging
    for objt in scene.objects:
        objt.select = False  # deselect all objects
    temp_rig_1.select = True
    temp_rig_2.select = True
    scene.objects.active = temp_rig_2

    # Merge the temporary rigs
    bpy.ops.object.join()

    # Delete the second temp rig
    bpy.ops.object.delete()

    # Select the generated rig
    for objt in scene.objects:
        objt.select = False  # deselect all objects
    obj.select = True
    scene.objects.active = obj

    # Copy over bone properties
    for bone in metarig.data.bones:
        bone_gen = obj.data.bones[bone.name]

        # B-bone stuff
        bone_gen.bbone_segments = bone.bbone_segments
        bone_gen.bbone_in = bone.bbone_in
        bone_gen.bbone_out = bone.bbone_out

    # Copy over the pose_bone properties
    for bone in metarig.pose.bones:
        bone_gen = obj.pose.bones[bone.name]

        # Rotation mode and transform locks
        bone_gen.rotation_mode = bone.rotation_mode
        bone_gen.lock_rotation = tuple(bone.lock_rotation)
        bone_gen.lock_rotation_w = bone.lock_rotation_w
        bone_gen.lock_rotations_4d = bone.lock_rotations_4d
        bone_gen.lock_location = tuple(bone.lock_location)
        bone_gen.lock_scale = tuple(bone.lock_scale)

        # rigify_type and rigify_parameters
        bone_gen.rigify_type = bone.rigify_type
        for prop in dir(bone_gen.rigify_parameters):
            if (not prop.startswith("_")) \
            and (not prop.startswith("bl_")) \
            and (prop != "rna_type"):
                try:
                    setattr(bone_gen.rigify_parameters, prop, \
                            getattr(bone.rigify_parameters, prop))
                except AttributeError:
                    print("FAILED TO COPY PARAMETER: " + str(prop))

        # Custom properties
        for prop in bone.keys():
            try:
                bone_gen[prop] = bone[prop]
            except KeyError:
                pass

        # Constraints
        for con1 in bone.constraints:
            con2 = bone_gen.constraints.new(type=con1.type)
            copy_attributes(con1, con2)

            # Set metarig target to rig target
            if "target" in dir(con2):
                if con2.target == metarig:
                    con2.target = obj

    # Copy drivers
    if metarig.animation_data:
        for d1 in metarig.animation_data.drivers:
            d2 = obj.driver_add(d1.data_path)
            copy_attributes(d1, d2)
            copy_attributes(d1.driver, d2.driver)

            # Remove default modifiers, variables, etc.
            for m in d2.modifiers:
                d2.modifiers.remove(m)
            for v in d2.driver.variables:
                d2.driver.variables.remove(v)

            # Copy modifiers
            for m1 in d1.modifiers:
                m2 = d2.modifiers.new(type=m1.type)
                copy_attributes(m1, m2)

            # Copy variables
            for v1 in d1.driver.variables:
                v2 = d2.driver.variables.new()
                copy_attributes(v1, v2)
                for i in range(len(v1.targets)):
                    copy_attributes(v1.targets[i], v2.targets[i])
                    # Switch metarig targets to rig targets
                    if v2.targets[i].id == metarig:
                        v2.targets[i].id = obj

                    # Mark targets that may need to be altered after rig generation
                    tar = v2.targets[i]
                    # If a custom property
                    if v2.type == 'SINGLE_PROP' \
                    and re.match('^pose.bones\["[^"\]]*"\]\["[^"\]]*"\]$', tar.data_path):
                        tar.data_path = "RIGIFY-" + tar.data_path

            # Copy key frames
            for i in range(len(d1.keyframe_points)):
                d2.keyframe_points.add()
                k1 = d1.keyframe_points[i]
                k2 = d2.keyframe_points[i]
                copy_attributes(k1, k2)

    t.tick("Duplicate rig: ")
    #----------------------------------
    # Make a list of the original bones so we can keep track of them.
    original_bones = [bone.name for bone in obj.data.bones]

    # Add the ORG_PREFIX to the original bones.
    bpy.ops.object.mode_set(mode='OBJECT')
    for i in range(0, len(original_bones)):
        obj.data.bones[original_bones[i]].name = make_original_name(
            original_bones[i])
        original_bones[i] = make_original_name(original_bones[i])

    # Create a sorted list of the original bones, sorted in the order we're
    # going to traverse them for rigging.
    # (root-most -> leaf-most, alphabetical)
    bones_sorted = []
    for name in original_bones:
        bones_sorted += [name]
    bones_sorted.sort()  # first sort by names
    bones_sorted.sort(key=lambda bone: len(obj.pose.bones[
        bone].parent_recursive))  # then parents before children

    t.tick("Make list of org bones: ")
    #----------------------------------
    # Create the root bone.
    bpy.ops.object.mode_set(mode='EDIT')
    root_bone = new_bone(obj, ROOT_NAME)
    obj.data.edit_bones[root_bone].head = (0, 0, 0)
    obj.data.edit_bones[root_bone].tail = (0, 1, 0)
    obj.data.edit_bones[root_bone].roll = 0
    bpy.ops.object.mode_set(mode='OBJECT')
    obj.data.bones[root_bone].layers = ROOT_LAYER
    # Put the rig_name in the armature custom properties
    rna_idprop_ui_prop_get(obj.data, "rig_id", create=True)
    obj.data["rig_id"] = rig_id

    t.tick("Create root bone: ")
    #----------------------------------
    try:
        # Collect/initialize all the rigs.
        rigs = []
        for bone in bones_sorted:
            bpy.ops.object.mode_set(mode='EDIT')
            rigs += get_bone_rigs(obj, bone)
        t.tick("Initialize rigs: ")

        # Generate all the rigs.
        ui_scripts = []
        for rig in rigs:
            # Go into editmode in the rig armature
            bpy.ops.object.mode_set(mode='OBJECT')
            context.scene.objects.active = obj
            obj.select = True
            bpy.ops.object.mode_set(mode='EDIT')
            scripts = rig.generate()
            if scripts != None:
                ui_scripts += [scripts[0]]
        t.tick("Generate rigs: ")
    except Exception as e:
        # Cleanup if something goes wrong
        print("Rigify: failed to generate rig.")
        metarig.data.pose_position = rest_backup
        obj.data.pose_position = 'POSE'
        bpy.ops.object.mode_set(mode='OBJECT')

        # Continue the exception
        raise e

    #----------------------------------
    bpy.ops.object.mode_set(mode='OBJECT')

    # Get a list of all the bones in the armature
    bones = [bone.name for bone in obj.data.bones]

    # Parent any free-floating bones to the root.
    bpy.ops.object.mode_set(mode='EDIT')
    for bone in bones:
        if obj.data.edit_bones[bone].parent is None:
            obj.data.edit_bones[bone].use_connect = False
            obj.data.edit_bones[bone].parent = obj.data.edit_bones[root_bone]
    bpy.ops.object.mode_set(mode='OBJECT')

    # Lock transforms on all non-control bones
    r = re.compile("[A-Z][A-Z][A-Z]-")
    for bone in bones:
        if r.match(bone):
            pb = obj.pose.bones[bone]
            pb.lock_location = (True, True, True)
            pb.lock_rotation = (True, True, True)
            pb.lock_rotation_w = True
            pb.lock_scale = (True, True, True)

    # Every bone that has a name starting with "DEF-" make deforming.  All the
    # others make non-deforming.
    for bone in bones:
        if obj.data.bones[bone].name.startswith(DEF_PREFIX):
            obj.data.bones[bone].use_deform = True
        else:
            obj.data.bones[bone].use_deform = False

    # Alter marked driver targets
    if obj.animation_data:
        for d in obj.animation_data.drivers:
            for v in d.driver.variables:
                for tar in v.targets:
                    if tar.data_path.startswith("RIGIFY-"):
                        temp, bone, prop = tuple(
                            [x.strip('"]') for x in tar.data_path.split('["')])
                        if bone in obj.data.bones \
                        and prop in obj.pose.bones[bone].keys():
                            tar.data_path = tar.data_path[7:]
                        else:
                            tar.data_path = 'pose.bones["%s"]["%s"]' % (
                                make_original_name(bone), prop)

    # Move all the original bones to their layer.
    for bone in original_bones:
        obj.data.bones[bone].layers = ORG_LAYER

    # Move all the bones with names starting with "MCH-" to their layer.
    for bone in bones:
        if obj.data.bones[bone].name.startswith(MCH_PREFIX):
            obj.data.bones[bone].layers = MCH_LAYER

    # Move all the bones with names starting with "DEF-" to their layer.
    for bone in bones:
        if obj.data.bones[bone].name.startswith(DEF_PREFIX):
            obj.data.bones[bone].layers = DEF_LAYER

    # Create root bone widget
    create_root_widget(obj, "root")

    # Assign shapes to bones
    # Object's with name WGT-<bone_name> get used as that bone's shape.
    for bone in bones:
        wgt_name = (WGT_PREFIX + obj.data.bones[bone].name
                    )[:63]  # Object names are limited to 63 characters... arg
        if wgt_name in context.scene.objects:
            # Weird temp thing because it won't let me index by object name
            for ob in context.scene.objects:
                if ob.name == wgt_name:
                    obj.pose.bones[bone].custom_shape = ob
                    break
            # This is what it should do:
            # obj.pose.bones[bone].custom_shape = context.scene.objects[wgt_name]
    # Reveal all the layers with control bones on them
    vis_layers = [False for n in range(0, 32)]
    for bone in bones:
        for i in range(0, 32):
            vis_layers[i] = vis_layers[i] or obj.data.bones[bone].layers[i]
    for i in range(0, 32):
        vis_layers[i] = vis_layers[i] and not (ORG_LAYER[i] or MCH_LAYER[i]
                                               or DEF_LAYER[i])
    obj.data.layers = vis_layers

    # Ensure the collection of layer names exists
    for i in range(1 + len(metarig.data.rigify_layers), 29):
        metarig.data.rigify_layers.add()

    # Create list of layer name/row pairs
    layer_layout = []
    for l in metarig.data.rigify_layers:
        layer_layout += [(l.name, l.row)]

    # Generate the UI script
    if "rig_ui.py" in bpy.data.texts:
        script = bpy.data.texts["rig_ui.py"]
        script.clear()
    else:
        script = bpy.data.texts.new("rig_ui.py")
    script.write(UI_SLIDERS % rig_id)
    for s in ui_scripts:
        script.write("\n        " + s.replace("\n", "\n        ") + "\n")
    script.write(layers_ui(vis_layers, layer_layout))
    script.write(UI_REGISTER)
    script.use_module = True

    # Run UI script
    exec(script.as_string(), {})

    t.tick("The rest: ")
    #----------------------------------
    # Deconfigure
    bpy.ops.object.mode_set(mode='OBJECT')
    metarig.data.pose_position = rest_backup
    obj.data.pose_position = 'POSE'
Beispiel #33
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)

        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 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 controls and sub-controls
        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]

        # 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

            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
        create_cube_widget(self.obj, main_control)

        # 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
            create_circle_widget(self.obj, name, radius=1.0, head_tail=0.5, with_line=True, bone_transform_name=self.org_bones[i])

        # Hips
        pb[controls[0]].custom_shape_transform = pb[self.org_bones[0]]
        # Create control widgets
        create_circle_widget(self.obj, controls[0], radius=1.0, head_tail=0.5, with_line=True, bone_transform_name=self.org_bones[0])

        # Ribs
        pb[controls[-1]].custom_shape_transform = pb[self.org_bones[-1]]
        # Create control widgets
        create_circle_widget(self.obj, controls[-1], radius=1.0, head_tail=0.5, with_line=True, bone_transform_name=self.org_bones[-1])

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

        return [main_control] + controls
Beispiel #34
0
    def create_leg(self, bones):
        org_bones = list(
            [self.org_bones[0]] + connected_children_names(self.obj, self.org_bones[0])
        )

        bones['ik']['ctrl']['terminal'] = []

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

        # Create toes def bone
        toes_def = get_bone_name(org_bones[-1], 'def')
        toes_def = copy_bone( self.obj, org_bones[-1], toes_def )

        eb[ toes_def ].use_connect = False
        eb[ toes_def ].parent      = eb[ bones['def'][-1] ]
        eb[ toes_def ].use_connect = True

        bones['def'] += [ toes_def ]

        pole_target = get_bone_name(org_bones[0], 'ctrl', 'ik_target')

        # Create IK leg control
        ctrl = get_bone_name(org_bones[2], 'ctrl', 'ik')
        ctrl = copy_bone(self.obj, org_bones[2], ctrl)

        # clear parent (so that rigify will parent to root)
        eb[ctrl].parent = None
        eb[ctrl].use_connect = False

        # MCH for ik control
        ctrl_socket = copy_bone(self.obj, org_bones[2], get_bone_name( org_bones[2], 'mch', 'ik_socket'))
        eb[ctrl_socket].tail = eb[ctrl_socket].head + 0.8*(eb[ctrl_socket].tail-eb[ctrl_socket].head)
        eb[ctrl_socket].parent = None
        eb[ctrl].parent = eb[ctrl_socket]

        # MCH for pole ik control
        ctrl_pole_socket = copy_bone(self.obj, org_bones[2], get_bone_name(org_bones[2], 'mch', 'pole_ik_socket'))
        eb[ctrl_pole_socket].tail = eb[ctrl_pole_socket].head + 0.8 * (eb[ctrl_pole_socket].tail - eb[ctrl_pole_socket].head)
        eb[ctrl_pole_socket].parent = None
        eb[pole_target].parent = eb[ctrl_pole_socket]

        ctrl_root = copy_bone(self.obj, org_bones[2], get_bone_name( org_bones[2], 'mch', 'ik_root'))
        eb[ctrl_root].tail = eb[ctrl_root].head + 0.7*(eb[ctrl_root].tail-eb[ctrl_root].head)
        eb[ctrl_root].use_connect = False
        eb[ctrl_root].parent = eb['root']

        if eb[org_bones[0]].parent:
            leg_parent = eb[org_bones[0]].parent
            ctrl_parent = copy_bone(self.obj, org_bones[2], get_bone_name( org_bones[2], 'mch', 'ik_parent'))
            eb[ctrl_parent].tail = eb[ctrl_parent].head + 0.6*(eb[ctrl_parent].tail-eb[ctrl_parent].head)
            eb[ctrl_parent].use_connect = False
            if eb[org_bones[0]].parent_recursive:
                eb[ctrl_parent].parent = eb[org_bones[0]].parent_recursive[-1]
            else:
                eb[ctrl_parent].parent = eb[org_bones[0]].parent
        else:
            leg_parent = None

        mch_name = get_bone_name(strip_org(org_bones[0]), 'mch', 'parent_socket')
        mch_main_parent = copy_bone(self.obj, org_bones[0], mch_name)
        eb[mch_main_parent].length = eb[org_bones[0]].length / 12
        eb[mch_main_parent].parent = eb[bones['parent']]
        eb[mch_main_parent].roll = 0.0
        eb[bones['main_parent']].parent = eb[mch_main_parent]

        # Create heel ctrl bone
        heel = get_bone_name(org_bones[2], 'ctrl', 'heel_ik')
        heel = copy_bone(self.obj, org_bones[2], heel)

        ax = eb[org_bones[2]].head - eb[org_bones[2]].tail
        ax[2] = 0
        align_bone_y_axis(self.obj, heel, ax)
        if self.rot_axis == 'x' or self.rot_axis == 'automatic':
            align_bone_x_axis(self.obj, heel, eb[org_bones[2]].x_axis)
        elif self.rot_axis == 'z':
            align_bone_z_axis(self.obj, heel, eb[org_bones[2]].z_axis)
        eb[heel].length = eb[org_bones[2]].length / 2

        # Reset control position and orientation
        if self.rot_axis == 'automatic' or self.auto_align_extremity:
            l = eb[ctrl].length
            orient_bone(self, eb[ctrl], 'y', reverse=True)
            eb[ctrl].length = l
        else:
            flip_bone(self.obj, ctrl)
            eb[ctrl].tail[2] = eb[ctrl].head[2]
            eb[ctrl].roll = 0


        # Parent
        eb[ heel ].use_connect = False
        eb[ heel ].parent      = eb[ ctrl ]

        eb[ bones['ik']['mch_target'] ].parent      = eb[ heel ]
        eb[ bones['ik']['mch_target'] ].use_connect = False

        # Create foot mch rock and roll bones

        # Get the tmp heel (floating unconnected without children)
        tmp_heel = ""
        for b in self.obj.data.bones[org_bones[2]].children:
            if not b.use_connect and not b.children:
                tmp_heel = b.name

        # roll1 MCH bone
        roll1_mch = get_bone_name(tmp_heel, 'mch', 'roll')
        roll1_mch = copy_bone(self.obj, org_bones[2], roll1_mch)

        # clear parent
        eb[roll1_mch].use_connect = False
        eb[roll1_mch].parent = None

        flip_bone(self.obj, roll1_mch)
        if self.rot_axis == 'x' or self.rot_axis == 'automatic':
            align_bone_x_axis(self.obj, roll1_mch, eb[org_bones[2]].x_axis)
        elif self.rot_axis == 'z':
            align_bone_z_axis(self.obj, roll1_mch, eb[org_bones[2]].z_axis)

        # Create 2nd roll mch, and two rock mch bones
        roll2_mch = get_bone_name(tmp_heel, 'mch', 'roll')
        roll2_mch = copy_bone(self.obj, org_bones[3], roll2_mch)

        eb[roll2_mch].use_connect = False
        eb[roll2_mch].parent = None

        put_bone(
            self.obj,
            roll2_mch,
            (eb[tmp_heel].head + eb[tmp_heel].tail) / 2
        )

        eb[ roll2_mch ].length /= 4

        # Rock MCH bones
        rock1_mch = get_bone_name( tmp_heel, 'mch', 'rock' )
        rock1_mch = copy_bone( self.obj, tmp_heel, rock1_mch )

        eb[ rock1_mch ].use_connect = False
        eb[ rock1_mch ].parent      = None

        orient_bone( self, eb[ rock1_mch ], 'y', 1.0, reverse = True )
        align_bone_y_axis(self.obj, rock1_mch, ax)
        eb[ rock1_mch ].length = eb[ tmp_heel ].length / 2

        rock2_mch = get_bone_name( tmp_heel, 'mch', 'rock' )
        rock2_mch = copy_bone( self.obj, tmp_heel, rock2_mch )

        eb[ rock2_mch ].use_connect = False
        eb[ rock2_mch ].parent      = None

        #orient_bone( self, eb[ rock2_mch ], 'y', 1.0 )
        align_bone_y_axis(self.obj, rock2_mch, ax)
        eb[ rock2_mch ].length = eb[ tmp_heel ].length / 2

        # Parent rock and roll MCH bones
        eb[ roll1_mch ].parent = eb[ roll2_mch ]
        eb[ roll2_mch ].parent = eb[ rock1_mch ]
        eb[ rock1_mch ].parent = eb[ rock2_mch ]
        eb[ rock2_mch ].parent = eb[ ctrl ]

        # make mch toe bone
        toe = ''
        foot = eb[self.org_bones[-1]]
        for c in foot.children:
            if 'org' in c.name.lower() and c.head == foot.tail:
                toe = c.name
        if not toe:
            raise MetarigError.message("Wrong metarig: can't find ORG-<toe>")

        toe_mch = get_bone_name(toe, 'mch')
        toe_mch = copy_bone(self.obj, toe, toe_mch)
        eb[toe_mch].length /= 3
        eb[toe_mch].parent = eb[self.org_bones[2]]
        eb[toe].use_connect = False
        eb[toe].parent = eb[toe_mch]

        # Constrain rock and roll MCH bones
        make_constraint( self, roll1_mch, {
            'constraint'   : 'COPY_ROTATION',
            'subtarget'    : heel,
            'owner_space'  : 'LOCAL',
            'target_space' : 'LOCAL'
        })

        if self.rot_axis == 'x'or self.rot_axis == 'automatic':
            make_constraint(self, roll1_mch, {
                'constraint': 'LIMIT_ROTATION',
                'use_limit_x': True,
                'max_x': math.radians(360),
                'owner_space': 'LOCAL'
            })
            make_constraint(self, roll2_mch, {
                'constraint': 'COPY_ROTATION',
                'subtarget': heel,
                'use_y': False,
                'use_z': False,
                'invert_x': True,
                'owner_space': 'LOCAL',
                'target_space': 'LOCAL'
            })
            make_constraint(self, roll2_mch, {
                'constraint': 'LIMIT_ROTATION',
                'use_limit_x': True,
                'max_x': math.radians(360),
                'owner_space': 'LOCAL'
            })

        elif self.rot_axis == 'z':
            make_constraint(self, roll1_mch, {
                'constraint': 'LIMIT_ROTATION',
                'use_limit_z': True,
                'max_z': math.radians(360),
                'owner_space': 'LOCAL'
            })
            make_constraint(self, roll2_mch, {
                'constraint': 'COPY_ROTATION',
                'subtarget': heel,
                'use_y': False,
                'use_x': False,
                'invert_z': True,
                'owner_space': 'LOCAL',
                'target_space': 'LOCAL'
            })
            make_constraint(self, roll2_mch, {
                'constraint': 'LIMIT_ROTATION',
                'use_limit_z': True,
                'max_z': math.radians(360),
                'owner_space': 'LOCAL'
            })

        pb = self.obj.pose.bones
        if self.rot_axis == 'x'or self.rot_axis == 'automatic':
            ik_rot_axis = pb[org_bones[0]].x_axis
        elif self.rot_axis == 'z':
            ik_rot_axis = pb[org_bones[0]].z_axis
        heel_x_orientation = pb[tmp_heel].y_axis.dot(ik_rot_axis)
        for i, b in enumerate([rock1_mch, rock2_mch]):
            if heel_x_orientation > 0:
                if not i:
                    min_y = 0
                    max_y = math.radians(360)
                else:
                    min_y = math.radians(-360)
                    max_y = 0
            else:
                if not i:
                    min_y = math.radians(-360)
                    max_y = 0
                else:
                    min_y = 0
                    max_y = math.radians(360)


            make_constraint( self, b, {
                'constraint'   : 'COPY_ROTATION',
                'subtarget'    : heel,
                'use_x'        : False,
                'use_z'        : False,
                'owner_space'  : 'LOCAL',
                'target_space' : 'LOCAL'
            })
            make_constraint( self, b, {
                'constraint'  : 'LIMIT_ROTATION',
                'use_limit_y' : True,
                'min_y'       : min_y,
                'max_y'       : max_y,
                'owner_space' : 'LOCAL'
            })

        # Cns toe_mch to MCH roll2
        make_constraint( self, toe_mch, {
            'constraint'  : 'COPY_TRANSFORMS',
            'subtarget'   : roll2_mch
        })

        # Set up constraints

        # Constrain ik ctrl to root / parent

        make_constraint( self, ctrl_socket, {
            'constraint'  : 'COPY_TRANSFORMS',
            'subtarget'   : ctrl_root,
        })

        make_constraint(self, ctrl_pole_socket, {
            'constraint': 'COPY_TRANSFORMS',
            'subtarget': ctrl_root,
        })

        if leg_parent:
            make_constraint( self, ctrl_socket, {
                'constraint'  : 'COPY_TRANSFORMS',
                'subtarget'   : ctrl_parent,
                'influence'   : 0.0,
            })

            make_constraint(self, ctrl_pole_socket, {
                'constraint': 'COPY_TRANSFORMS',
                'subtarget': bones['ik']['mch_target'],
            })

        # Constrain mch target bone to the ik control and mch stretch
        make_constraint( self, bones['ik']['mch_target'], {
            'constraint'  : 'COPY_LOCATION',
            'subtarget'   : bones['ik']['mch_str'],
            'head_tail'   : 1.0
        })

        # Constrain mch ik stretch bone to the ik control
        make_constraint( self, bones['ik']['mch_str'], {
            'constraint'  : 'DAMPED_TRACK',
            'subtarget'   : roll1_mch,
            'head_tail'   : 1.0
        })
        make_constraint( self, bones['ik']['mch_str'], {
            'constraint'  : 'STRETCH_TO',
            'subtarget'   : roll1_mch,
            'head_tail'   : 1.0
        })
        make_constraint( self, bones['ik']['mch_str'], {
            'constraint'  : 'LIMIT_SCALE',
            'use_min_y'   : True,
            'use_max_y'   : True,
            'max_y'       : 1.05,
            'owner_space' : 'LOCAL'
        })
        make_constraint(self, mch_main_parent, {
            'constraint': 'COPY_ROTATION',
            'subtarget': org_bones[0]
        })

        # Create ik/fk switch property
        pb_parent = pb[bones['main_parent']]
        pb_parent.lock_location = True, True, True
        pb_parent.lock_rotation = True, True, True
        pb_parent.lock_scale = True, True, True

        prop = make_property(pb_parent, 'IK_Stretch', 1.0, description='IK Stretch')

        # Add driver to limit scale constraint influence
        b = bones['ik']['mch_str']

        make_driver(pb[b].constraints[-1], "influence", variables=[(self.obj, pb_parent, prop.name)], polynomial=[1.0, -1.0])

        # Create leg widget
        create_foot_widget(self.obj, ctrl, bone_transform_name=None)

        # Create heel ctrl locks
        pb[heel].lock_location = True, True, True
        if self.rot_axis == 'x'or self.rot_axis == 'automatic':
            pb[heel].lock_rotation = False, False, True
        elif self.rot_axis == 'z':
            pb[heel].lock_rotation = True, False, False
        pb[heel].lock_scale = True, True, True

        # Add ballsocket widget to heel
        create_ballsocket_widget(self.obj, heel, bone_transform_name=None)

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

        if len(org_bones) >= 4:
            # Create toes control bone
            toes = get_bone_name(org_bones[3], 'ctrl')
            toes = copy_bone(self.obj, org_bones[3], toes)

            eb[toes].use_connect = False
            eb[toes].parent = eb[toe_mch]

            # Constrain 4th ORG to toes
            make_constraint(self, org_bones[3], {
                'constraint': 'COPY_TRANSFORMS',
                # 'subtarget'   : roll2_mch
                'subtarget': toes
            })

            # Constrain toes def bones
            make_constraint(self, bones['def'][-2], {
                'constraint': 'DAMPED_TRACK',
                'subtarget': toes
            })
            make_constraint(self, bones['def'][-2], {
                'constraint': 'STRETCH_TO',
                'subtarget': toes
            })
            make_constraint(self, bones['def'][-1], {
                'constraint': 'COPY_TRANSFORMS',
                'subtarget': toes
            })

            # Find IK/FK switch property
            pb = self.obj.pose.bones
            prop = rna_idprop_ui_prop_get( pb[bones['fk']['ctrl'][-1]], 'IK_FK' )

            # Modify rotation mode for ik and tweak controls
            pb[bones['ik']['ctrl']['limb']].rotation_mode = 'ZXY'

            for b in bones['tweak']['ctrl']:
                pb[b].rotation_mode = 'ZXY'

            # Add driver to limit scale constraint influence
            b = toe_mch

            make_driver(pb[b].constraints[-1], "influence", variables=[(self.obj, pb_parent, prop.name)], polynomial=[1.0, -1.0])

            # Create toe circle widget
            create_circle_widget(self.obj, toes, radius=0.4, head_tail=0.5)

            bones['ik']['ctrl']['terminal'] += [toes]

        bones['ik']['ctrl']['terminal'] += [ heel, ctrl ]

        if leg_parent:
            bones['ik']['mch_foot'] = [ctrl_socket, ctrl_pole_socket, ctrl_root, ctrl_parent]
        else:
            bones['ik']['mch_foot'] = [ctrl_socket, ctrl_pole_socket, ctrl_root]

        return bones
Beispiel #35
0
def copy_bone(obj, bone_name, assign_name=''):
    """ Makes a copy of the given bone in the given armature object.
        Returns the resulting bone's name.
    """
    #if bone_name not in obj.data.bones:
    if bone_name not in obj.data.edit_bones:
        raise MetarigError("copy_bone(): bone '%s' not found, cannot copy it" % bone_name)

    if obj == bpy.context.active_object and bpy.context.mode == 'EDIT_ARMATURE':
        if assign_name == '':
            assign_name = bone_name
        # Copy the edit bone
        edit_bone_1 = obj.data.edit_bones[bone_name]
        edit_bone_2 = obj.data.edit_bones.new(assign_name)
        bone_name_1 = bone_name
        bone_name_2 = edit_bone_2.name

        edit_bone_2.parent = edit_bone_1.parent
        edit_bone_2.use_connect = edit_bone_1.use_connect

        # Copy edit bone attributes
        edit_bone_2.layers = list(edit_bone_1.layers)

        edit_bone_2.head = Vector(edit_bone_1.head)
        edit_bone_2.tail = Vector(edit_bone_1.tail)
        edit_bone_2.roll = edit_bone_1.roll

        edit_bone_2.use_inherit_rotation = edit_bone_1.use_inherit_rotation
        edit_bone_2.use_inherit_scale = edit_bone_1.use_inherit_scale
        edit_bone_2.use_local_location = edit_bone_1.use_local_location

        edit_bone_2.use_deform = edit_bone_1.use_deform
        edit_bone_2.bbone_segments = edit_bone_1.bbone_segments
        edit_bone_2.bbone_in = edit_bone_1.bbone_in
        edit_bone_2.bbone_out = edit_bone_1.bbone_out

        bpy.ops.object.mode_set(mode='OBJECT')

        # Get the pose bones
        pose_bone_1 = obj.pose.bones[bone_name_1]
        pose_bone_2 = obj.pose.bones[bone_name_2]

        # Copy pose bone attributes
        pose_bone_2.rotation_mode = pose_bone_1.rotation_mode
        pose_bone_2.rotation_axis_angle = tuple(pose_bone_1.rotation_axis_angle)
        pose_bone_2.rotation_euler = tuple(pose_bone_1.rotation_euler)
        pose_bone_2.rotation_quaternion = tuple(pose_bone_1.rotation_quaternion)

        pose_bone_2.lock_location = tuple(pose_bone_1.lock_location)
        pose_bone_2.lock_scale = tuple(pose_bone_1.lock_scale)
        pose_bone_2.lock_rotation = tuple(pose_bone_1.lock_rotation)
        pose_bone_2.lock_rotation_w = pose_bone_1.lock_rotation_w
        pose_bone_2.lock_rotations_4d = pose_bone_1.lock_rotations_4d

        # Copy custom properties
        for key in pose_bone_1.keys():
            if key != "_RNA_UI" \
            and key != "rigify_parameters" \
            and key != "rigify_type":
                prop1 = rna_idprop_ui_prop_get(pose_bone_1, key, create=False)
                prop2 = rna_idprop_ui_prop_get(pose_bone_2, key, create=True)
                pose_bone_2[key] = pose_bone_1[key]
                for key in prop1.keys():
                    prop2[key] = prop1[key]

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

        return bone_name_2
    else:
        raise MetarigError("Cannot copy bones outside of edit mode")
def generate_rig(context, metarig):
    """ Generates a rig from a metarig.
    """
    t = Timer()

    # clear created widget list
    create_widget.created_widgets = None

    # Find overwrite target rig if exists
    rig_name = get_rig_name(metarig)

    # store rig name to property if rig name already not stored.
    if not metarig.data.gamerig_rig_name:
        metarig.data.gamerig_rig_name = rig_name

    print("Fetch rig (%s)." % rig_name)
    obj = next(
        (i for i in context.collection.objects
         if i != metarig and i.type == 'ARMATURE' and i.name == rig_name),
        None)

    # Random string with time appended so that
    # different rigs don't collide id's
    rig_id = (obj.data.get("gamerig_id") if obj else None) or random_id()

    # Initial configuration
    rest_backup = metarig.data.pose_position
    metarig.data.pose_position = 'REST'

    bpy.ops.object.mode_set(mode='OBJECT')

    scene = context.scene
    view_layer = context.view_layer
    collection = context.collection
    layer_collection = context.layer_collection
    id_store = context.window_manager
    #------------------------------------------
    # Create/find the rig object and set it up

    # Check if the generated rig already exists, so we can
    # regenerate in the same object.  If not, create a new
    # object to generate the rig in.

    toggledArmatureModifiers = []
    if obj is not None:
        print("Overwrite existing rig.")
        try:
            # toggle armature object to metarig if it using generated rig.
            # (referensing rig overwriting makes script runs very slowly)
            for i in collection.objects:
                for j in i.modifiers:
                    if j.type == 'ARMATURE' and j.object == obj:
                        toggledArmatureModifiers.append(j)
                        j.object = metarig
            # Get rid of anim data in case the rig already existed
            print("Clear rig animation data.")
            obj.animation_data_clear()
        except KeyError:
            print("Overwrite failed.")
            obj = None

    if obj is None:
        print("Create new rig.")
        name = metarig.data.get("gamerig_rig_name") or "rig"
        obj = bpy.data.objects.new(name, bpy.data.armatures.new(
            name))  # in case name 'rig' exists it will be rig.001
        obj.display_type = 'WIRE'
        collection.objects.link(obj)
        # Put the rig_name in the armature custom properties
        rna_idprop_ui_prop_get(obj.data, "gamerig_id", create=True)
        obj.data["gamerig_id"] = rig_id

    obj.data.pose_position = 'POSE'

    # Select generated rig object
    metarig.select_set(False)
    obj.select_set(True)
    obj.hide_viewport = False
    view_layer.objects.active = obj

    # Get parented objects to restore later
    childs = {}  # {object: bone}
    for child in obj.children:
        childs[child] = child.parent_bone

    # Remove all bones from the generated rig armature.
    bpy.ops.object.mode_set(mode='EDIT')
    for bone in obj.data.edit_bones:
        obj.data.edit_bones.remove(bone)
    bpy.ops.object.mode_set(mode='OBJECT')

    # Create temporary duplicates for merging
    temp_rig_1 = metarig.copy()
    temp_rig_1.data = metarig.data.copy()
    collection.objects.link(temp_rig_1)

    temp_rig_2 = metarig.copy()
    temp_rig_2.data = obj.data
    collection.objects.link(temp_rig_2)

    # Select the temp rigs for merging
    for objt in collection.objects:
        objt.select_set(False)  # deselect all objects
    temp_rig_1.select_set(True)
    temp_rig_2.select_set(True)
    view_layer.objects.active = temp_rig_2

    # Merge the temporary rigs
    bpy.ops.object.join()

    # Delete the second temp rig
    bpy.ops.object.delete()

    # Select the generated rig
    for objt in scene.objects:
        objt.select_set(False)  # deselect all objects
    obj.select_set(True)
    view_layer.objects.active = obj

    # Copy over bone properties
    for bone in metarig.data.bones:
        bone_gen = obj.data.bones[bone.name]

        # B-bone stuff
        bone_gen.bbone_segments = bone.bbone_segments
        bone_gen.bbone_easein = bone.bbone_easein
        bone_gen.bbone_easeout = bone.bbone_easeout

    # Copy over the pose_bone properties
    for bone in metarig.pose.bones:
        bone_gen = obj.pose.bones[bone.name]

        # Rotation mode and transform locks
        bone_gen.rotation_mode = bone.rotation_mode
        bone_gen.lock_rotation = tuple(bone.lock_rotation)
        bone_gen.lock_rotation_w = bone.lock_rotation_w
        bone_gen.lock_rotations_4d = bone.lock_rotations_4d
        bone_gen.lock_location = tuple(bone.lock_location)
        bone_gen.lock_scale = tuple(bone.lock_scale)

        # gamerig_type and gamerig_parameters
        bone_gen.gamerig_type = bone.gamerig_type
        for prop in dir(bone_gen.gamerig_parameters):
            if (not prop.startswith("_")) and (
                    not prop.startswith("bl_")) and (prop != "rna_type"):
                try:
                    setattr(bone_gen.gamerig_parameters, prop,
                            getattr(bone.gamerig_parameters, prop))
                except AttributeError:
                    print("FAILED TO COPY PARAMETER: " + str(prop))

        # Custom properties
        for prop in bone.keys():
            try:
                bone_gen[prop] = bone[prop]
            except KeyError:
                pass

        # Constraints
        for con1 in bone.constraints:
            con2 = bone_gen.constraints.new(type=con1.type)
            copy_attributes(con1, con2)

            # Set metarig target to rig target
            if "target" in dir(con2):
                if con2.target == metarig:
                    con2.target = obj

    # Clear drivers
    if obj.animation_data:
        for d in obj.animation_data.drivers:
            try:
                obj.driver_remove(d.data_path)
            except expression as TypeError:
                pass

    # Copy drivers
    if metarig.animation_data:
        for d1 in metarig.animation_data.drivers:
            d2 = obj.driver_add(d1.data_path)
            copy_attributes(d1, d2)
            copy_attributes(d1.driver, d2.driver)

            # Remove default modifiers, variables, etc.
            for m in d2.modifiers:
                d2.modifiers.remove(m)
            for v in d2.driver.variables:
                d2.driver.variables.remove(v)

            # Copy modifiers
            for m1 in d1.modifiers:
                m2 = d2.modifiers.new(type=m1.type)
                copy_attributes(m1, m2)

            # Copy variables
            for v1 in d1.driver.variables:
                v2 = d2.driver.variables.new()
                copy_attributes(v1, v2)
                for i in range(len(v1.targets)):
                    copy_attributes(v1.targets[i], v2.targets[i])
                    # Switch metarig targets to rig targets
                    if v2.targets[i].id == metarig:
                        v2.targets[i].id = obj

                    # Mark targets that may need to be altered after rig generation
                    target = v2.targets[i]
                    # If a custom property
                    if v2.type == 'SINGLE_PROP' and re.match(
                            '^pose.bones\["[^"\]]*"\]\["[^"\]]*"\]$',
                            tar.data_path):
                        target.data_path = "GAMERIG-" + target.data_path

            # Copy key frames
            for i in range(len(d1.keyframe_points)):
                d2.keyframe_points.add()
                k1 = d1.keyframe_points[i]
                k2 = d2.keyframe_points[i]
                copy_attributes(k1, k2)

    t.tick("Duplicate rig: ")
    #----------------------------------
    # Make a list of the original bones so we can keep track of them.
    original_bones = [bone.name for bone in obj.data.bones]

    # Add the ORG_PREFIX to the original bones.
    bpy.ops.object.mode_set(mode='OBJECT')
    for i in range(0, len(original_bones)):
        obj.data.bones[original_bones[i]].name = org(original_bones[i])
        original_bones[i] = org(original_bones[i])

    # Create a sorted list of the original bones, sorted in the order we're
    # going to traverse them for rigging.
    # (root-most -> leaf-most, alphabetical)
    bones_sorted = []
    for name in original_bones:
        bones_sorted.append(name)
    bones_sorted.sort()  # first sort by names
    bones_sorted.sort(key=lambda bone: len(obj.pose.bones[
        bone].parent_recursive))  # then parents before children
    t.tick("Make list of org bones: ")

    #----------------------------------
    try:
        # Collect/initialize all the rigs.
        rigs = []
        rigtypes = set()
        for bone in bones_sorted:
            bpy.ops.object.mode_set(mode='EDIT')
            rigs += get_bone_rigs(obj, bone, rigtypes)
        t.tick("Initialize rigs: ")

        # Generate all the rigs.
        tt = Timer()
        ui_scripts = []
        for rig in rigs:
            # Go into editmode in the rig armature
            bpy.ops.object.mode_set(mode='OBJECT')
            context.view_layer.objects.active = obj
            obj.select_set(True)
            bpy.ops.object.mode_set(mode='EDIT')
            scripts = rig.generate(context)
            if scripts is not None:
                ui_scripts.append(scripts[0])
            tt.tick("Generate rig : %s: " % rig)
        t.tick("Generate rigs: ")
    except Exception as e:
        # Cleanup if something goes wrong
        print("GameRig: failed to generate rig.")
        metarig.data.pose_position = rest_backup
        obj.data.pose_position = 'POSE'
        bpy.ops.object.mode_set(mode='OBJECT')

        # Continue the exception
        raise e

    #----------------------------------
    bpy.ops.object.mode_set(mode='OBJECT')

    # Get a list of all the bones in the armature
    bones = [bone.name for bone in obj.data.bones]
    metabones = [bone.name for bone in metarig.data.bones]

    # All the others make non-deforming. (except for bone that already has 'ORG-' prefix from metarig.)
    for bone in bones:
        if not (is_org(bone) or bone in metabones):
            b = obj.data.bones[bone]
            b.use_deform = False

    # Alter marked driver targets
    if obj.animation_data:
        for d in obj.animation_data.drivers:
            for v in d.driver.variables:
                for target in v.targets:
                    if target.data_path.startswith("GAMERIG-"):
                        temp, bone, prop = tuple([
                            x.strip('"]') for x in target.data_path.split('["')
                        ])
                        if bone in obj.data.bones and prop in obj.pose.bones[
                                bone].keys():
                            target.data_path = target.data_path[7:]
                        else:
                            target.data_path = 'pose.bones["%s"]["%s"]' % (
                                org(bone), prop)

    # Move all the original bones to their layer.
    for bone in original_bones:
        obj.data.bones[bone].layers = ORG_LAYER

    # Move all the bones with names starting with "MCH-" to their layer.
    for bone in bones:
        if is_mch(obj.data.bones[bone].name):
            obj.data.bones[bone].layers = MCH_LAYER

    # Assign shapes to bones
    assign_and_unlink_all_widgets(collection, obj)
    # Reveal all the layers with control bones on them
    vis_layers = [False for n in range(0, 32)]
    for bone in bones:
        for i in range(0, 32):
            vis_layers[i] = vis_layers[i] or obj.data.bones[bone].layers[i]
    for i in range(0, 32):
        vis_layers[i] = vis_layers[i] and not (ORG_LAYER[i] or MCH_LAYER[i])
    obj.data.layers = vis_layers

    # Ensure the collection of layer names exists
    for i in range(1 + len(metarig.data.gamerig_layers), 30):
        metarig.data.gamerig_layers.add()

    # Create list of layer name/row pairs
    layer_layout = []
    for l in metarig.data.gamerig_layers:
        #print(l.name)
        layer_layout.append((l.name, l.row))

    # Generate the UI script
    rig_ui_name = 'gamerig_ui_%s.py' % rig_id

    if rig_ui_name in bpy.data.texts.keys():
        script = bpy.data.texts[rig_ui_name]
        script.clear()
    else:
        script = bpy.data.texts.new(rig_ui_name)

    operator_scripts = ''
    for rigt in rigtypes:
        try:
            rigt.operator_script
        except AttributeError:
            pass
        else:
            operator_scripts += rigt.operator_script(rig_id)

    uitemplate = rig_lists.riguitemplate_dic[
        metarig.data.gamerig_rig_ui_template]

    script.write(uitemplate[0].format(rig_id=rig_id,
                                      operators=operator_scripts,
                                      properties=properties_ui(ui_scripts),
                                      layers=layers_ui(vis_layers,
                                                       layer_layout)))
    script.use_module = True

    # Run UI script
    exec(script.as_string(), {})

    # Create Selection Sets
    create_selection_sets(obj, metarig)

    # Create Bone Groups
    create_bone_groups(obj, metarig)

    # Add rig_ui to logic
    create_persistent_rig_ui(obj, script)

    # Remove all jig bones.
    bpy.ops.object.mode_set(mode='EDIT')
    for bone in [bone.name for bone in obj.data.edit_bones]:
        if is_jig(bone):
            obj.data.edit_bones.remove(obj.data.edit_bones[bone])

    #----------------------------------
    # Deconfigure
    bpy.ops.object.mode_set(mode='OBJECT')
    metarig.data.pose_position = rest_backup
    obj.data.pose_position = 'POSE'

    # Restore toggled armature modifiers
    for i in toggledArmatureModifiers:
        i.object = obj
    # Restore parent to bones
    for child, sub_parent in childs.items():
        if sub_parent in obj.pose.bones:
            mat = child.matrix_world.copy()
            child.parent_bone = sub_parent
            child.matrix_world = mat
    # Restore active collection
    view_layer.active_layer_collection = layer_collection

    t.tick("The rest: ")

    # set location generated rig to metarig location
    obj.location = metarig.location
    obj.rotation_mode = metarig.rotation_mode
    obj.rotation_euler = metarig.rotation_euler
    obj.rotation_quaternion = metarig.rotation_quaternion
    obj.rotation_axis_angle = metarig.rotation_axis_angle
    obj.scale = metarig.scale

    t.tick("The rest: ")
    def generate(self):
        org_bones = self.org_bones
        
        bpy.ops.object.mode_set(mode ='EDIT')
        eb = self.obj.data.edit_bones
        
        # Bone name lists
        ctrl_chain    = []
        def_chain     = []
        mch_chain     = []
        mch_drv_chain = []
        
        # Create ctrl master bone
        org_name  = self.org_bones[0]
        temp_name = strip_org(self.org_bones[0])
        
        suffix = temp_name[-2:]
        master_name      = temp_name[:-5] + "_master" + suffix
        master_name      = copy_bone( self.obj, org_name, master_name )
        ctrl_bone_master = eb[ master_name ]
        
        ## Parenting bug fix ??
        ctrl_bone_master.use_connect = False
        ctrl_bone_master.parent      = None
        
        ctrl_bone_master.tail += ( eb[ org_bones[-1] ].tail - eb[org_name].head ) * 1.25

        for bone in org_bones:
            eb[bone].use_connect = False
            if org_bones.index( bone ) != 0:
               eb[bone].parent      = None
        
        # Creating the bone chains
        for i in range(len(self.org_bones)):
            
            name      = self.org_bones[i]
            ctrl_name = strip_org(name)
            
            # Create control bones
            ctrl_bone   = copy_bone( self.obj, name, ctrl_name )
            ctrl_bone_e = eb[ ctrl_name ]
            
            # Create deformation bones
            def_name  = make_deformer_name( ctrl_name )
            def_bone  = copy_bone( self.obj, name, def_name )

            # Create mechanism bones
            mch_name  = make_mechanism_name( ctrl_name )
            mch_bone  = copy_bone( self.obj, name, mch_name )
            
            # Create mechanism driver bones
            drv_name  = make_mechanism_name(ctrl_name) + "_drv"
            mch_bone_drv    = copy_bone(self.obj, name, drv_name)
            mch_bone_drv_e  = eb[drv_name]
            
            # Adding to lists
            ctrl_chain    += [ctrl_name]
            def_chain     += [def_bone] 
            mch_chain     += [mch_bone]
            mch_drv_chain += [drv_name]
        
        # Restoring org chain parenting
        for bone in org_bones[1:]:
            eb[bone].parent = eb[ org_bones[ org_bones.index(bone) - 1 ] ]
        
        # Parenting the master bone to the first org
        ctrl_bone_master = eb[ master_name ]
        ctrl_bone_master.parent = eb[ org_bones[0] ]
        
        # Parenting chain bones
        for i in range(len(self.org_bones)):
            # Edit bone references
            def_bone_e     = eb[def_chain[i]]
            ctrl_bone_e    = eb[ctrl_chain[i]]
            mch_bone_e     = eb[mch_chain[i]]
            mch_bone_drv_e = eb[mch_drv_chain[i]]
            
            if i == 0:
                # First ctl bone
                ctrl_bone_e.parent      = mch_bone_drv_e
                ctrl_bone_e.use_connect = False
                # First def bone
                def_bone_e.parent       = eb[self.org_bones[i]].parent
                def_bone_e.use_connect  = False
                # First mch bone
                mch_bone_e.parent = eb[self.org_bones[i]].parent
                mch_bone_e.use_connect  = False
                # First mch driver bone
                mch_bone_drv_e.parent = eb[self.org_bones[i]].parent
                mch_bone_drv_e.use_connect  = False
            else:
                # The rest
                ctrl_bone_e.parent         = mch_bone_drv_e
                ctrl_bone_e.use_connect    = False 
                
                def_bone_e.parent          = eb[def_chain[i-1]]
                def_bone_e.use_connect     = True
                
                mch_bone_drv_e.parent      = eb[ctrl_chain[i-1]]
                mch_bone_drv_e.use_connect = False

                # Parenting mch bone
                mch_bone_e.parent      = ctrl_bone_e
                mch_bone_e.use_connect = False
                
        # Creating tip conrtol bone 
        tip_name      = copy_bone( self.obj, org_bones[-1], temp_name )
        ctrl_bone_tip = eb[ tip_name ]
        flip_bone( self.obj, tip_name )
        ctrl_bone_tip.length /= 2

        ctrl_bone_tip.parent = eb[ctrl_chain[-1]]

        bpy.ops.object.mode_set(mode ='OBJECT')
        
        pb = self.obj.pose.bones
        
        # Setting pose bones locks
        pb_master = pb[master_name]
        pb_master.lock_scale    = True,False,True
        
        pb[tip_name].lock_scale      = True,True,True
        pb[tip_name].lock_rotation   = True,True,True
        pb[tip_name].lock_rotation_w = True
        
        pb_master['finger_curve'] = 0.0
        prop = rna_idprop_ui_prop_get(pb_master, 'finger_curve')
        prop["min"] = 0.0
        prop["max"] = 1.0
        prop["soft_min"] = 0.0
        prop["soft_max"] = 1.0
        prop["description"] = "Rubber hose finger cartoon effect"

        # Pose settings
        for org, ctrl, deform, mch, mch_drv in zip(self.org_bones, ctrl_chain, def_chain, mch_chain, mch_drv_chain):
            
            # Constraining the org bones
            #con           = pb[org].constraints.new('COPY_TRANSFORMS')
            #con.target    = self.obj
            #con.subtarget = ctrl

            # Constraining the deform bones
            con           = pb[deform].constraints.new('COPY_TRANSFORMS')
            con.target    = self.obj
            con.subtarget = mch
            
            # Constraining the mch bones
            if mch_chain.index(mch) == 0:
                con           = pb[mch].constraints.new('COPY_LOCATION')
                con.target    = self.obj
                con.subtarget = ctrl
                
                con           = pb[mch].constraints.new('COPY_SCALE')
                con.target    = self.obj
                con.subtarget = ctrl
                
                con           = pb[mch].constraints.new('DAMPED_TRACK')
                con.target    = self.obj
                con.subtarget = ctrl_chain[ctrl_chain.index(ctrl)+1]
                
                con           = pb[mch].constraints.new('STRETCH_TO')
                con.target    = self.obj
                con.subtarget = ctrl_chain[ctrl_chain.index(ctrl)+1]
                con.volume    = 'NO_VOLUME'
            
            elif mch_chain.index(mch) == len(mch_chain) - 1:
                con           = pb[mch].constraints.new('DAMPED_TRACK')
                con.target    = self.obj
                con.subtarget = tip_name
                
                con           = pb[mch].constraints.new('STRETCH_TO')
                con.target    = self.obj
                con.subtarget = tip_name
                con.volume    = 'NO_VOLUME'
            else:
                con           = pb[mch].constraints.new('DAMPED_TRACK')
                con.target    = self.obj
                con.subtarget = ctrl_chain[ctrl_chain.index(ctrl)+1]
                
                con           = pb[mch].constraints.new('STRETCH_TO')
                con.target    = self.obj
                con.subtarget = ctrl_chain[ctrl_chain.index(ctrl)+1]
                con.volume    = 'NO_VOLUME'

            # Constraining and driving mch driver bones
            pb[mch_drv].rotation_mode = 'YZX'
            
            if mch_drv_chain.index(mch_drv) == 0:
                # Constraining to master bone
                con              = pb[mch_drv].constraints.new('COPY_LOCATION')
                con.target       = self.obj
                con.subtarget    = master_name
                
                con              = pb[mch_drv].constraints.new('COPY_ROTATION')
                con.target       = self.obj
                con.subtarget    = master_name
                con.target_space = 'LOCAL'
                con.owner_space  = 'LOCAL'
            
            else:
                # Match axis to expression
                options = {
                    "X"  : { "axis" : 0,
                             "expr" : '(1-sy)*pi' },
                    "-X" : { "axis" : 0,
                             "expr" : '-((1-sy)*pi)' },
                    "Y"  : { "axis" : 1,
                             "expr" : '(1-sy)*pi' },
                    "-Y" : { "axis" : 1,
                             "expr" : '-((1-sy)*pi)' },
                    "Z"  : { "axis" : 2,
                             "expr" : '(1-sy)*pi' },
                    "-Z" : { "axis" : 2,
                             "expr" : '-((1-sy)*pi)' }
                }
                
                axis = self.params.primary_rotation_axis

                # Drivers
                drv                          = pb[mch_drv].driver_add("rotation_euler", options[axis]["axis"]).driver
                drv.type                     = 'SCRIPTED'
                drv.expression               = options[axis]["expr"]
                drv_var                      = drv.variables.new()
                drv_var.name                 = 'sy'
                drv_var.type                 = "SINGLE_PROP"
                drv_var.targets[0].id        = self.obj
                drv_var.targets[0].data_path = pb[master_name].path_from_id() + '.scale.y'
                
            # Setting bone curvature setting, costum property, and drivers
            def_bone = self.obj.data.bones[deform]

            def_bone.bbone_segments = 8
            drv = def_bone.driver_add("bbone_in").driver # Ease in

            drv.type='SUM'
            drv_var = drv.variables.new()
            drv_var.name = "curvature"
            drv_var.type = "SINGLE_PROP"
            drv_var.targets[0].id = self.obj
            drv_var.targets[0].data_path = pb_master.path_from_id() + '["finger_curve"]'
            
            drv = def_bone.driver_add("bbone_out").driver # Ease out

            drv.type='SUM'
            drv_var = drv.variables.new()
            drv_var.name = "curvature"
            drv_var.type = "SINGLE_PROP"
            drv_var.targets[0].id = self.obj
            drv_var.targets[0].data_path = pb_master.path_from_id() + '["finger_curve"]'

            
            # Assigning shapes to control bones
            create_circle_widget(self.obj, ctrl, radius=0.3, head_tail=0.5)
            
        # Create ctrl master widget
        w = create_widget(self.obj, master_name)
        if w != None:
            mesh = w.data
            verts = [(0, 0, 0), (0, 1, 0), (0.05, 1, 0), (0.05, 1.1, 0), (-0.05, 1.1, 0), (-0.05, 1, 0)]
            if 'Z' in self.params.primary_rotation_axis:
                # Flip x/z coordinates
                temp = []
                for v in verts:
                    temp += [(v[2], v[1], v[0])]
                verts = temp
            edges = [(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 1)]
            mesh.from_pydata(verts, edges, [])
            mesh.update()
        
        # Create tip control widget
        create_circle_widget(self.obj, tip_name, radius=0.3, head_tail=0.0)
        
        # Create UI
        controls_string = ", ".join(
            ["'" + x + "'" for x in ctrl_chain]
            ) + ", " + "'" + master_name + "'"
        return [script % (controls_string, master_name, 'finger_curve')]
Beispiel #38
0
def build_crane_rig(context):
    # Define some useful variables:
    boneLayer = (False, True, False, False, False, False, False, False, False,
                 False, False, False, False, False, False, False, False, False,
                 False, False, False, False, False, False, False, False, False,
                 False, False, False, False, False)

    # Add the new armature object:
    view_layer = bpy.context.view_layer
    bpy.ops.object.armature_add()
    rig = context.active_object

    # it will try to name the rig "Dolly_Rig" but if that name exists it will
    # add .000 to the name
    if "Crane_Rig" not in context.scene.objects:
        rig.name = "Crane_Rig"
    else:
        rig.name = "Crane_Rig.000"
    rig["rig_id"] = "Crane_Rig"

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

    # Remove default bone:
    bones = rig.data.edit_bones
    bones.remove(bones[0])

    # Add new bones:
    root = bones.new("Root")
    root.tail = (0.0, 0.0, -5.0)

    ctrlAimChild = bones.new("AIM_child")
    ctrlAimChild.head = (0.0, 10.0, 1.0)
    ctrlAimChild.tail = (0.0, 12.0, 1.0)
    ctrlAimChild.layers = boneLayer

    ctrlAim = bones.new("AIM")
    ctrlAim.head = (0.0, 10.0, 1.0)
    ctrlAim.tail = (0.0, 12.0, 1.0)

    ctrl = bones.new("CTRL")
    ctrl.head = (0.0, 1.0, 1.0)
    ctrl.tail = (0.0, 3.0, 1.0)

    arm = bones.new("Crane_Arm")
    arm.head = (0.0, 0.0, 1.0)
    arm.tail = (0.0, 1.0, 1.0)

    height = bones.new("Height")
    height.head = (0.0, 0.0, 0.0)
    height.tail = (0.0, 0.0, 1.0)

    # Setup hierarchy:
    ctrl.parent = arm
    ctrl.use_inherit_rotation = False
    ctrl.use_inherit_scale = False

    arm.parent = height
    arm.use_inherit_scale = False

    height.parent = root
    ctrlAim.parent = root
    ctrlAimChild.parent = ctrlAim

    # change display to BBone: it just looks nicer
    bpy.context.object.data.display_type = 'BBONE'
    # change display to wire for object
    bpy.context.object.display_type = 'WIRE'

    # jump into pose mode and change bones to euler
    bpy.ops.object.mode_set(mode='POSE')
    for x in bpy.context.object.pose.bones:
        x.rotation_mode = 'XYZ'

    # lock the relevant loc, rot and scale
    bpy.context.object.pose.bones["Crane_Arm"].lock_rotation = [
        False, True, False
    ]
    bpy.context.object.pose.bones["Crane_Arm"].lock_scale = [True, False, True]
    bpy.context.object.pose.bones["Height"].lock_location = [True, True, True]
    bpy.context.object.pose.bones["Height"].lock_rotation = [True, True, True]
    bpy.context.object.pose.bones["Height"].lock_scale = [True, False, True]

    # add the custom bone shapes
    bpy.context.object.pose.bones["Root"].custom_shape = bpy.data.objects[
        "WDGT_Camera_Root"]  # add the widget as custom shape
    # set the wireframe checkbox to true
    bpy.context.object.data.bones["Root"].show_wire = True
    bpy.context.object.pose.bones["AIM"].custom_shape = bpy.data.objects[
        "WDGT_AIM"]
    bpy.context.object.data.bones["AIM"].show_wire = True
    bpy.context.object.pose.bones[
        "AIM"].custom_shape_transform = bpy.data.objects[rig.name].pose.bones[
            "AIM_child"]  # sets the "At" field to the child
    bpy.context.object.pose.bones["CTRL"].custom_shape = bpy.data.objects[
        "WDGT_CTRL"]
    bpy.context.object.data.bones["CTRL"].show_wire = True

    # jump into object mode
    bpy.ops.object.mode_set(mode='OBJECT')

    # Add constraints to bones:
    con = rig.pose.bones['AIM_child'].constraints.new('COPY_ROTATION')
    con.target = rig
    con.subtarget = "CTRL"

    con = rig.pose.bones['CTRL'].constraints.new('TRACK_TO')
    con.target = rig
    con.subtarget = "AIM"
    con.use_target_z = True

    # Add custom Bone property to CTRL bone
    ob = bpy.context.object.pose.bones['CTRL']
    prop = rna_idprop_ui_prop_get(ob, "Lock", create=True)
    ob["Lock"] = 1.0
    prop["soft_min"] = prop["min"] = 0.0
    prop["soft_max"] = prop["max"] = 1.0

    # Add Driver to Lock/Unlock Camera from Aim Target
    rig = view_layer.objects.active
    pose_bone = bpy.data.objects[rig.name].pose.bones['CTRL']

    constraint = pose_bone.constraints["Track To"]
    inf_driver = constraint.driver_add('influence')
    inf_driver.driver.type = 'SCRIPTED'
    var = inf_driver.driver.variables.new()
    var.name = 'var'
    var.type = 'SINGLE_PROP'

    # Target the Custom bone property
    var.targets[0].id = bpy.data.objects[rig.name]
    var.targets[0].data_path = 'pose.bones["CTRL"]["Lock"]'
    inf_driver.driver.expression = 'var'

    # Add the camera object:
    bpy.ops.object.mode_set(mode='OBJECT')

    bpy.ops.object.camera_add(view_align=False,
                              enter_editmode=False,
                              location=(0, 0, 0),
                              rotation=(0, 0, 0))
    cam = bpy.context.active_object

    # this will name the Camera Object
    if 'Crane_Camera' not in context.scene.objects:
        cam.name = "Crane_Camera"
    else:
        cam.name = "Crane_Camera.000"

    # this will name the camera Data Object
    if "Crane_Camera" not in bpy.context.scene.objects.data.camera:
        cam.data.name = "Crane_Camera"
    else:
        cam.data.name = "Crane_Camera.000"

    cam_data_name = bpy.context.object.data.name
    bpy.data.cameras[cam_data_name].display_size = 1.0
    cam.rotation_euler[0] = 1.5708  # rotate the camera 90 degrees in x
    cam.location = (0.0, -2.0, 0.0)  # move the camera to the correct position
    cam.parent = rig
    cam.parent_type = "BONE"
    cam.parent_bone = "CTRL"

    # Add blank drivers to lock the camera loc, rot scale
    cam.driver_add('location', 0)
    cam.driver_add('location', 1)
    cam.driver_add('location', 2)
    cam.driver_add('rotation_euler', 0)
    cam.driver_add('rotation_euler', 1)
    cam.driver_add('rotation_euler', 2)
    cam.driver_add('scale', 0)
    cam.driver_add('scale', 1)
    cam.driver_add('scale', 2)

    # Set new camera as active camera
    bpy.context.scene.camera = cam

    # make sure the camera is selectable by default (this can be locked in the UI)
    bpy.context.object.hide_select = False

    # make the rig the active object before finishing
    view_layer.objects.active = rig
    cam.select_set(False)
    rig.select_set(True)

    return rig
Beispiel #39
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')

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

        hand = copy_bone(self.obj, self.org_bones[2], strip_org(insert_before_lr(self.org_bones[2], "_ik")))
        pole = copy_bone(self.obj, self.org_bones[0], strip_org(insert_before_lr(self.org_bones[0], "_pole")))

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

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

        uarm_e = eb[uarm]
        farm_e = eb[farm]
        hand_e = eb[hand]
        pole_e = eb[pole]
        vishand_e = eb[vishand]
        vispole_e = eb[vispole]

        # Parenting
        farm_e.parent = uarm_e

        hand_e.use_connect = False
        hand_e.parent = None

        pole_e.use_connect = False

        vishand_e.use_connect = False
        vishand_e.parent = None

        vispole_e.use_connect = False
        vispole_e.parent = None

        # Misc
        hand_e.use_local_location = False

        vishand_e.hide_select = True
        vispole_e.hide_select = True

        # Positioning
        v1 = farm_e.tail - uarm_e.head
        if 'X' in self.primary_rotation_axis or 'Y' in self.primary_rotation_axis:
            v2 = v1.cross(farm_e.x_axis)
            if (v2 * farm_e.z_axis) > 0.0:
                v2 *= -1.0
        else:
            v2 = v1.cross(farm_e.z_axis)
            if (v2 * farm_e.x_axis) < 0.0:
                v2 *= -1.0
        v2.normalize()
        v2 *= v1.length

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

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

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

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

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

        # uarm_p = pb[uarm]  # UNUSED
        farm_p = pb[farm]
        hand_p = pb[hand]
        pole_p = pb[pole]
        vishand_p = pb[vishand]
        vispole_p = pb[vispole]

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

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

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

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

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

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

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

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

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

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

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

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

        # Set layers if specified
        if self.layers:
            hand_p.bone.layers = self.layers
            pole_p.bone.layers = self.layers
            vishand_p.bone.layers = self.layers
            vispole_p.bone.layers = self.layers

        # Create widgets
        create_line_widget(self.obj, vispole)
        create_line_widget(self.obj, vishand)
        create_sphere_widget(self.obj, pole)

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

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

        return [uarm, farm, hand, pole]
Beispiel #40
0
def generate_rig(context, metarig):
    """ Generates a rig from a metarig.
    """
    t = Timer()

    # clear created widget list
    if hasattr(create_widget, 'created_widgets'):
        del create_widget.created_widgets
    # clear copied bone list
    if hasattr(copy_bone, 'copied'):
        del copy_bone.copied

    # Find overwrite target rig if exists
    rig_name = get_rig_name(metarig)

    # store rig name to property if rig name already not stored.
    if not metarig.data.gamerig.rig_name:
        metarig.data.gamerig.rig_name = rig_name

    print("Fetch rig (%s)." % rig_name)
    obj = next((i for i in context.collection.objects if i != metarig and i.type == 'ARMATURE' and i.name == rig_name), None)
    if obj and not obj in context.visible_objects:
        return "GAMERIG ERROR: Overwritee rig '%s' is hidden. Cannot Operate." % obj.name

    # Random string with time appended so that
    # different rigs don't collide id's
    rig_id = (obj.data.get("gamerig_id") if obj else None) or random_id()

    # Initial configuration
    rest_backup = metarig.data.pose_position
    metarig.data.pose_position = 'REST'

    bpy.ops.object.mode_set(mode='OBJECT')

    view_layer = context.view_layer
    collection = context.collection
    layer_collection = context.layer_collection
    #------------------------------------------
    # Create/find the rig object and set it up

    # Check if the generated rig already exists, so we can
    # regenerate in the same object.  If not, create a new
    # object to generate the rig in.
    
    previous_action = None
    previous_nla_tracks = None
    previous_nla_strips = {}
    toggledArmatureModifiers = []
    if obj:
        print("Overwrite existing rig.")
        try:
            # toggle armature object to metarig if it using generated rig.
            # (referensing rig overwriting makes script runs very slowly)
            for i in collection.objects:
                for j in i.modifiers:
                    if j.type == 'ARMATURE' and j.object == obj:
                        toggledArmatureModifiers.append(j)
                        j.object = metarig
            # Get rid of anim data in case the rig already existed
            print("Clear rig animation data.")
            previous_action = obj.animation_data.action
            previous_nla_tracks = tuple(obj.animation_data.nla_tracks)
            for i in previous_nla_tracks:
                previous_nla_strips[i] = tuple(i.strips)
            obj.animation_data_clear()
            obj.data.animation_data_clear()
        except KeyError:
            print("Overwrite failed.")
            obj = None
    
    if obj is None:
        print("Create new rig.")
        name = metarig.data.gamerig.rig_name or "rig"
        obj = bpy.data.objects.new(name, bpy.data.armatures.new(name))  # in case name 'rig' exists it will be rig.001
        obj.display_type = 'WIRE'
        collection.objects.link(obj)
        # Put the rig_name in the armature custom properties
        rna_idprop_ui_prop_get(obj.data, "gamerig_id", create=True)
        obj.data["gamerig_id"] = rig_id
        obj.location            = metarig.location
        obj.rotation_mode       = metarig.rotation_mode
        obj.rotation_euler      = metarig.rotation_euler
        obj.rotation_quaternion = metarig.rotation_quaternion
        obj.rotation_axis_angle = metarig.rotation_axis_angle
        obj.scale               = metarig.scale

    # apply rotation for metarig / rig
    bpy.ops.object.select_all(action='DESELECT')
    metarig.select_set(True)
    obj.select_set(True)
    metarig_rotation_euler_backup      = metarig.rotation_euler.copy()
    metarig_rotation_quaternion_backup = metarig.rotation_quaternion.copy()
    metarig_rotation_axis_angle_backup = Vector(metarig.rotation_axis_angle)
    rig_rotation_euler_backup      = obj.rotation_euler.copy()
    rig_rotation_quaternion_backup = obj.rotation_quaternion.copy()
    rig_rotation_axis_angle_backup = Vector(obj.rotation_axis_angle)
    bpy.ops.object.transform_apply(location=False, rotation=True, scale=False)

    obj.data.pose_position = 'POSE'

    # Select generated rig object
    metarig.select_set(False)
    obj.select_set(True)
    view_layer.objects.active = obj

    # Get parented objects to restore later
    childs = {}  # {object: bone}
    for child in obj.children:
        childs[child] = child.parent_bone

    # Remove all bones from the generated rig armature.
    bpy.ops.object.mode_set(mode='EDIT')
    for bone in obj.data.edit_bones:
        obj.data.edit_bones.remove(bone)
    bpy.ops.object.mode_set(mode='OBJECT')

    # Create temporary duplicates for merging
    temp_rig_1 = metarig.copy()
    temp_rig_1.data = metarig.data.copy()
    collection.objects.link(temp_rig_1)

    temp_rig_2 = metarig.copy()
    temp_rig_2.data = obj.data
    collection.objects.link(temp_rig_2)

    # Select the temp rigs for merging
    for objt in collection.objects:
        objt.select_set(False)  # deselect all objects
    temp_rig_1.select_set(True)
    temp_rig_2.select_set(True)
    view_layer.objects.active = temp_rig_2

    # Merge the temporary rigs
    bpy.ops.object.join()

    # Delete the second temp rig
    bpy.ops.object.delete()

    # Select the generated rig
    for objt in view_layer.objects:
        objt.select_set(False)  # deselect all objects
    obj.select_set(True)
    view_layer.objects.active = obj

    # Copy metarig's Custom properties to rig
    for prop in metarig.data.keys():
        try:
            if prop != "_RNA_UI" and prop != "gamerig" and prop != "gamerig_id":
                obj.data[prop] = metarig.data[prop]
        except KeyError:
            pass

    # Copy over bone properties
    for bone in metarig.data.bones:
        bone_gen = obj.data.bones[bone.name]

        # B-bone stuff
        bone_gen.bbone_segments = bone.bbone_segments
        bone_gen.bbone_easein = bone.bbone_easein
        bone_gen.bbone_easeout = bone.bbone_easeout

    # Copy over the pose_bone properties
    for bone in metarig.pose.bones:
        bone_gen = obj.pose.bones[bone.name]

        # Rotation mode and transform locks
        bone_gen.rotation_mode = bone.rotation_mode
        bone_gen.lock_rotation = tuple(bone.lock_rotation)
        bone_gen.lock_rotation_w = bone.lock_rotation_w
        bone_gen.lock_rotations_4d = bone.lock_rotations_4d
        bone_gen.lock_location = tuple(bone.lock_location)
        bone_gen.lock_scale = tuple(bone.lock_scale)

        # Custom properties
        for prop in bone.keys():
            try:
                bone_gen[prop] = bone[prop]
            except KeyError:
                pass

    # Clear drivers
    if obj.animation_data:
        for d in obj.animation_data.drivers:
            try:
                obj.driver_remove(d.data_path)
            except TypeError:
                pass
    
    t.tick("Duplicate rig: ")
    #----------------------------------
    # Make a list of the original bones so we can keep track of them.
    original_bones = [bone.name for bone in obj.data.bones]

    # Create a sorted list of the original bones, sorted in the order we're
    # going to traverse them for rigging.
    # (root-most -> leaf-most, alphabetical)
    bones_sorted = []
    for name in original_bones:
        bones_sorted.append(name)
    bones_sorted.sort()  # first sort by names
    bones_sorted.sort(key=lambda bone: len(obj.pose.bones[bone].parent_recursive))  # then parents before children
    t.tick("Make list of org bones: ")

    #----------------------------------
    error = None
    def append_error(bone, rig, e):
        nonlocal error
        errorstr  = "failed at rig '%s' (%s)." % (bone, rig.__class__.__module__) if rig else "failed at rig '%s'." % bone
        errorstr += "\n   " + e.message
        print("GameRig: %s" % errorstr)
        if error:
            error += '\n' + errorstr
        else:
            error = errorstr
    
    try:
        # Collect/initialize all the rigs.
        rigs = {}
        rigtypes = set()
        bpy.ops.object.mode_set(mode='EDIT')
        for bone in bones_sorted:
            try:
                rig = get_bone_rig(metarig, obj, bone, rigtypes)
                if rig:
                    rigs[bone] = rig
            except MetarigError as e:
                append_error(bone, None, e)
        t.tick("Initialize rigs: ")

        begin_progress(len(rigs.keys()) * 2)

        # Generate all the rigs.
        bpy.ops.object.mode_set(mode='OBJECT')
        context.view_layer.objects.active = obj
        obj.select_set(True)
        tt = Timer()
        ui_scripts = []

        # Go into editmode in the rig armature
        bpy.ops.object.mode_set(mode='EDIT')
        for bone, rig in dict(rigs.items()).items():
            try:
                script = rig.generate(context)
                if script and len(script) > 0:
                    ui_scripts.append(script)
            except MetarigError as e:
                append_error(bone, rig, e)
                del rigs[bone]
            tt.tick("Generate rig : %s (%s): " % (bone, rig.__class__.__module__))
            update_progress()

        # Go into objectmode in the rig armature
        bpy.ops.object.mode_set(mode='OBJECT')

        # Copy Constraints
        for bone in metarig.pose.bones:
            bone_gen = obj.pose.bones[bone.name]
            
            for con1 in bone.constraints:
                con2 = bone_gen.constraints.new(type=con1.type)
                copy_attributes(con1, con2)

                # Set metarig target to rig target
                if "target" in dir(con2):
                    if con2.target == metarig:
                        con2.target = obj

        # Copy drivers
        if metarig.animation_data:
            for d1 in metarig.animation_data.drivers:
                d2 = obj.driver_add(d1.data_path)
                copy_attributes(d1, d2)
                copy_attributes(d1.driver, d2.driver)

                # Remove default modifiers, variables, etc.
                for m in d2.modifiers:
                    d2.modifiers.remove(m)
                for v in d2.driver.variables:
                    d2.driver.variables.remove(v)

                # Copy modifiers
                for m1 in d1.modifiers:
                    m2 = d2.modifiers.new(type=m1.type)
                    copy_attributes(m1, m2)

                # Copy variables
                for v1 in d1.driver.variables:
                    v2 = d2.driver.variables.new()
                    copy_attributes(v1, v2)
                    for i in range(len(v1.targets)):
                        copy_attributes(v1.targets[i], v2.targets[i])
                        # Switch metarig targets to rig targets
                        if v2.targets[i].id == metarig:
                            v2.targets[i].id = obj

                        # Mark targets that may need to be altered after rig generation
                        target = v2.targets[i]
                        # If a custom property
                        if v2.type == 'SINGLE_PROP' and re.match('^pose.bones\["[^"\]]*"\]\["[^"\]]*"\]$', tar.data_path):
                            target.data_path = "GAMERIG-" + target.data_path

                # Copy key frames
                try:
                    for i in range(len(d1.keyframe_points)):
                        d2.keyframe_points.add()
                        k1 = d1.keyframe_points[i]
                        k2 = d2.keyframe_points[i]
                        copy_attributes(k1, k2)
                except TypeError:
                    pass
        
        for bone, rig in rigs.items():
            try:
                rig.postprocess(context)
            except MetarigError as e:
                append_error(bone, rig, e)
            tt.tick("PostProcess rig : %s (%s): " % (bone, rig.__class__.__module__))
            update_progress()
        t.tick("Generate rigs: ")
    except Exception as e:
        # Cleanup if something goes wrong
        print("GameRig: failed to generate rig.")
        metarig.data.pose_position = rest_backup
        obj.data.pose_position = 'POSE'
        bpy.ops.object.mode_set(mode='OBJECT')

        # Continue the exception
        raise e
    finally:
        end_progress()

    # Alter marked driver targets
    if obj.animation_data:
        for d in obj.animation_data.drivers:
            for v in d.driver.variables:
                for target in v.targets:
                    if target.data_path.startswith("GAMERIG-"):
                        temp, bone, prop = tuple([x.strip('"]') for x in target.data_path.split('["')])
                        if bone in obj.data.bones and prop in obj.pose.bones[bone].keys():
                            target.data_path = target.data_path[7:]
                        else:
                            target.data_path = 'pose.bones["%s"]["%s"]' % (basename(bone), prop) #?

    # Get a list of all the bones in the armature
    bones = [bone.name for bone in obj.data.bones]
    metabones = [bone.name for bone in metarig.data.bones]

    # All the others make non-deforming.
    for bone in bones:
        if not (is_org(bone) or bone in metabones):
            b = obj.data.bones[bone]
            b.use_deform = False

    # Move all the original bones to their layer.
    for bone in original_bones:
        obj.data.bones[bone].layers = ORG_LAYER

    # Move all the bones with names starting with "MCH-" to their layer.
    for bone in bones:
        if is_mch(obj.data.bones[bone].name):
            obj.data.bones[bone].layers = MCH_LAYER

    # Assign shapes to bones
    assign_all_widgets(obj)
    # Reveal all the layers with control bones on them
    vis_layers = [False for n in range(0, 32)]
    for bone in bones:
        for i in range(0, 32):
            vis_layers[i] = vis_layers[i] or obj.data.bones[bone].layers[i]
    for i in range(0, 32):
        vis_layers[i] = vis_layers[i] and not (ORG_LAYER[i] or MCH_LAYER[i])
    obj.data.layers = vis_layers

    # Ensure the collection of layer names exists
    for i in range(1 + len(metarig.data.gamerig.layers), 30):
        metarig.data.gamerig.layers.add()

    # Create list of layer name/row pairs
    layer_layout = []
    for l in metarig.data.gamerig.layers:
        #print(l.name)
        layer_layout.append((l.name, l.row))

    # Generate the UI script
    rig_ui_name = 'gamerig_ui_%s.py' % rig_id

    if rig_ui_name in bpy.data.texts.keys():
        script = bpy.data.texts[rig_ui_name]
        try:
            script.as_module().unregister()
        except:
            pass
        script.clear()
    else:
        script = bpy.data.texts.new(rig_ui_name)

    operator_scripts = ''
    for rigt in rigtypes:
        try:
            rigt.operator_script
        except AttributeError:
            pass
        else:
            operator_scripts += rigt.operator_script(rig_id)

    uitemplate = rig_lists.riguitemplate_dic[metarig.data.gamerig.rig_ui_template]

    script.write(
        uitemplate[0].format(
            rig_id=rig_id,
            operators=operator_scripts,
            properties=properties_ui(ui_scripts),
            layers=layers_ui(vis_layers, layer_layout)
        )
    )
    script.use_module = True

    # Register UI script
    script.as_module().register()

    # Create Selection Sets
    create_selection_sets(obj, metarig)

    # Create Bone Groups
    create_bone_groups(obj, metarig)

    # Remove all jig bones.
    bpy.ops.object.mode_set(mode='EDIT')
    for bone in [bone.name for bone in obj.data.edit_bones]:
        if is_jig(bone):
            obj.data.edit_bones.remove(obj.data.edit_bones[bone])

    #----------------------------------
    # Deconfigure
    bpy.ops.object.mode_set(mode='OBJECT')

    # Restore original rotation

    metarig_rotation_euler_inverted = metarig_rotation_euler_backup.copy()
    metarig_rotation_euler_inverted.x *= -1
    metarig_rotation_euler_inverted.y *= -1
    metarig_rotation_euler_inverted.z *= -1

    metarig_rotation_axis_angle_inverted = metarig_rotation_axis_angle_backup.copy()
    metarig_rotation_axis_angle_inverted.w *= -1

    metarig.rotation_euler      = metarig_rotation_euler_inverted
    metarig.rotation_quaternion = metarig_rotation_quaternion_backup.inverted()
    metarig.rotation_axis_angle = metarig_rotation_axis_angle_inverted

    rig_rotation_euler_inverted = rig_rotation_euler_backup.copy()
    rig_rotation_euler_inverted.x *= -1
    rig_rotation_euler_inverted.y *= -1
    rig_rotation_euler_inverted.z *= -1

    rig_rotation_axis_angle_inverted = rig_rotation_axis_angle_backup.copy()
    rig_rotation_axis_angle_inverted.w *= -1

    obj.rotation_euler      = rig_rotation_euler_inverted
    obj.rotation_quaternion = rig_rotation_quaternion_backup.inverted()
    obj.rotation_axis_angle = rig_rotation_axis_angle_inverted

    bpy.ops.object.select_all(action='DESELECT')
    metarig.select_set(True)
    obj.select_set(True)
    bpy.ops.object.transform_apply(location=False, rotation=True, scale=False)

    for ob in bpy.data.objects:
        if ob.parent == obj:
            for i in range(len(ob.rotation_euler)):
                if abs(ob.rotation_euler[i]) <= sys.float_info.epsilon:
                    ob.rotation_euler[i] = 0
            for i in range(len(ob.rotation_quaternion)):
                if abs(ob.rotation_quaternion[i]) <= sys.float_info.epsilon:
                    ob.rotation_quaternion[i] = 0
            for i in range(len(ob.rotation_axis_angle)):
                if abs(ob.rotation_axis_angle[i]) <= sys.float_info.epsilon:
                    ob.rotation_axis_angle[i] = 0

    metarig.rotation_euler      = metarig_rotation_euler_backup
    metarig.rotation_quaternion = metarig_rotation_quaternion_backup
    metarig.rotation_axis_angle = metarig_rotation_axis_angle_backup

    obj.rotation_euler      = rig_rotation_euler_backup
    obj.rotation_quaternion = rig_rotation_quaternion_backup
    obj.rotation_axis_angle = rig_rotation_axis_angle_backup
    
    metarig.select_set(False)
    obj.select_set(True)

    metarig.data.pose_position = rest_backup
    
    obj.data.pose_position = 'POSE'

    # Restore toggled armature modifiers
    for i in toggledArmatureModifiers:
        i.object = obj
    # Restore parent to bones
    for child, sub_parent in childs.items():
        if sub_parent in obj.pose.bones:
            mat = child.matrix_world.copy()
            child.parent_bone = sub_parent
            child.matrix_world = mat
    # Restore active collection
    view_layer.active_layer_collection = layer_collection

    # Restore action and NLA tracks
    if previous_action:
        obj.animation_data.action = previous_action
    if previous_nla_tracks:
        try:
            for s in previous_nla_tracks:
                d = obj.animation_data.nla_tracks.new()
                copy_attributes(s, d)
                for ss in previous_nla_strips[s]:
                    dd = d.strips.new(ss.name, ss.frame_start, ss.action)
                    copy_attributes(ss, dd)
        except Exception as e:
            print("GameRig: Warning. failed to restore NLA tracks.")

    t.tick("The rest: ")
    return error
Beispiel #41
0
    def generate(self):
        bpy.ops.object.mode_set(mode='EDIT')

        # Create non-scaling parent bone
        if self.org_parent is not None:
            loc = Vector(self.obj.data.edit_bones[self.org_bones[0]].head)
            parent = make_nonscaling_child(self.obj, self.org_parent, loc, "_fk")
        else:
            parent = None

        # Create the control bones
        ulimb = copy_bone(self.obj, self.org_bones[0], strip_org(insert_before_lr(self.org_bones[0], ".fk")))
        flimb = copy_bone(self.obj, self.org_bones[1], strip_org(insert_before_lr(self.org_bones[1], ".fk")))
        elimb = copy_bone(self.obj, self.org_bones[2], strip_org(insert_before_lr(self.org_bones[2], ".fk")))

        # Create the end-limb mechanism bone
        elimb_mch = copy_bone(self.obj, self.org_bones[2], make_mechanism_name(strip_org(self.org_bones[2])))

        # Create the anti-stretch bones
        # These sit between a parent and its child, and counteract the
        # stretching of the parent so that the child is unaffected
        fantistr = copy_bone(self.obj, self.org_bones[0], make_mechanism_name(strip_org(insert_before_lr(self.org_bones[0], "_antistr.fk"))))
        eantistr = copy_bone(self.obj, self.org_bones[1], make_mechanism_name(strip_org(insert_before_lr(self.org_bones[1], "_antistr.fk"))))

        # Create the hinge bones
        if parent is not None:
            socket1 = copy_bone(self.obj, ulimb, make_mechanism_name(ulimb + ".socket1"))
            socket2 = copy_bone(self.obj, ulimb, make_mechanism_name(ulimb + ".socket2"))

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

        ulimb_e = eb[ulimb]
        flimb_e = eb[flimb]
        elimb_e = eb[elimb]

        fantistr_e = eb[fantistr]
        eantistr_e = eb[eantistr]

        elimb_mch_e = eb[elimb_mch]

        if parent is not None:
            socket1_e = eb[socket1]
            socket2_e = eb[socket2]

        # Parenting
        elimb_mch_e.use_connect = False
        elimb_mch_e.parent = elimb_e

        elimb_e.use_connect = False
        elimb_e.parent = eantistr_e

        eantistr_e.use_connect = False
        eantistr_e.parent = flimb_e

        flimb_e.use_connect = False
        flimb_e.parent = fantistr_e

        fantistr_e.use_connect = False
        fantistr_e.parent = ulimb_e

        if parent is not None:
            socket1_e.use_connect = False
            socket1_e.parent = eb[parent]

            socket2_e.use_connect = False
            socket2_e.parent = None

            ulimb_e.use_connect = False
            ulimb_e.parent = socket2_e

        # Positioning
        fantistr_e.length /= 8
        put_bone(self.obj, fantistr, Vector(ulimb_e.tail))
        eantistr_e.length /= 8
        put_bone(self.obj, eantistr, Vector(flimb_e.tail))

        if parent is not None:
            socket1_e.length /= 4
            socket2_e.length /= 3

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

        ulimb_p = pb[ulimb]
        flimb_p = pb[flimb]
        elimb_p = pb[elimb]

        fantistr_p = pb[fantistr]
        eantistr_p = pb[eantistr]

        if parent is not None:
            socket2_p = pb[socket2]

        # Lock axes
        ulimb_p.lock_location = (True, True, True)
        flimb_p.lock_location = (True, True, True)
        elimb_p.lock_location = (True, True, True)

        # Set the elbow to only bend on the x-axis.
        flimb_p.rotation_mode = 'XYZ'
        if 'X' in self.primary_rotation_axis:
            flimb_p.lock_rotation = (False, True, True)
        elif 'Y' in self.primary_rotation_axis:
            flimb_p.lock_rotation = (True, False, True)
        else:
            flimb_p.lock_rotation = (True, True, False)

        # Set up custom properties
        if parent is not None:
            prop = rna_idprop_ui_prop_get(ulimb_p, "isolate", create=True)
            ulimb_p["isolate"] = 0.0
            prop["soft_min"] = prop["min"] = 0.0
            prop["soft_max"] = prop["max"] = 1.0

        prop = rna_idprop_ui_prop_get(ulimb_p, "stretch_length", create=True)
        ulimb_p["stretch_length"] = 1.0
        prop["min"] = 0.05
        prop["max"] = 20.0
        prop["soft_min"] = 0.25
        prop["soft_max"] = 4.0

        # Stretch drivers
        def add_stretch_drivers(pose_bone):
            driver = pose_bone.driver_add("scale", 1).driver
            var = driver.variables.new()
            var.name = "stretch_length"
            var.targets[0].id_type = 'OBJECT'
            var.targets[0].id = self.obj
            var.targets[0].data_path = ulimb_p.path_from_id() + '["stretch_length"]'
            driver.type = 'SCRIPTED'
            driver.expression = "stretch_length"

            driver = pose_bone.driver_add("scale", 0).driver
            var = driver.variables.new()
            var.name = "stretch_length"
            var.targets[0].id_type = 'OBJECT'
            var.targets[0].id = self.obj
            var.targets[0].data_path = ulimb_p.path_from_id() + '["stretch_length"]'
            driver.type = 'SCRIPTED'
            driver.expression = "1/sqrt(stretch_length)"

            driver = pose_bone.driver_add("scale", 2).driver
            var = driver.variables.new()
            var.name = "stretch_length"
            var.targets[0].id_type = 'OBJECT'
            var.targets[0].id = self.obj
            var.targets[0].data_path = ulimb_p.path_from_id() + '["stretch_length"]'
            driver.type = 'SCRIPTED'
            driver.expression = "1/sqrt(stretch_length)"

        def add_antistretch_drivers(pose_bone):
            driver = pose_bone.driver_add("scale", 1).driver
            var = driver.variables.new()
            var.name = "stretch_length"
            var.targets[0].id_type = 'OBJECT'
            var.targets[0].id = self.obj
            var.targets[0].data_path = ulimb_p.path_from_id() + '["stretch_length"]'
            driver.type = 'SCRIPTED'
            driver.expression = "1/stretch_length"

            driver = pose_bone.driver_add("scale", 0).driver
            var = driver.variables.new()
            var.name = "stretch_length"
            var.targets[0].id_type = 'OBJECT'
            var.targets[0].id = self.obj
            var.targets[0].data_path = ulimb_p.path_from_id() + '["stretch_length"]'
            driver.type = 'SCRIPTED'
            driver.expression = "sqrt(stretch_length)"

            driver = pose_bone.driver_add("scale", 2).driver
            var = driver.variables.new()
            var.name = "stretch_length"
            var.targets[0].id_type = 'OBJECT'
            var.targets[0].id = self.obj
            var.targets[0].data_path = ulimb_p.path_from_id() + '["stretch_length"]'
            driver.type = 'SCRIPTED'
            driver.expression = "sqrt(stretch_length)"

        add_stretch_drivers(ulimb_p)
        add_stretch_drivers(flimb_p)
        add_antistretch_drivers(fantistr_p)
        add_antistretch_drivers(eantistr_p)

        # Hinge constraints / drivers
        if parent is not None:
            con = socket2_p.constraints.new('COPY_LOCATION')
            con.name = "copy_location"
            con.target = self.obj
            con.subtarget = socket1

            con = socket2_p.constraints.new('COPY_TRANSFORMS')
            con.name = "isolate_off"
            con.target = self.obj
            con.subtarget = socket1

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

        # Constrain org bones to controls
        con = pb[self.org_bones[0]].constraints.new('COPY_TRANSFORMS')
        con.name = "fk"
        con.target = self.obj
        con.subtarget = ulimb

        con = pb[self.org_bones[1]].constraints.new('COPY_TRANSFORMS')
        con.name = "fk"
        con.target = self.obj
        con.subtarget = flimb

        con = pb[self.org_bones[2]].constraints.new('COPY_TRANSFORMS')
        con.name = "fk"
        con.target = self.obj
        con.subtarget = elimb_mch

        # Set layers if specified
        if self.layers:
            ulimb_p.bone.layers = self.layers
            flimb_p.bone.layers = self.layers
            elimb_p.bone.layers = self.layers

        # Create control widgets
        create_limb_widget(self.obj, ulimb)
        create_limb_widget(self.obj, flimb)

        ob = create_widget(self.obj, elimb)
        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 [ulimb, flimb, elimb, elimb_mch]
Beispiel #42
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')

        # Create the control bones
        thigh = copy_bone(self.obj, self.org_bones[0], strip_org(self.org_bones[0]))
        shin = copy_bone(self.obj, self.org_bones[1], strip_org(self.org_bones[1]))
        foot = copy_bone(self.obj, self.org_bones[2], strip_org(self.org_bones[2]))

        # Create the foot mechanism bone
        foot_mch = copy_bone(self.obj, self.org_bones[2], make_mechanism_name(strip_org(self.org_bones[2])))

        # Create the hinge bones
        if self.org_parent != None:
            hinge = copy_bone(self.obj, self.org_parent, make_mechanism_name(thigh + ".hinge"))
            socket1 = copy_bone(self.obj, thigh, make_mechanism_name(thigh + ".socket1"))
            socket2 = copy_bone(self.obj, thigh, make_mechanism_name(thigh + ".socket2"))

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

        thigh_e = eb[thigh]
        shin_e = eb[shin]
        foot_e = eb[foot]
        foot_mch_e = eb[foot_mch]

        if self.org_parent != None:
            hinge_e = eb[hinge]
            socket1_e = eb[socket1]
            socket2_e = eb[socket2]

        # Parenting
        shin_e.parent = thigh_e
        foot_e.parent = shin_e

        foot_mch_e.use_connect = False
        foot_mch_e.parent = foot_e

        if self.org_parent != None:
            hinge_e.use_connect = False
            socket1_e.use_connect = False
            socket2_e.use_connect = False

            thigh_e.parent = hinge_e
            hinge_e.parent = socket2_e
            socket2_e.parent = None

        # Positioning
        vec = Vector(eb[self.org_bones[3]].vector)
        vec = vec.normalize()
        foot_e.tail = foot_e.head + (vec * foot_e.length)
        foot_e.roll = eb[self.org_bones[3]].roll

        if self.org_parent != None:
            center = (hinge_e.head + hinge_e.tail) / 2
            hinge_e.head = center
            socket1_e.length /= 4
            socket2_e.length /= 3

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

        thigh_p = pb[thigh]
        shin_p = pb[shin]
        foot_p = pb[foot]

        if self.org_parent != None:
            socket1_p = pb[socket1]
            socket2_p = pb[socket2]

        # Set the elbow to only bend on the x-axis.
        shin_p.rotation_mode = 'XYZ'
        if 'X' in self.primary_rotation_axis:
            shin_p.lock_rotation = (False, True, True)
        elif 'Y' in self.primary_rotation_axis:
            shin_p.lock_rotation = (True, False, True)
        else:
            shin_p.lock_rotation = (True, True, False)

        # Set up custom properties
        if self.org_parent != None:
            prop = rna_idprop_ui_prop_get(thigh_p, "isolate", create=True)
            thigh_p["isolate"] = 0.0
            prop["soft_min"] = prop["min"] = 0.0
            prop["soft_max"] = prop["max"] = 1.0

        # Hinge constraints / drivers
        if self.org_parent != None:
            con = socket2_p.constraints.new('COPY_LOCATION')
            con.name = "copy_location"
            con.target = self.obj
            con.subtarget = socket1

            con = socket2_p.constraints.new('COPY_TRANSFORMS')
            con.name = "isolate_off"
            con.target = self.obj
            con.subtarget = socket1

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

        # Constrain org bones to controls
        con = pb[self.org_bones[0]].constraints.new('COPY_TRANSFORMS')
        con.name = "fk"
        con.target = self.obj
        con.subtarget = thigh

        con = pb[self.org_bones[1]].constraints.new('COPY_TRANSFORMS')
        con.name = "fk"
        con.target = self.obj
        con.subtarget = shin

        con = pb[self.org_bones[2]].constraints.new('COPY_TRANSFORMS')
        con.name = "fk"
        con.target = self.obj
        con.subtarget = foot_mch

        # Set layers if specified
        if self.layers:
            thigh_p.bone.layers = self.layers
            shin_p.bone.layers = self.layers
            foot_p.bone.layers = self.layers

        # Create control widgets
        create_limb_widget(self.obj, thigh)
        create_limb_widget(self.obj, shin)

        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

        return [thigh, shin, foot]
    def create_def( self, tweaks ):
        org_bones = self.org_bones
        
        bpy.ops.object.mode_set(mode ='EDIT')
        eb = self.obj.data.edit_bones
        
        def_bones = []
        for i,org in enumerate(org_bones):
            if i < len(org_bones) - 1:
                # Create segments if specified
                for j in range( self.segments ):
                    name = get_bone_name( strip_org(org), 'def' )
                    def_name = copy_bone( self.obj, org, name )
                    
                    eb[ def_name ].length /= self.segments

                    # If we have more than one segments, place the 2nd and
                    # onwards on the tail of the previous bone
                    if j > 0:
                         put_bone(self.obj, def_name, eb[ def_bones[-1] ].tail)

                    def_bones += [ def_name ]
            else:
                name     = get_bone_name( strip_org(org), 'def' )
                def_name = copy_bone( self.obj, org, name )
                def_bones.append( def_name )

        # Parent deform bones
        for i,b in enumerate( def_bones ):
            if i > 0: # For all bones but the first (which has no parent)
                eb[b].parent      = eb[ def_bones[i-1] ] # to previous
                eb[b].use_connect = True

        # Constraint def to tweaks
        for d,t in zip(def_bones, tweaks):
            tidx = tweaks.index(t)

            make_constraint( self, d, {
                'constraint'  : 'COPY_TRANSFORMS',
                'subtarget'   : t
            })

            if tidx != len(tweaks) - 1:
                make_constraint( self, d, {
                    'constraint'  : 'DAMPED_TRACK',
                    'subtarget'   : tweaks[ tidx + 1 ],
                })

                make_constraint( self, d, {
                    'constraint'  : 'STRETCH_TO',
                    'subtarget'   : tweaks[ tidx + 1 ],
                })

        # Create bbone segments
        for bone in def_bones[:-1]:
            self.obj.data.bones[bone].bbone_segments = self.bbones

        self.obj.data.bones[ def_bones[0]  ].bbone_in  = 0.0
        self.obj.data.bones[ def_bones[-2] ].bbone_out = 0.0
        self.obj.data.bones[ def_bones[-1] ].bbone_in  = 0.0
        self.obj.data.bones[ def_bones[-1] ].bbone_out = 0.0


        # Rubber hose drivers
        pb = self.obj.pose.bones
        for i,t in enumerate( tweaks[1:-1] ):
            # Create custom property on tweak bone to control rubber hose
            name = 'rubber_tweak'

            if i == trunc( len( tweaks[1:-1] ) / 2 ):
                pb[t][name] = 0.0
            else:
                pb[t][name] = 1.0

            prop = rna_idprop_ui_prop_get( pb[t], name, create=True )
                                  
            prop["min"]         = 0.0
            prop["max"]         = 2.0
            prop["soft_min"]    = 0.0
            prop["soft_max"]    = 1.0
            prop["description"] = name

        for j,d in enumerate(def_bones[:-1]):
            drvs = {}
            if j != 0:
                tidx = j
                drvs[tidx] = self.obj.data.bones[d].driver_add("bbone_in").driver

            if j != len( def_bones[:-1] ) - 1:
                tidx = j + 1
                drvs[tidx] = self.obj.data.bones[d].driver_add("bbone_out").driver

            for d in drvs:
                drv = drvs[d]
                name = 'rubber_tweak'
                drv.type = 'AVERAGE'
                var = drv.variables.new()
                var.name = name
                var.type = "SINGLE_PROP"
                var.targets[0].id = self.obj
                var.targets[0].data_path = pb[tweaks[d]].path_from_id() + \
                                           '[' + '"' + name + '"' + ']'
                       
        return def_bones
Beispiel #44
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
Beispiel #45
0
def generate_rig(context, metarig):
    """ Generates a rig from a metarig.

    """
    t = Timer()

    # Random string with time appended so that
    # different rigs don't collide id's
    rig_id = random_id(16)

    # Initial configuration
    # mode_orig = context.mode  # UNUSED
    rest_backup = metarig.data.pose_position
    metarig.data.pose_position = 'REST'

    bpy.ops.object.mode_set(mode='OBJECT')

    scene = context.scene

    #------------------------------------------
    # Create/find the rig object and set it up

    # Check if the generated rig already exists, so we can
    # regenerate in the same object.  If not, create a new
    # object to generate the rig in.
    print("Fetch rig.")
    try:
        name = metarig["rig_object_name"]
    except KeyError:
        name = "rig"

    try:
        obj = scene.objects[name]
    except KeyError:
        obj = bpy.data.objects.new(name, bpy.data.armatures.new(name))
        obj.draw_type = 'WIRE'
        scene.objects.link(obj)

    obj.data.pose_position = 'POSE'

    # Get rid of anim data in case the rig already existed
    print("Clear rig animation data.")
    obj.animation_data_clear()

    # Select generated rig object
    metarig.select = False
    obj.select = True
    scene.objects.active = obj

    # Remove all bones from the generated rig armature.
    bpy.ops.object.mode_set(mode='EDIT')
    for bone in obj.data.edit_bones:
        obj.data.edit_bones.remove(bone)
    bpy.ops.object.mode_set(mode='OBJECT')

    # Create temporary duplicates for merging
    temp_rig_1 = metarig.copy()
    temp_rig_1.data = metarig.data.copy()
    scene.objects.link(temp_rig_1)

    temp_rig_2 = metarig.copy()
    temp_rig_2.data = obj.data
    scene.objects.link(temp_rig_2)

    # Select the temp rigs for merging
    for objt in scene.objects:
        objt.select = False  # deselect all objects
    temp_rig_1.select = True
    temp_rig_2.select = True
    scene.objects.active = temp_rig_2

    # Merge the temporary rigs
    bpy.ops.object.join()

    # Delete the second temp rig
    bpy.ops.object.delete()

    # Select the generated rig
    for objt in scene.objects:
        objt.select = False  # deselect all objects
    obj.select = True
    scene.objects.active = obj

    # Copy over bone properties
    for bone in metarig.data.bones:
        bone_gen = obj.data.bones[bone.name]

        # B-bone stuff
        bone_gen.bbone_segments = bone.bbone_segments
        bone_gen.bbone_in = bone.bbone_in
        bone_gen.bbone_out = bone.bbone_out

    # Copy over the pose_bone properties
    for bone in metarig.pose.bones:
        bone_gen = obj.pose.bones[bone.name]

        # Rotation mode and transform locks
        bone_gen.rotation_mode = bone.rotation_mode
        bone_gen.lock_rotation = tuple(bone.lock_rotation)
        bone_gen.lock_rotation_w = bone.lock_rotation_w
        bone_gen.lock_rotations_4d = bone.lock_rotations_4d
        bone_gen.lock_location = tuple(bone.lock_location)
        bone_gen.lock_scale = tuple(bone.lock_scale)

        # rigify_type and rigify_parameters
        bone_gen.rigify_type = bone.rigify_type
        for prop in dir(bone_gen.rigify_parameters):
            if (not prop.startswith("_")) \
            and (not prop.startswith("bl_")) \
            and (prop != "rna_type"):
                try:
                    setattr(bone_gen.rigify_parameters, prop, \
                            getattr(bone.rigify_parameters, prop))
                except AttributeError:
                    print("FAILED TO COPY PARAMETER: " + str(prop))

        # Custom properties
        for prop in bone.keys():
            try:
                bone_gen[prop] = bone[prop]
            except KeyError:
                pass

        # Constraints
        for con1 in bone.constraints:
            con2 = bone_gen.constraints.new(type=con1.type)
            copy_attributes(con1, con2)

            # Set metarig target to rig target
            if "target" in dir(con2):
                if con2.target == metarig:
                    con2.target = obj

    # Copy drivers
    if metarig.animation_data:
        for d1 in metarig.animation_data.drivers:
            d2 = obj.driver_add(d1.data_path)
            copy_attributes(d1, d2)
            copy_attributes(d1.driver, d2.driver)

            # Remove default modifiers, variables, etc.
            for m in d2.modifiers:
                d2.modifiers.remove(m)
            for v in d2.driver.variables:
                d2.driver.variables.remove(v)

            # Copy modifiers
            for m1 in d1.modifiers:
                m2 = d2.modifiers.new(type=m1.type)
                copy_attributes(m1, m2)

            # Copy variables
            for v1 in d1.driver.variables:
                v2 = d2.driver.variables.new()
                copy_attributes(v1, v2)
                for i in range(len(v1.targets)):
                    copy_attributes(v1.targets[i], v2.targets[i])
                    # Switch metarig targets to rig targets
                    if v2.targets[i].id == metarig:
                        v2.targets[i].id = obj

                    # Mark targets that may need to be altered after rig generation
                    tar = v2.targets[i]
                    # If a custom property
                    if v2.type == 'SINGLE_PROP' \
                    and re.match('^pose.bones\["[^"\]]*"\]\["[^"\]]*"\]$', tar.data_path):
                        tar.data_path = "RIGIFY-" + tar.data_path

            # Copy key frames
            for i in range(len(d1.keyframe_points)):
                d2.keyframe_points.add()
                k1 = d1.keyframe_points[i]
                k2 = d2.keyframe_points[i]
                copy_attributes(k1, k2)

    t.tick("Duplicate rig: ")
    #----------------------------------
    # Make a list of the original bones so we can keep track of them.
    original_bones = [bone.name for bone in obj.data.bones]

    # Add the ORG_PREFIX to the original bones.
    bpy.ops.object.mode_set(mode='OBJECT')
    for i in range(0, len(original_bones)):
        obj.data.bones[original_bones[i]].name = make_original_name(original_bones[i])
        original_bones[i] = make_original_name(original_bones[i])

    # Create a sorted list of the original bones, sorted in the order we're
    # going to traverse them for rigging.
    # (root-most -> leaf-most, alphabetical)
    bones_sorted = []
    for name in original_bones:
        bones_sorted += [name]
    bones_sorted.sort()  # first sort by names
    bones_sorted.sort(key=lambda bone: len(obj.pose.bones[bone].parent_recursive))  # then parents before children

    t.tick("Make list of org bones: ")
    #----------------------------------
    # Create the root bone.
    bpy.ops.object.mode_set(mode='EDIT')
    root_bone = new_bone(obj, ROOT_NAME)
    obj.data.edit_bones[root_bone].head = (0, 0, 0)
    obj.data.edit_bones[root_bone].tail = (0, 1, 0)
    obj.data.edit_bones[root_bone].roll = 0
    bpy.ops.object.mode_set(mode='OBJECT')
    obj.data.bones[root_bone].layers = ROOT_LAYER
    # Put the rig_name in the armature custom properties
    rna_idprop_ui_prop_get(obj.data, "rig_id", create=True)
    obj.data["rig_id"] = rig_id

    t.tick("Create root bone: ")
    #----------------------------------
    try:
        # Collect/initialize all the rigs.
        rigs = []
        for bone in bones_sorted:
            bpy.ops.object.mode_set(mode='EDIT')
            rigs += get_bone_rigs(obj, bone)
        t.tick("Initialize rigs: ")

        # Generate all the rigs.
        ui_scripts = []
        for rig in rigs:
            # Go into editmode in the rig armature
            bpy.ops.object.mode_set(mode='OBJECT')
            context.scene.objects.active = obj
            obj.select = True
            bpy.ops.object.mode_set(mode='EDIT')
            scripts = rig.generate()
            if scripts != None:
                ui_scripts += [scripts[0]]
        t.tick("Generate rigs: ")
    except Exception as e:
        # Cleanup if something goes wrong
        print("Rigify: failed to generate rig.")
        metarig.data.pose_position = rest_backup
        obj.data.pose_position = 'POSE'
        bpy.ops.object.mode_set(mode='OBJECT')

        # Continue the exception
        raise e

    #----------------------------------
    bpy.ops.object.mode_set(mode='OBJECT')

    # Get a list of all the bones in the armature
    bones = [bone.name for bone in obj.data.bones]

    # Parent any free-floating bones to the root.
    bpy.ops.object.mode_set(mode='EDIT')
    for bone in bones:
        if obj.data.edit_bones[bone].parent is None:
            obj.data.edit_bones[bone].use_connect = False
            obj.data.edit_bones[bone].parent = obj.data.edit_bones[root_bone]
    bpy.ops.object.mode_set(mode='OBJECT')

    # Lock transforms on all non-control bones
    r = re.compile("[A-Z][A-Z][A-Z]-")
    for bone in bones:
        if r.match(bone):
            pb = obj.pose.bones[bone]
            pb.lock_location = (True, True, True)
            pb.lock_rotation = (True, True, True)
            pb.lock_rotation_w = True
            pb.lock_scale = (True, True, True)

    # Every bone that has a name starting with "DEF-" make deforming.  All the
    # others make non-deforming.
    for bone in bones:
        if obj.data.bones[bone].name.startswith(DEF_PREFIX):
            obj.data.bones[bone].use_deform = True
        else:
            obj.data.bones[bone].use_deform = False

    # Alter marked driver targets
    if obj.animation_data:
        for d in obj.animation_data.drivers:
            for v in d.driver.variables:
                for tar in v.targets:
                    if tar.data_path.startswith("RIGIFY-"):
                        temp, bone, prop = tuple([x.strip('"]') for x in tar.data_path.split('["')])
                        if bone in obj.data.bones \
                        and prop in obj.pose.bones[bone].keys():
                            tar.data_path = tar.data_path[7:]
                        else:
                            tar.data_path = 'pose.bones["%s"]["%s"]' % (make_original_name(bone), prop)

    # Move all the original bones to their layer.
    for bone in original_bones:
        obj.data.bones[bone].layers = ORG_LAYER

    # Move all the bones with names starting with "MCH-" to their layer.
    for bone in bones:
        if obj.data.bones[bone].name.startswith(MCH_PREFIX):
            obj.data.bones[bone].layers = MCH_LAYER

    # Move all the bones with names starting with "DEF-" to their layer.
    for bone in bones:
        if obj.data.bones[bone].name.startswith(DEF_PREFIX):
            obj.data.bones[bone].layers = DEF_LAYER

    # Create root bone widget
    create_root_widget(obj, "root")

    # Assign shapes to bones
    # Object's with name WGT-<bone_name> get used as that bone's shape.
    for bone in bones:
        wgt_name = (WGT_PREFIX + obj.data.bones[bone].name)[:63]  # Object names are limited to 63 characters... arg
        if wgt_name in context.scene.objects:
            # Weird temp thing because it won't let me index by object name
            for ob in context.scene.objects:
                if ob.name == wgt_name:
                    obj.pose.bones[bone].custom_shape = ob
                    break
            # This is what it should do:
            # obj.pose.bones[bone].custom_shape = context.scene.objects[wgt_name]
    # Reveal all the layers with control bones on them
    vis_layers = [False for n in range(0, 32)]
    for bone in bones:
        for i in range(0, 32):
            vis_layers[i] = vis_layers[i] or obj.data.bones[bone].layers[i]
    for i in range(0, 32):
        vis_layers[i] = vis_layers[i] and not (ORG_LAYER[i] or MCH_LAYER[i] or DEF_LAYER[i])
    obj.data.layers = vis_layers

    # Ensure the collection of layer names exists
    for i in range(1 + len(metarig.data.rigify_layers), 29):
        metarig.data.rigify_layers.add()

    # Create list of layer name/row pairs
    layer_layout = []
    for l in metarig.data.rigify_layers:
        layer_layout += [(l.name, l.row)]

    # Generate the UI script
    if "rig_ui.py" in bpy.data.texts:
        script = bpy.data.texts["rig_ui.py"]
        script.clear()
    else:
        script = bpy.data.texts.new("rig_ui.py")
    script.write(UI_SLIDERS % rig_id)
    for s in ui_scripts:
        script.write("\n        " + s.replace("\n", "\n        ") + "\n")
    script.write(layers_ui(vis_layers, layer_layout))
    script.write(UI_REGISTER)
    script.use_module = True

    # Run UI script
    exec(script.as_string(), {})

    t.tick("The rest: ")
    #----------------------------------
    # Deconfigure
    bpy.ops.object.mode_set(mode='OBJECT')
    metarig.data.pose_position = rest_backup
    obj.data.pose_position = 'POSE'
Beispiel #46
0
    def control(self):
        """ Generate the control rig.
        """
        bpy.ops.object.mode_set(mode='EDIT')

        # Figure out the name for the control bone (remove the last .##)
        ctrl_name = re.sub("([0-9]+\.)",
                           "",
                           strip_org(self.org_bones[0])[::-1],
                           count=1)[::-1]

        # Create the bones
        ctrl = copy_bone(self.obj, self.org_bones[0], ctrl_name)

        helpers = []
        bones = []
        for bone in self.org_bones:
            bones += [copy_bone(self.obj, bone, strip_org(bone))]
            helpers += [
                copy_bone(self.obj, bone, make_mechanism_name(strip_org(bone)))
            ]

        # Position bones
        eb = self.obj.data.edit_bones

        length = 0.0
        for bone in helpers:
            length += eb[bone].length
            eb[bone].length /= 2

        eb[ctrl].length = length * 1.5

        # Parent bones
        prev = eb[self.org_bones[0]].parent
        for (b, h) in zip(bones, helpers):
            b_e = eb[b]
            h_e = eb[h]
            b_e.use_connect = False
            h_e.use_connect = False

            b_e.parent = h_e
            h_e.parent = prev

            prev = b_e

        # Transform locks and rotation mode
        bpy.ops.object.mode_set(mode='OBJECT')
        pb = self.obj.pose.bones

        for bone in bones[1:]:
            pb[bone].lock_location = True, True, True

        if pb[self.org_bones[0]].bone.use_connect is True:
            pb[bones[0]].lock_location = True, True, True

        pb[ctrl].lock_scale = True, False, True

        for bone in helpers:
            pb[bone].rotation_mode = 'XYZ'

        # Drivers
        i = 1
        val = 1.2 / (len(self.org_bones) - 1)
        for bone in helpers:
            # Add custom prop
            prop_name = "bend_%02d" % i
            prop = rna_idprop_ui_prop_get(pb[ctrl], prop_name, create=True)
            prop["min"] = 0.0
            prop["max"] = 1.0
            prop["soft_min"] = 0.0
            prop["soft_max"] = 1.0
            if i == 1:
                pb[ctrl][prop_name] = 0.0
            else:
                pb[ctrl][prop_name] = val

            # Add driver
            if 'X' in self.primary_rotation_axis:
                fcurve = pb[bone].driver_add("rotation_euler", 0)
            elif 'Y' in self.primary_rotation_axis:
                fcurve = pb[bone].driver_add("rotation_euler", 1)
            else:
                fcurve = pb[bone].driver_add("rotation_euler", 2)

            driver = fcurve.driver
            driver.type = 'SCRIPTED'

            var = driver.variables.new()
            var.name = "ctrl_y"
            var.targets[0].id_type = 'OBJECT'
            var.targets[0].id = self.obj
            var.targets[0].data_path = pb[ctrl].path_from_id() + '.scale[1]'

            var = driver.variables.new()
            var.name = "bend"
            var.targets[0].id_type = 'OBJECT'
            var.targets[0].id = self.obj
            var.targets[0].data_path = pb[ctrl].path_from_id(
            ) + '["' + prop_name + '"]'

            if '-' in self.primary_rotation_axis:
                driver.expression = "-(1.0-ctrl_y) * bend * 3.14159 * 2"
            else:
                driver.expression = "(1.0-ctrl_y) * bend * 3.14159 * 2"

            i += 1

        # Constraints
        con = pb[helpers[0]].constraints.new('COPY_LOCATION')
        con.name = "copy_location"
        con.target = self.obj
        con.subtarget = ctrl

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

        # Constrain org bones to the control bones
        for (bone, org) in zip(bones, self.org_bones):
            con = pb[org].constraints.new('COPY_TRANSFORMS')
            con.name = "copy_transforms"
            con.target = self.obj
            con.subtarget = bone

        # Set layers for extra control bones
        if self.ex_layers:
            for bone in bones:
                pb[bone].bone.layers = self.ex_layers

        # Create control widgets
        w = create_widget(self.obj, ctrl)
        if w is not None:
            mesh = w.data
            verts = [(0, 0, 0), (0, 1, 0), (0.05, 1, 0), (0.05, 1.1, 0),
                     (-0.05, 1.1, 0), (-0.05, 1, 0)]
            if 'Z' in self.primary_rotation_axis:
                # Flip x/z coordinates
                temp = []
                for v in verts:
                    temp += [(v[2], v[1], v[0])]
                verts = temp
            edges = [(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 1)]
            mesh.from_pydata(verts, edges, [])
            mesh.update()

        for bone in bones:
            create_limb_widget(self.obj, bone)
Beispiel #47
0
    def control(self):
        """ Generate the control rig.
        """
        bpy.ops.object.mode_set(mode='EDIT')

        # Figure out the name for the control bone (remove the last .##)
        ctrl_name = re.sub("([0-9]+\.)", "", strip_org(self.org_bones[0])[::-1], count=1)[::-1]

        # Create the bones
        ctrl = copy_bone(self.obj, self.org_bones[0], ctrl_name)

        helpers = []
        bones = []
        for bone in self.org_bones:
            bones += [copy_bone(self.obj, bone, strip_org(bone))]
            helpers += [copy_bone(self.obj, bone, make_mechanism_name(strip_org(bone)))]

        # Position bones
        eb = self.obj.data.edit_bones

        length = 0.0
        for bone in helpers:
            length += eb[bone].length
            eb[bone].length /= 2

        eb[ctrl].length = length * 1.5

        # Parent bones
        prev = eb[self.org_bones[0]].parent
        for (b, h) in zip(bones, helpers):
            b_e = eb[b]
            h_e = eb[h]
            b_e.use_connect = False
            h_e.use_connect = False

            b_e.parent = h_e
            h_e.parent = prev

            prev = b_e

        # Transform locks and rotation mode
        bpy.ops.object.mode_set(mode='OBJECT')
        pb = self.obj.pose.bones

        for bone in bones[1:]:
            pb[bone].lock_location = True, True, True

        if pb[self.org_bones[0]].bone.use_connect is True:
            pb[bones[0]].lock_location = True, True, True

        pb[ctrl].lock_scale = True, False, True

        for bone in helpers:
            pb[bone].rotation_mode = 'XYZ'

        # Drivers
        i = 1
        val = 1.2 / (len(self.org_bones) - 1)
        for bone in helpers:
            # Add custom prop
            prop_name = "bend_%02d" % i
            prop = rna_idprop_ui_prop_get(pb[ctrl], prop_name, create=True)
            prop["min"] = 0.0
            prop["max"] = 1.0
            prop["soft_min"] = 0.0
            prop["soft_max"] = 1.0
            if i == 1:
                pb[ctrl][prop_name] = 0.0
            else:
                pb[ctrl][prop_name] = val

            # Add driver
            if 'X' in self.primary_rotation_axis:
                fcurve = pb[bone].driver_add("rotation_euler", 0)
            elif 'Y' in self.primary_rotation_axis:
                fcurve = pb[bone].driver_add("rotation_euler", 1)
            else:
                fcurve = pb[bone].driver_add("rotation_euler", 2)

            driver = fcurve.driver
            driver.type = 'SCRIPTED'

            var = driver.variables.new()
            var.name = "ctrl_y"
            var.targets[0].id_type = 'OBJECT'
            var.targets[0].id = self.obj
            var.targets[0].data_path = pb[ctrl].path_from_id() + '.scale[1]'

            var = driver.variables.new()
            var.name = "bend"
            var.targets[0].id_type = 'OBJECT'
            var.targets[0].id = self.obj
            var.targets[0].data_path = pb[ctrl].path_from_id() + '["' + prop_name + '"]'

            if '-' in self.primary_rotation_axis:
                driver.expression = "-(1.0-ctrl_y) * bend * 3.14159 * 2"
            else:
                driver.expression = "(1.0-ctrl_y) * bend * 3.14159 * 2"

            i += 1

        # Constraints
        con = pb[helpers[0]].constraints.new('COPY_LOCATION')
        con.name = "copy_location"
        con.target = self.obj
        con.subtarget = ctrl

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

        # Constrain org bones to the control bones
        for (bone, org) in zip(bones, self.org_bones):
            con = pb[org].constraints.new('COPY_TRANSFORMS')
            con.name = "copy_transforms"
            con.target = self.obj
            con.subtarget = bone

        # Set layers for extra control bones
        if self.ex_layers:
            for bone in bones:
                pb[bone].bone.layers = self.ex_layers

        # Create control widgets
        w = create_widget(self.obj, ctrl)
        if w != None:
            mesh = w.data
            verts = [(0, 0, 0), (0, 1, 0), (0.05, 1, 0), (0.05, 1.1, 0), (-0.05, 1.1, 0), (-0.05, 1, 0)]
            if 'Z' in self.primary_rotation_axis:
                # Flip x/z coordinates
                temp = []
                for v in verts:
                    temp += [(v[2], v[1], v[0])]
                verts = temp
            edges = [(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 1)]
            mesh.from_pydata(verts, edges, [])
            mesh.update()

        for bone in bones:
            create_limb_widget(self.obj, bone)
    def create_arm(self, bones):
        org_bones = self.org_bones

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

        ctrl = get_bone_name(org_bones[2], "ctrl", "ik")

        # Create IK arm control
        ctrl = copy_bone(self.obj, org_bones[2], ctrl)

        # clear parent (so that rigify will parent to root)
        eb[ctrl].parent = None
        eb[ctrl].use_connect = False

        # Parent
        eb[bones["ik"]["mch_target"]].parent = eb[ctrl]
        eb[bones["ik"]["mch_target"]].use_connect = False

        # MCH for ik control
        ctrl_socket = copy_bone(self.obj, org_bones[2], get_bone_name(org_bones[2], "mch", "ik_socket"))
        eb[ctrl_socket].tail = eb[ctrl_socket].head + 0.8 * (eb[ctrl_socket].tail - eb[ctrl_socket].head)
        eb[ctrl_socket].parent = None
        eb[ctrl].parent = eb[ctrl_socket]

        ctrl_root = copy_bone(self.obj, org_bones[2], get_bone_name(org_bones[2], "mch", "ik_root"))
        eb[ctrl_root].tail = eb[ctrl_root].head + 0.7 * (eb[ctrl_root].tail - eb[ctrl_root].head)
        eb[ctrl_root].use_connect = False
        eb[ctrl_root].parent = eb["root"]

        if eb[org_bones[0]].parent:
            arm_parent = eb[org_bones[0]].parent
            ctrl_parent = copy_bone(self.obj, org_bones[2], get_bone_name(org_bones[2], "mch", "ik_parent"))
            eb[ctrl_parent].tail = eb[ctrl_parent].head + 0.6 * (eb[ctrl_parent].tail - eb[ctrl_parent].head)
            eb[ctrl_parent].use_connect = False
            eb[ctrl_parent].parent = eb[org_bones[0]].parent
        else:
            arm_parent = None

        # Set up constraints

        # Constrain ik ctrl to root / parent

        make_constraint(self, ctrl_socket, {"constraint": "COPY_TRANSFORMS", "subtarget": ctrl_root})

        if arm_parent:
            make_constraint(self, ctrl_socket, {"constraint": "COPY_TRANSFORMS", "subtarget": ctrl_parent})

        # Constrain mch target bone to the ik control and mch stretch

        make_constraint(
            self,
            bones["ik"]["mch_target"],
            {"constraint": "COPY_LOCATION", "subtarget": bones["ik"]["mch_str"], "head_tail": 1.0},
        )

        # Constrain mch ik stretch bone to the ik control
        make_constraint(self, bones["ik"]["mch_str"], {"constraint": "DAMPED_TRACK", "subtarget": ctrl})
        make_constraint(self, bones["ik"]["mch_str"], {"constraint": "STRETCH_TO", "subtarget": ctrl})
        make_constraint(
            self,
            bones["ik"]["mch_str"],
            {"constraint": "LIMIT_SCALE", "use_min_y": True, "use_max_y": True, "max_y": 1.05, "owner_space": "LOCAL"},
        )

        # Create ik/fk switch property
        pb = self.obj.pose.bones
        pb_parent = pb[bones["parent"]]

        # Modify rotation mode for ik and tweak controls
        pb[bones["ik"]["ctrl"]["limb"]].rotation_mode = "ZXY"

        for b in bones["tweak"]["ctrl"]:
            pb[b].rotation_mode = "ZXY"

        pb_parent["IK_Strertch"] = 1.0
        prop = rna_idprop_ui_prop_get(pb_parent, "IK_Strertch", create=True)
        prop["min"] = 0.0
        prop["max"] = 1.0
        prop["soft_min"] = 0.0
        prop["soft_max"] = 1.0
        prop["description"] = "IK Stretch"

        # Add driver to limit scale constraint influence
        b = bones["ik"]["mch_str"]
        drv = pb[b].constraints[-1].driver_add("influence").driver
        drv.type = "SUM"

        var = drv.variables.new()
        var.name = prop.name
        var.type = "SINGLE_PROP"
        var.targets[0].id = self.obj
        var.targets[0].data_path = pb_parent.path_from_id() + "[" + '"' + prop.name + '"' + "]"

        drv_modifier = self.obj.animation_data.drivers[-1].modifiers[0]

        drv_modifier.mode = "POLYNOMIAL"
        drv_modifier.poly_order = 1
        drv_modifier.coefficients[0] = 1.0
        drv_modifier.coefficients[1] = -1.0

        # Create hand widget
        create_hand_widget(self.obj, ctrl, bone_transform_name=None)

        bones["ik"]["ctrl"]["terminal"] = [ctrl]
        if arm_parent:
            bones["ik"]["mch_hand"] = [ctrl_socket, ctrl_root, ctrl_parent]
        else:
            bones["ik"]["mch_hand"] = [ctrl_socket, ctrl_root]

        return bones
Beispiel #49
0
def create_leg( cls, bones ):
    org_bones = list(
        [cls.org_bones[0]] + connected_children_names(cls.obj, cls.org_bones[0])
    )

    bones['ik']['ctrl']['terminal'] = []
    
    bpy.ops.object.mode_set(mode='EDIT')
    eb = cls.obj.data.edit_bones

    # Create toes def bone
    toes_def = get_bone_name( org_bones[-1], 'def' )
    toes_def = copy_bone( cls.obj, org_bones[-1], toes_def )

    eb[ toes_def ].use_connect = False
    eb[ toes_def ].parent      = eb[ bones['def'][-1] ]
    eb[ toes_def ].use_connect = True

    bones['def'] += [ toes_def ]

    # Create IK leg control
    ctrl = get_bone_name( org_bones[2], 'ctrl', 'ik' )
    ctrl = copy_bone( cls.obj, org_bones[2], ctrl )

    # clear parent (so that rigify will parent to root) 
    eb[ ctrl ].parent      = None
    eb[ ctrl ].use_connect = False

    # Create heel ctrl bone
    heel = get_bone_name( org_bones[2], 'ctrl', 'heel_ik' )
    heel = copy_bone( cls.obj, org_bones[2], heel )
    orient_bone( cls, eb[ heel ], 'y', 0.5 )
    eb[ heel ].length = eb[ org_bones[2] ].length / 2

    # Reset control position and orientation
    l = eb[ ctrl ].length
    orient_bone( cls, eb[ ctrl ], 'y', reverse = True )
    eb[ ctrl ].length = l

    # Parent 
    eb[ heel ].use_connect = False
    eb[ heel ].parent      = eb[ ctrl ]

    eb[ bones['ik']['mch_target'] ].parent      = eb[ heel ]
    eb[ bones['ik']['mch_target'] ].use_connect = False

    # Create foot mch rock and roll bones

    # Get the tmp heel (floating unconnected without children)
    tmp_heel = ""
    for b in cls.obj.data.bones[ org_bones[2] ].children:
        if not b.use_connect and not b.children:
            tmp_heel = b.name

    # roll1 MCH bone
    roll1_mch = get_bone_name( tmp_heel, 'mch', 'roll' )
    roll1_mch = copy_bone( cls.obj, org_bones[2], roll1_mch )

    # clear parent
    eb[ roll1_mch ].use_connect = False
    eb[ roll1_mch ].parent      = None

    flip_bone( cls.obj, roll1_mch )

    # Create 2nd roll mch, and two rock mch bones
    roll2_mch = get_bone_name( tmp_heel, 'mch', 'roll' )
    roll2_mch = copy_bone( cls.obj, org_bones[3], roll2_mch )    

    eb[ roll2_mch ].use_connect = False
    eb[ roll2_mch ].parent      = None
    
    put_bone( 
        cls.obj, 
        roll2_mch, 
        ( eb[ tmp_heel ].head + eb[ tmp_heel ].tail ) / 2
    )

    eb[ roll2_mch ].length /= 4
    
    # Rock MCH bones
    rock1_mch = get_bone_name( tmp_heel, 'mch', 'rock' )
    rock1_mch = copy_bone( cls.obj, tmp_heel, rock1_mch )    

    eb[ rock1_mch ].use_connect = False
    eb[ rock1_mch ].parent      = None    
    
    orient_bone( cls, eb[ rock1_mch ], 'y', 1.0, reverse = True )
    eb[ rock1_mch ].length = eb[ tmp_heel ].length / 2
    
    rock2_mch = get_bone_name( tmp_heel, 'mch', 'rock' )
    rock2_mch = copy_bone( cls.obj, tmp_heel, rock2_mch )

    eb[ rock2_mch ].use_connect = False
    eb[ rock2_mch ].parent      = None    

    orient_bone( cls, eb[ rock2_mch ], 'y', 1.0 )
    eb[ rock2_mch ].length = eb[ tmp_heel ].length / 2
    
    # Parent rock and roll MCH bones
    eb[ roll1_mch ].parent = eb[ roll2_mch ]
    eb[ roll2_mch ].parent = eb[ rock1_mch ]
    eb[ rock1_mch ].parent = eb[ rock2_mch ]
    eb[ rock2_mch ].parent = eb[ ctrl ]

    # Constrain rock and roll MCH bones
    make_constraint( cls, roll1_mch, {
        'constraint'   : 'COPY_ROTATION',
        'subtarget'    : heel,
        'owner_space'  : 'LOCAL',
        'target_space' : 'LOCAL'
    })    
    make_constraint( cls, roll1_mch, {
        'constraint'  : 'LIMIT_ROTATION',
        'use_limit_x' : True,
        'max_x'       : math.radians(360),
        'owner_space' : 'LOCAL'
    })
    make_constraint( cls, roll2_mch, {
        'constraint'   : 'COPY_ROTATION',
        'subtarget'    : heel,
        'use_y'        : False,
        'use_z'        : False,
        'invert_x'     : True,
        'owner_space'  : 'LOCAL',
        'target_space' : 'LOCAL'
    })    
    make_constraint( cls, roll2_mch, {
        'constraint'  : 'LIMIT_ROTATION',
        'use_limit_x' : True,
        'max_x'       : math.radians(360),
        'owner_space' : 'LOCAL'
    })    

    pb = cls.obj.pose.bones   
    for i,b in enumerate([ rock1_mch, rock2_mch ]):
        head_tail = pb[b].head - pb[tmp_heel].head
        if '.L' in b:
            if not i:
                min_y = 0
                max_y = math.radians(360)
            else:
                min_y = math.radians(-360)
                max_y = 0
        else:
            if not i:
                min_y = math.radians(-360)
                max_y = 0
            else:
                min_y = 0
                max_y = math.radians(360)

                
        make_constraint( cls, b, {
            'constraint'   : 'COPY_ROTATION',
            'subtarget'    : heel,
            'use_x'        : False,
            'use_z'        : False,
            'owner_space'  : 'LOCAL',
            'target_space' : 'LOCAL'
        })    
        make_constraint( cls, b, {
            'constraint'  : 'LIMIT_ROTATION',
            'use_limit_y' : True,
            'min_y'       : min_y,
            'max_y'       : max_y,
            'owner_space' : 'LOCAL'
        })    

    # Constrain 4th ORG to roll2 MCH bone
    make_constraint( cls, org_bones[3], {
        'constraint'  : 'COPY_TRANSFORMS',
        'subtarget'   : roll2_mch
    })

    # Set up constraints
    # Constrain mch target bone to the ik control and mch stretch
   
    make_constraint( cls, bones['ik']['mch_target'], {
        'constraint'  : 'COPY_LOCATION',
        'subtarget'   : bones['ik']['mch_str'],
        'head_tail'   : 1.0
    })

    # Constrain mch ik stretch bone to the ik control
    make_constraint( cls, bones['ik']['mch_str'], {
        'constraint'  : 'DAMPED_TRACK',
        'subtarget'   : roll1_mch,
        'head_tail'   : 1.0
    })
    make_constraint( cls, bones['ik']['mch_str'], {
        'constraint'  : 'STRETCH_TO',
        'subtarget'   : roll1_mch,
        'head_tail'   : 1.0
    })
    make_constraint( cls, bones['ik']['mch_str'], {
        'constraint'  : 'LIMIT_SCALE',
        'use_min_y'   : True,
        'use_max_y'   : True,
        'max_y'       : 1.05,
        'owner_space' : 'LOCAL'
    })

    # Modify rotation mode for ik and tweak controls
    pb[bones['ik']['ctrl']['limb']].rotation_mode = 'ZXY'

    for b in bones['tweak']['ctrl']:
        pb[b].rotation_mode = 'ZXY'

    # Create ik/fk switch property
    pb_parent = pb[ bones['parent'] ]
    
    pb_parent['IK_Strertch'] = 1.0
    prop = rna_idprop_ui_prop_get( pb_parent, 'IK_Strertch', create=True )
    prop["min"]         = 0.0
    prop["max"]         = 1.0
    prop["soft_min"]    = 0.0
    prop["soft_max"]    = 1.0
    prop["description"] = 'IK Stretch'

    # Add driver to limit scale constraint influence
    b        = bones['ik']['mch_str']
    drv      = pb[b].constraints[-1].driver_add("influence").driver
    drv.type = 'AVERAGE'
    
    var = drv.variables.new()
    var.name = prop.name
    var.type = "SINGLE_PROP"
    var.targets[0].id = cls.obj
    var.targets[0].data_path = \
        pb_parent.path_from_id() + '['+ '"' + prop.name + '"' + ']'

    drv_modifier = cls.obj.animation_data.drivers[-1].modifiers[0]
    
    drv_modifier.mode            = 'POLYNOMIAL'
    drv_modifier.poly_order      = 1
    drv_modifier.coefficients[0] = 1.0
    drv_modifier.coefficients[1] = -1.0

    # Create leg widget
    create_foot_widget(cls.obj, ctrl, bone_transform_name=None)

    # Create heel ctrl locks
    pb[ heel ].lock_location = True, True, True
    pb[ heel ].lock_rotation = False, False, True
    pb[ heel ].lock_scale    = True, True, True

    # Add ballsocket widget to heel
    create_ballsocket_widget(cls.obj, heel, bone_transform_name=None)

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

    if len( org_bones ) >= 4:
        # Create toes control bone
        toes = get_bone_name( org_bones[3], 'ctrl' )
        toes = copy_bone( cls.obj, org_bones[3], toes )

        eb[ toes ].use_connect = False
        eb[ toes ].parent      = eb[ org_bones[3] ]
        
        # Constrain toes def bones
        make_constraint( cls, bones['def'][-2], {
            'constraint'  : 'DAMPED_TRACK',
            'subtarget'   : toes
        })
        make_constraint( cls, bones['def'][-2], {
            'constraint'  : 'STRETCH_TO',
            'subtarget'   : toes
        })        
       
        make_constraint( cls, bones['def'][-1], {
            'constraint'  : 'COPY_TRANSFORMS',
            'subtarget'   : toes
        })

        # Find IK/FK switch property
        pb   = cls.obj.pose.bones
        prop = rna_idprop_ui_prop_get( pb[ bones['parent'] ], 'IK/FK' )
        
        # Add driver to limit scale constraint influence
        b        = org_bones[3]
        drv      = pb[b].constraints[-1].driver_add("influence").driver
        drv.type = 'AVERAGE'
        
        var = drv.variables.new()
        var.name = prop.name
        var.type = "SINGLE_PROP"
        var.targets[0].id = cls.obj
        var.targets[0].data_path = \
            pb_parent.path_from_id() + '['+ '"' + prop.name + '"' + ']'

        drv_modifier = cls.obj.animation_data.drivers[-1].modifiers[0]
        
        drv_modifier.mode            = 'POLYNOMIAL'
        drv_modifier.poly_order      = 1
        drv_modifier.coefficients[0] = 1.0
        drv_modifier.coefficients[1] = -1.0
   
        # Create toe circle widget
        create_circle_widget(cls.obj, toes, radius=0.4, head_tail=0.5)

        bones['ik']['ctrl']['terminal'] += [ toes ]

    bones['ik']['ctrl']['terminal'] += [ heel, ctrl ]
    
    return bones
Beispiel #50
0
    def create_drivers(self, bones):

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

        ctrl = pb[bones['ik']['mch_foot'][0]]

        props = ["IK_follow", "root/parent"]

        for prop in props:
            if prop == 'IK_follow':

                ctrl[prop] = True
                rna_prop = rna_idprop_ui_prop_get(ctrl, prop, create=True)
                rna_prop["min"] = False
                rna_prop["max"] = True
                rna_prop["description"] = prop

                drv = ctrl.constraints[0].driver_add("mute").driver
                drv.type = 'AVERAGE'

                var = drv.variables.new()
                var.name = prop
                var.type = "SINGLE_PROP"
                var.targets[0].id = self.obj
                var.targets[0].data_path = \
                ctrl.path_from_id() + '['+ '"' + prop + '"' + ']'

                drv_modifier = self.obj.animation_data.drivers[-1].modifiers[0]

                drv_modifier.mode = 'POLYNOMIAL'
                drv_modifier.poly_order = 1
                drv_modifier.coefficients[0] = 1.0
                drv_modifier.coefficients[1] = -1.0

                if len(ctrl.constraints) > 1:
                    drv = ctrl.constraints[1].driver_add("mute").driver
                    drv.type = 'AVERAGE'

                    var = drv.variables.new()
                    var.name = prop
                    var.type = "SINGLE_PROP"
                    var.targets[0].id = self.obj
                    var.targets[0].data_path = \
                    ctrl.path_from_id() + '['+ '"' + prop + '"' + ']'

                    drv_modifier = self.obj.animation_data.drivers[
                        -1].modifiers[0]

                    drv_modifier.mode = 'POLYNOMIAL'
                    drv_modifier.poly_order = 1
                    drv_modifier.coefficients[0] = 1.0
                    drv_modifier.coefficients[1] = -1.0

            elif len(ctrl.constraints) > 1:
                ctrl[prop] = 0.0
                rna_prop = rna_idprop_ui_prop_get(ctrl, prop, create=True)
                rna_prop["min"] = 0.0
                rna_prop["max"] = 1.0
                rna_prop["soft_min"] = 0.0
                rna_prop["soft_max"] = 1.0
                rna_prop["description"] = prop

                # drv = ctrl.constraints[ 0 ].driver_add("influence").driver
                # drv.type = 'AVERAGE'
                #
                # var = drv.variables.new()
                # var.name = prop
                # var.type = "SINGLE_PROP"
                # var.targets[0].id = self.obj
                # var.targets[0].data_path = \
                # ctrl.path_from_id() + '['+ '"' + prop + '"' + ']'
                #
                # drv_modifier = self.obj.animation_data.drivers[-1].modifiers[0]
                #
                # drv_modifier.mode            = 'POLYNOMIAL'
                # drv_modifier.poly_order      = 1
                # drv_modifier.coefficients[0] = 1.0
                # drv_modifier.coefficients[1] = -1.0

                drv = ctrl.constraints[1].driver_add("influence").driver
                drv.type = 'AVERAGE'

                var = drv.variables.new()
                var.name = prop
                var.type = "SINGLE_PROP"
                var.targets[0].id = self.obj
                var.targets[0].data_path = \
                ctrl.path_from_id() + '['+ '"' + prop + '"' + ']'