Skip to content
Snippets Groups Projects
io_export_unreal_psk_psa.py 101 KiB
Newer Older
            bpy.context.scene.unrealignoreactionmatchcount = True
        else:
            bpy.context.scene.unrealignoreactionmatchcount = False
        if(self.limituvbool):
            bpy.types.Scene.limituv = True
        else:
            bpy.types.Scene.limituv = False
Luca Bonavita's avatar
Luca Bonavita committed
        write_data(self.filepath, context)
        
        self.report({'WARNING', 'INFO'}, exportmessage)
        return {'FINISHED'}
        
    def invoke(self, context, event):
        wm = context.window_manager
        wm.fileselect_add(self)
        return {'RUNNING_MODAL'}
class VIEW3D_PT_unrealtools_objectmode(bpy.types.Panel):
Luca Bonavita's avatar
Luca Bonavita committed
    bl_space_type = "VIEW_3D"
    bl_region_type = "TOOLS"
    bl_label = "Unreal Tools"
    
    @classmethod
    def poll(cls, context):
        return context.active_object

    def draw(self, context):
        layout = self.layout
        rd = context.scene
        layout.prop(rd, "unrealexport_settings",expand=True)
        layout.prop(rd, "UEActionSetSettings")
        layout.prop(rd, "unrealignoreactionmatchcount")
        
Luca Bonavita's avatar
Luca Bonavita committed
        #FPS #it use the real data from your scene
        layout.prop(rd.render, "fps")
        layout.prop(rd, "limituv")
        layout.operator(OBJECT_OT_UnrealExport.bl_idname)
        
John Phan's avatar
John Phan committed
        layout.prop(rd, "unrealdisplayactionsets")
        
        ArmatureSelect = None
        for obj in bpy.data.objects:
            if obj.type == 'ARMATURE' and obj.select == True:
                #print("Armature Name:",obj.name)
                ArmatureSelect = obj
                break
        #display armature actions list
        if ArmatureSelect != None and rd.unrealdisplayactionsets == True:
            layout.label(("Selected: "+ArmatureSelect.name))
            row = layout.row()
            row.template_list(obj, "myCollectionUEA", obj, "myCollectionUEA_index")                        # This show list for the collection
            col = row.column(align=True)
            col.operator("collection.add_remove_ueactions", icon="ZOOMIN", text="").set = "add"            # This show a plus sign button
            col.operator("collection.add_remove_ueactions", icon="ZOOMOUT", text="").set = "remove"        # This show a minus sign button        
            col.operator("collection.add_remove_ueactions", icon="FILE_REFRESH", text="").set = "refresh"  # This show a refresh sign button
            
            ##change name of Entry:
            if obj.myCollectionUEA:
                entry = obj.myCollectionUEA[obj.myCollectionUEA_index]
                layout.prop(entry, "name")
                layout.prop(entry, "mybool")
        layout.operator(OBJECT_OT_UTSelectedFaceSmooth.bl_idname)        
        layout.operator(OBJECT_OT_UTRebuildArmature.bl_idname)
        layout.operator(OBJECT_OT_UTRebuildMesh.bl_idname)
        layout.operator(OBJECT_OT_ToggleConsle.bl_idname)
        layout.operator(OBJECT_OT_DeleteActionSet.bl_idname)
        layout.operator(OBJECT_OT_MeshClearWeights.bl_idname)
Luca Bonavita's avatar
Luca Bonavita committed
        
class OBJECT_OT_UnrealExport(bpy.types.Operator):
Luca Bonavita's avatar
Luca Bonavita committed
    global exportmessage
    bl_idname = "export_mesh.udk"  # XXX, name???
Luca Bonavita's avatar
Luca Bonavita committed
    bl_label = "Unreal Export"
    __doc__ = """Select export setting for .psk/.psa or both."""
Luca Bonavita's avatar
Luca Bonavita committed
    
    def invoke(self, context, event):
        print("Init Export Script:")
        if(int(bpy.context.scene.unrealexport_settings) == 0):
            bpy.context.scene.unrealexportpsk = True
            bpy.context.scene.unrealexportpsa = False
            print("Exporting PSK...")
        if(int(bpy.context.scene.unrealexport_settings) == 1):
            bpy.context.scene.unrealexportpsk = False
            bpy.context.scene.unrealexportpsa = True
            print("Exporting PSA...")
        if(int(bpy.context.scene.unrealexport_settings) == 2):
            bpy.context.scene.unrealexportpsk = True
            bpy.context.scene.unrealexportpsa = True
            print("Exporting ALL...")

        default_path = os.path.splitext(bpy.data.filepath)[0] + ".psk"
        fs_callback(default_path, bpy.context)        
Luca Bonavita's avatar
Luca Bonavita committed
        #self.report({'WARNING', 'INFO'}, exportmessage)
        self.report({'INFO'}, exportmessage)
        return{'FINISHED'}   

class OBJECT_OT_ToggleConsle(bpy.types.Operator):
    global exportmessage
    bl_idname = "object.toggleconsle"  # XXX, name???
    bl_label = "Toggle Console"
    __doc__ = "Show or Hide Console."
    
    def invoke(self, context, event):
        bpy.ops.wm.console_toggle()
        return{'FINISHED'} 

class OBJECT_OT_UTSelectedFaceSmooth(bpy.types.Operator):
    bl_idname = "object.utselectfacesmooth"  # XXX, name???
    bl_label = "Select Smooth faces"
    __doc__ = """It will only select smooth faces that is select mesh."""
    
    def invoke(self, context, event):
        print("----------------------------------------")
        print("Init Select Face(s):")
        bselected = False
        for obj in bpy.data.objects:
            if obj.type == 'MESH' and obj.select == True:
                bpy.ops.object.mode_set(mode='OBJECT')#it need to go into object mode to able to select the faces
                for i in bpy.context.scene.objects: i.select = False #deselect all objects
                obj.select = True #set current object select
                bpy.context.scene.objects.active = obj #set active object
                for face in obj.data.faces:
                    if face.use_smooth == True:
                        face.select = True
                        face.select = False
                    #print("selected:",face.select)
                    #print(("smooth:",face.use_smooth))
                bpy.ops.object.mode_set(mode='EDIT')
                print("Select Smooth Count(s):",smoothcount," Flat Count(s):",flatcount)
                bselected = True
        if bselected:
            print("Selected Face(s) Exectue!")
            self.report({'INFO'}, "Selected Face(s) Exectue!")
        else:
            print("Didn't select Mesh Object!")
            self.report({'INFO'}, "Didn't Select Mesh Object!")
        print("----------------------------------------")        
        return{'FINISHED'}
class OBJECT_OT_DeleteActionSet(bpy.types.Operator):
    bl_idname = "object.deleteactionset"  # XXX, name???
    bl_label = "Delete Action Set"
John Phan's avatar
John Phan committed
    __doc__ = """It will remove the first top of the index of the action list. Reload file to remove it. It used for unable to delete action set. """
    
    def invoke(self, context, event):
        if len(bpy.data.actions) > 0:
John Phan's avatar
John Phan committed
            for action in bpy.data.actions:
                print("Action:",action.name)
                action.user_clear()
                break
            #bpy.data.actions.remove(act)
        print("finish")
        return{'FINISHED'}
			
class OBJECT_OT_MeshClearWeights(bpy.types.Operator):
    bl_idname = "object.meshclearweights"  # XXX, name???
    bl_label = "Mesh Clear Weights"
    __doc__ = """Clear selected mesh vertex group weights for the bones. Be sure you unparent the armature."""
    
    def invoke(self, context, event):
        for obj in bpy.data.objects:
            if obj.type == 'MESH' and obj.select == True:
                for vg in obj.vertex_groups:
                    obj.vertex_groups.remove(vg)
                break			
        return{'FINISHED'}
		
class OBJECT_OT_UTRebuildArmature(bpy.types.Operator):
    bl_idname = "object.utrebuildarmature"  # XXX, name???
    bl_label = "Rebuild Armature"
    __doc__ = """If mesh is deform when importing to unreal engine try this. It rebuild the bones one at the time by select one armature object scrape to raw setup build. Note the scale will be 1:1 for object mode. To keep from deforming."""
        print("----------------------------------------")
        print("Init Rebuild Armature...")
        bselected = False
        for obj in bpy.data.objects:
            if obj.type == 'ARMATURE' and obj.select == True:
                currentbone = [] #select armature for roll copy
                print("Armature Name:",obj.name)
John Phan's avatar
John Phan committed
                objectname = "ArmatureDataPSK"
                meshname ="ArmatureObjectPSK"
                armdata = bpy.data.armatures.new(objectname)
                ob_new = bpy.data.objects.new(meshname, armdata)
                bpy.context.scene.objects.link(ob_new)
John Phan's avatar
John Phan committed
                bpy.ops.object.mode_set(mode='OBJECT')
                for i in bpy.context.scene.objects: i.select = False #deselect all objects
                ob_new.select = True
John Phan's avatar
John Phan committed
                bpy.context.scene.objects.active = obj
                
                bpy.ops.object.mode_set(mode='EDIT')
                for bone in obj.data.edit_bones:
                    if bone.parent != None:
                        currentbone.append([bone.name,bone.roll])
                    else:
                        currentbone.append([bone.name,bone.roll])
                bpy.ops.object.mode_set(mode='OBJECT')
John Phan's avatar
John Phan committed
                for i in bpy.context.scene.objects: i.select = False #deselect all objects
                bpy.context.scene.objects.active = ob_new
                bpy.ops.object.mode_set(mode='EDIT')
John Phan's avatar
John Phan committed
                
                for bone in obj.data.bones:
                    bpy.ops.object.mode_set(mode='EDIT')
                    newbone = ob_new.data.edit_bones.new(bone.name)
                    newbone.head = bone.head_local
                    newbone.tail = bone.tail_local
John Phan's avatar
John Phan committed
                    for bonelist in currentbone:
                        if bone.name == bonelist[0]:
                            newbone.roll = bonelist[1]
                            break
                    if bone.parent != None:
                        parentbone = ob_new.data.edit_bones[bone.parent.name]
                        newbone.parent = parentbone
                print("Bone Count:",len(obj.data.bones))
                print("Hold Bone Count",len(currentbone))
                print("New Bone Count",len(ob_new.data.edit_bones))
John Phan's avatar
John Phan committed
                print("Rebuild Armture Finish:",ob_new.name)
        if bselected:
            self.report({'INFO'}, "Rebuild Armature Finish!")
        else:
            self.report({'INFO'}, "Didn't Select Armature Object!")
        print("End of Rebuild Armature.")
        print("----------------------------------------")
John Phan's avatar
John Phan committed
		
# rounded the vert locations to save a bit of blurb.. change the round value or remove for accuracy i suppose
def rounded_tuple(tup):
    return tuple(round(value,4) for value in tup)
	
def unpack_list(list_of_tuples):
    l = []
    for t in list_of_tuples:
        l.extend(t)
    return l
	
class OBJECT_OT_UTRebuildMesh(bpy.types.Operator):
    bl_idname = "object.utrebuildmesh"  # XXX, name???
    bl_label = "Rebuild Mesh"
    __doc__ = """It rebuild the mesh from scrape from the selected mesh object. Note the scale will be 1:1 for object mode. To keep from deforming."""
        print("----------------------------------------")
        print("Init Mesh Bebuild...")
        bselected = False
        for obj in bpy.data.objects:
            if obj.type == 'MESH' and obj.select == True:
                for i in bpy.context.scene.objects: i.select = False #deselect all objects
                obj.select = True
                bpy.context.scene.objects.active = obj
                bpy.ops.object.mode_set(mode='OBJECT')
                me_ob = bpy.data.meshes.new(("Re_"+obj.name))
                #print(dir(mesh))
                print("creating array build mesh...")
                uv_layer = mesh.uv_textures.active
                for face in mesh.faces:
                    smoothings.append(face.use_smooth)#smooth or flat in boolean
                    if uv_layer != None:#check if there texture data exist
                        faceUV = uv_layer.data[face.index]
                        #print(len(faceUV.uv))
                        uvs = []
                        for uv in faceUV.uv:
                            #vert = mesh.vertices[videx]
                            #print("UV:",uv[0],":",uv[1])
                            uvs.append((uv[0],uv[1]))
                        #print(uvs)
                        uvfaces.append(uvs)
Campbell Barton's avatar
Campbell Barton committed
                    faces.append(face.vertices[:])           
                for vertex in mesh.vertices:
                    verts.append(vertex.co.to_tuple())				
                #vertices weight groups into array
                vertGroups = {} #array in strings
                for vgroup in obj.vertex_groups:
                    #print(dir(vgroup))
                    #print("name:",(vgroup.name),"index:",vgroup.index)
                    #vertex in index and weight
                    vlist = []
                    for v in mesh.vertices:
                        for vg in v.groups:
                            if vg.group == vgroup.index:
                                vlist.append((v.index,vg.weight))
                                #print((v.index,vg.weight))
                    vertGroups[vgroup.name] = vlist					
                '''
				#Fail for this method
				#can't covert the tri face plogyon
                for face in mesh.faces:
                    x = [f for f in face.vertices]
                    faces.extend(x)
                    smoothings.append(face.use_smooth)
                for vertex in mesh.vertices:
                    verts.append(vertex.co.to_tuple())
                me_ob.vertices.add(len(verts))
                me_ob.faces.add(len(faces)//4)
                me_ob.vertices.foreach_set("co", unpack_list(verts))
                me_ob.faces.foreach_set("vertices_raw", faces)
                me_ob.faces.foreach_set("use_smooth", smoothings)
                '''
                #test dummy mesh
                #verts = [(-1,1,0),(1,1,0),(1,-1,0),(-1,-1,0),(0,1,1),(0,-1,1)]
                #faces = [(0,1,2,3),(1,2,5,4),(0,3,5,4),(0,1,4),(2,3,5)]
                #for f in faces:
                    #print("face",f)
                #for v in verts:
                    #print("vertex",v)
                #me_ob = bpy.data.objects.new("ReBuildMesh",me_ob)
                print("creating mesh object...")
                me_ob.from_pydata(verts, [], faces)
                me_ob.faces.foreach_set("use_smooth", smoothings)#smooth array from face
                #check if there is uv faces
                if len(uvfaces) > 0:
                    uvtex = me_ob.uv_textures.new(name="retex")
                    for i, face in enumerate(me_ob.faces):
                        blender_tface = uvtex.data[i] #face
                        mfaceuv = uvfaces[i]
                        if len(mfaceuv) == 3:
                            blender_tface.uv1 = mfaceuv[0];
                            blender_tface.uv2 = mfaceuv[1];
                            blender_tface.uv3 = mfaceuv[2];
                        if len(mfaceuv) == 4:
                            blender_tface.uv1 = mfaceuv[0];
                            blender_tface.uv2 = mfaceuv[1];
                            blender_tface.uv3 = mfaceuv[2];
                            blender_tface.uv4 = mfaceuv[3];
                
                obmesh = bpy.data.objects.new(("Re_"+obj.name),me_ob)
                bpy.context.scene.update()
                #Build tmp materials
                materialname = "ReMaterial"
                for matcount in mesh.materials:
                    matdata = bpy.data.materials.new(materialname)
                    me_ob.materials.append(matdata)
                #assign face to material id
                for face in mesh.faces:
                    #print(dir(face))
                    me_ob.faces[face.index].material_index = face.material_index
                #vertices weight groups
                for vgroup in vertGroups:
                    #print("vgroup",vgroup)#name of group
                    #print(dir(vgroup))
                    #print(vertGroups[vgroup])
                    group = obmesh.vertex_groups.new(vgroup)
                    #print("group index",group.index)
                    for v in vertGroups[vgroup]:
                        group.add([v[0]], v[1], 'ADD')# group.add(array[vertex id],weight,add)
                        #print("[vertex id, weight]",v) #array (0,0)
                        #print("[vertex id, weight]",v[0],":",v[1]) #array (0,0)
                print("Mesh Material Count:",len(me_ob.materials))
                matcount = 0
                print("MATERIAL ID OREDER:")
                for mat in me_ob.materials:
                    print("-Material:",mat.name,"INDEX:",matcount)
                    matcount += 1
                print("")
                print("Object Name:",obmesh.name)
                bpy.context.scene.update()
                #bpy.ops.wm.console_toggle()
        if bselected:
            self.report({'INFO'}, "Rebuild Mesh Finish!")
            print("Finish Mesh Build...")
        else:
            self.report({'INFO'}, "Didn't Select Mesh Object!")
            print("Didn't Select Mesh Object!")
        print("----------------------------------------")
        
def menu_func(self, context):
Luca Bonavita's avatar
Luca Bonavita committed
    #bpy.context.scene.unrealexportpsk = True
    #bpy.context.scene.unrealexportpsa = True
    default_path = os.path.splitext(bpy.data.filepath)[0] + ".psk"
    self.layout.operator(ExportUDKAnimData.bl_idname, text="Skeleton Mesh / Animation Data (.psk/.psa)").filepath = default_path
Luca Bonavita's avatar
Luca Bonavita committed
    bpy.types.INFO_MT_file_export.append(menu_func)
Luca Bonavita's avatar
Luca Bonavita committed
    bpy.types.INFO_MT_file_export.remove(menu_func)
Luca Bonavita's avatar
Luca Bonavita committed
    register()