Skip to content
Snippets Groups Projects
io_export_unreal_psk_psa.py 85.9 KiB
Newer Older
  • Learn to ignore specific revisions
  •                 mesh = obj.data
                    faces = []
                    verts = []
                    smoothings = []
                    uvfaces = []
                    print("creating array build mesh...")
                    mmesh = obj.to_mesh(bpy.context.scene,True,'PREVIEW')
                    uv_layer = mmesh.tessface_uv_textures.active
                    for face in mmesh.tessfaces:
                        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]
                            uvs = []
                            for uv in faceUV.uv:
                                uvs.append((uv[0],uv[1]))
                            uvfaces.append(uvs)
                        print((face.vertices[:]))
                        if len(face.vertices) == 3:
                            faces.extend([(face.vertices[0],face.vertices[1],face.vertices[2],0)])
                        else:
                            faces.extend([(face.vertices[0],face.vertices[1],face.vertices[2],face.vertices[3])])
                    #vertex positions
                    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:
                        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
                    
                    print("creating mesh object...")
                    #me_ob.from_pydata(verts, [], faces)
                    me_ob.vertices.add(len(verts))
                    me_ob.tessfaces.add(len(faces))
                    me_ob.vertices.foreach_set("co", unpack_list(verts)) 
                    me_ob.tessfaces.foreach_set("vertices_raw",unpack_list( faces))
                    me_ob.tessfaces.foreach_set("use_smooth", smoothings)#smooth array from face
                    
                    #check if there is uv faces
                    if len(uvfaces) > 0:
                        uvtex = me_ob.tessface_uv_textures.new(name="retex")
                        for i, face in enumerate(me_ob.tessfaces):
                            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];
                    
                    me_ob.update()#need to update the information to able to see into the secne
                    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.tessfaces:
                        me_ob.faces[face.index].material_index = face.material_index
                    #vertices weight groups
                    for vgroup in vertGroups:
                        group = obmesh.vertex_groups.new(vgroup)
                        for v in vertGroups[vgroup]:
                            group.add([v[0]], v[1], 'ADD')# group.add(array[vertex id],weight,add)
                    bpy.context.scene.objects.link(obmesh)
                    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("Object Name:",obmesh.name)
                    bpy.context.scene.update()
                    bselected = True
                    break
            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("----------------------------------------")
            return{'FINISHED'}
    		
    class OBJECT_OT_UTRebuildArmature(bpy.types.Operator):
        bl_idname = "object.utrebuildarmature"  # XXX, name???
    
    John Phan's avatar
    John Phan committed
        bl_label = "Rebuild" #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"""
        
        def invoke(self, context, event):
            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)
                    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)
                    bpy.ops.object.mode_set(mode='OBJECT')
                    for i in bpy.context.scene.objects: i.select = False #deselect all objects
                    ob_new.select = True
                    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')
                    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')
                    
                    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
                        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))
                    print("Rebuild Armture Finish:",ob_new.name)
                    bpy.context.scene.update()
                    bselected = True
                    break
            if bselected:
                self.report({'INFO'}, "Rebuild Armature Finish!")
            else:
                self.report({'INFO'}, "Didn't Select Armature Object!")
            print("End of Rebuild Armature.")
            print("----------------------------------------")
            return{'FINISHED'}
    
    
    John Phan's avatar
    John Phan committed
    class UDKActionSetListPG(bpy.types.PropertyGroup):
    	bool    = BoolProperty(default=False)
    	string  = StringProperty()
    	actionname  = StringProperty()
    	bmatch    = BoolProperty(default=False,name="Match", options={"HIDDEN"},description = "This check against bone names and action group names matches and override boolean if true.")
    	bexport    = BoolProperty(default=False,name="Export",description = "Check this to export the animation")
    	template_list_controls = StringProperty(default="bmatch:bexport", options={"HIDDEN"})
    
    bpy.utils.register_class(UDKActionSetListPG)
    bpy.types.Scene.udkas_list = CollectionProperty(type=UDKActionSetListPG)
    bpy.types.Scene.udkas_list_idx = IntProperty()
    
    class UDKObjListPG(bpy.types.PropertyGroup):
    	bool    = BoolProperty(default=False)
    	string  = StringProperty()
    	bexport    = BoolProperty(default=False,name="Export", options={"HIDDEN"},description = "This will be ignore when exported")
    	bselect    = BoolProperty(default=False,name="Select", options={"HIDDEN"},description = "This will be ignore when exported")
    	otype  = StringProperty(name="Type",description = "This will be ignore when exported")
    	template_list_controls = StringProperty(default="otype:bselect", options={"HIDDEN"})
    
    bpy.utils.register_class(UDKObjListPG)
    bpy.types.Scene.udkobj_list = CollectionProperty(type=UDKObjListPG)
    bpy.types.Scene.udkobj_list_idx = IntProperty()
    
    class UDKMeshListPG(bpy.types.PropertyGroup):
    	bool    = BoolProperty(default=False)
    	string  = StringProperty()
    	bexport    = BoolProperty(default=False,name="Export", options={"HIDDEN"},description = "This object will be export when true.")
    	bselect    = BoolProperty(default=False,name="Select", options={"HIDDEN"},description = "Make sure you have Mesh is parent to Armature.")
    	otype  = StringProperty(name="Type",description = "This will be ignore when exported")
    	template_list_controls = StringProperty(default="bselect:bexport", options={"HIDDEN"})
    
    bpy.utils.register_class(UDKMeshListPG)
    bpy.types.Scene.udkmesh_list = CollectionProperty(type=UDKMeshListPG)
    bpy.types.Scene.udkmesh_list_idx = IntProperty()
    
    class UDKArmListPG(bpy.types.PropertyGroup):
    	bool    = BoolProperty(default=False)
    	string  = StringProperty()
    	bexport    = BoolProperty(default=False,name="Export", options={"HIDDEN"},description = "This will be ignore when exported")
    	bselect    = BoolProperty(default=False,name="Select", options={"HIDDEN"},description = "This will be ignore when exported")
    	otype  = StringProperty(name="Type",description = "This will be ignore when exported")
    	template_list_controls = StringProperty(default="", options={"HIDDEN"})
    
    bpy.utils.register_class(UDKArmListPG)
    bpy.types.Scene.udkArm_list = CollectionProperty(type=UDKArmListPG)
    bpy.types.Scene.udkArm_list_idx = IntProperty()
    
    class Panel_UDKExport( bpy.types.Panel ):
    
    	bl_label		= "UDK Export"
    	bl_idname		= "OBJECT_PT_udk_tools"
    	#bl_space_type	= "PROPERTIES"
    	#bl_region_type	= "WINDOW"
    	#bl_context		= "object"
    	bl_space_type	= "VIEW_3D"
    	bl_region_type	= "TOOLS"
    	
    	#def draw_header(self, context):
    	#	layout = self.layout
    		#obj = context.object
    		#layout.prop(obj, "select", text="")
    	
    	#@classmethod
    	#def poll(cls, context):
    	#	return context.active_object
    
    	def draw(self, context):
    		layout = self.layout
    		path = get_dst_path()
    
    		object_name = ""
    		#if context.object:
    		#	object_name = context.object.name
    		if context.active_object:
    			object_name = context.active_object.name
    
    John Phan's avatar
    John Phan committed
    		row10 = layout.row()
    		row10.prop(context.scene, "udk_option_smoothing_groups")
    		row10.prop(context.scene, "udk_option_clamp_uv")
    		row10.prop(context.scene, "udk_option_verbose")
    		#layout.prop(context.scene, "udk_option_smoothing_groups")
    		#layout.prop(context.scene, "udk_option_clamp_uv")
    		#layout.prop(context.scene, "udk_option_verbose")
    
    		row = layout.row()
    		row.label(text="Active object: " + object_name)
    
    		#layout.separator()
    
    		layout.prop(context.scene, "udk_option_filename_src")
    		row = layout.row()
    		row.label(text=path)
    
    		#layout.separator()
    
    		layout.prop(context.scene, "udk_option_export")
    		
    
    John Phan's avatar
    John Phan committed
    		row10 = layout.row()
    		
    		row10.prop(context.scene, "udk_option_selectanimations")
    		row10.prop(context.scene, "udk_option_selectobjects")
    		
    		if context.scene.udk_option_selectobjects:
    			layout.operator("object.selobjectpdate")
    			#layout.template_list(context.scene, "udkobj_list", context.scene, "udkobj_list_idx",prop_list="template_list_controls", rows=5)
    			layout.label(text="ARMATURE")
    			layout.template_list(context.scene, "udkArm_list", context.scene, "udkArm_list_idx",prop_list="template_list_controls", rows=3)
    			layout.label(text="MESH")
    			layout.template_list(context.scene, "udkmesh_list", context.scene, "udkmesh_list_idx",prop_list="template_list_controls", rows=5)
    			
    		if context.scene.udk_option_selectanimations:
    			layout.operator("action.setanimupdate")
    			layout.label(text="Action Set(s)")
    			layout.template_list(context.scene, "udkas_list", context.scene, "udkas_list_idx",prop_list="template_list_controls", rows=5)
    		test = layout.separator()
    		#test.operator("object.udk_export")
    		row11 = layout.row()
    		row11.operator("object.udk_export")
    		row11.operator("object.toggle_console")
    		layout.label(text="Armature")
    		row12 = layout.row()
    		row12.operator(OBJECT_OT_UTRebuildArmature.bl_idname)
    		layout.label(text="Mesh")
    		row13 = layout.row()
    		row13.operator(OBJECT_OT_MeshClearWeights.bl_idname)
    		row13.operator(OBJECT_OT_UTSelectedFaceSmooth.bl_idname)
    		row13.operator(OBJECT_OT_UTRebuildMesh.bl_idname)
    		#row13.box(name="Test")
    		
    def udkupdateobjects():
    		my_objlist = bpy.context.scene.udkArm_list
    		objectl = []
    		for objarm in bpy.context.scene.objects:#list and filter only mesh and armature
    			if objarm.type == 'ARMATURE':
    				objectl.append(objarm)
    		for _objd in objectl:#check if list has in udk list
    			bfound_obj = False
    			for _obj in my_objlist:
    				if _obj.name == _objd.name and _obj.otype == _objd.type:
    					_obj.bselect = _objd.select
    					bfound_obj = True
    					break
    			if bfound_obj == False:
    				#print("ADD ARMATURE...")
    				my_item = my_objlist.add()
    				my_item.name = _objd.name
    				my_item.bselect = _objd.select
    				my_item.otype = _objd.type
    		removeobject = []
    		for _udkobj in my_objlist:
    			bfound_objv = False
    			for _objd in bpy.context.scene.objects: #check if there no existing object from sense to remove it
    				if _udkobj.name == _objd.name and _udkobj.otype == _objd.type:
    					bfound_objv = True
    					break
    			if bfound_objv == False:
    				removeobject.append(_udkobj)
    		#print("remove check...")
    		for _item in removeobject: #loop remove object from udk list object
    			count = 0
    			for _obj in my_objlist:
    				if _obj.name == _item.name and _obj.otype == _item.otype:
    					my_objlist.remove(count)
    					break
    				count += 1
    				
    		my_objlist = bpy.context.scene.udkmesh_list
    		objectl = []
    		for objarm in bpy.context.scene.objects:#list and filter only mesh and armature
    			if objarm.type == 'MESH':
    				objectl.append(objarm)
    		for _objd in objectl:#check if list has in udk list
    			bfound_obj = False
    			for _obj in my_objlist:
    				if _obj.name == _objd.name and _obj.otype == _objd.type:
    					_obj.bselect = _objd.select
    					bfound_obj = True
    					break
    			if bfound_obj == False:
    				my_item = my_objlist.add()
    				my_item.name = _objd.name
    				my_item.bselect = _objd.select
    				my_item.otype = _objd.type
    		removeobject = []
    		for _udkobj in my_objlist:
    			bfound_objv = False
    			for _objd in bpy.context.scene.objects: #check if there no existing object from sense to remove it
    				if _udkobj.name == _objd.name and _udkobj.otype == _objd.type:
    					bfound_objv = True
    					break
    			if bfound_objv == False:
    				removeobject.append(_udkobj)
    		#print("remove check...")
    		for _item in removeobject: #loop remove object from udk list object
    			count = 0
    			for _obj in my_objlist:
    				if _obj.name == _item.name and _obj.otype == _item.otype:
    					my_objlist.remove(count)
    					break
    				count += 1
    				
    class OBJECT_OT_UDKObjUpdate(bpy.types.Operator):
    	bl_idname = "object.selobjectpdate"
    	bl_label = "Update Object(s)"
    	__doc__		= "This will update the filter of the mesh and armature."
    	actionname = bpy.props.StringProperty()
     
    	def execute(self, context):
    		udkupdateobjects()
    		return{'FINISHED'}
    
    class OBJECT_OT_ActionSetAnimUpdate(bpy.types.Operator):
    	bl_idname = "action.setanimupdate"
    	bl_label = "Update Action Set(s)"
    	__doc__		= "Select Armture to match the action set groups. All bones keys must be set to match with number of bones."
    	actionname = bpy.props.StringProperty()
     
    	def execute(self, context):
    		my_sett = bpy.context.scene.udkas_list
    		
    		bones = []
    		armature = None
    		armatures = []
    		armatureselected = []
    		for objarm in bpy.context.scene.objects:
    			if objarm.type == 'ARMATURE':
    				#print("ADDED ARMATURE...")
    				armatures.append(objarm)
    				if objarm.select == True:
    					armatureselected.append(objarm)
    				
    		if len(armatureselected) == len(armatures) == 1:
    			armature = armatures[0]
    		if len(armatures) == 1:
    			armature = armatures[0]
    		if len(armatureselected) == 1:		
    			armature = armatureselected[0]
    			
    		if armature != None:
    			for bone in armature.pose.bones:
    				bones.append(bone.name)
    
    		for action in bpy.data.actions:#action list
    			bfound = False
    			count = 0
    			for actionbone in action.groups:
    				#print("Pose bone name: ",actionbone.name)
    				for b in bones:
    					if b == actionbone.name:
    						count += 1
    						#print(b," : ",actionbone.name)
    						break
    			for actionlist in my_sett:
    				if action.name == actionlist.name:
    					bactionfound = True
    					if len(bones) == len(action.groups) == count:
    						actionlist.bmatch = True
    					else:
    						actionlist.bmatch = False
    					bfound = True
    					break
    			if bfound != True:
    				my_item = my_sett.add()
    				#print(dir(my_item.bmatch))
    				my_item.name = action.name
    				my_item.template_list_controls = "bmatch:bexport"
    				if len(bones) == len(action.groups) == count:
    					my_item.bmatch = True
    				else:
    					my_item.bmatch = False
    		removeactions = []	
    		#check action list and data actions
    		for actionlist in bpy.context.scene.udkas_list:
    			bfind = False
    			notfound = 0
    			for act in bpy.data.actions:
    				if actionlist.name == act.name:
    					bfind = True
    				else:
    					notfound += 1
    			#print("ACT NAME:",actionlist.name," COUNT",notfound)
    			if notfound == len(bpy.data.actions):
    				#print("remove :",actionlist.name)
    				removeactions.append(actionlist.name)	
    		#print("Not in the action data list:",len(removeactions))
    		#remove list or chnages in the name the template list
    		for actname in removeactions:
    			actioncount = 0
    			for actionlist in my_sett:
    				#print("action name:",actionlist.name)
    				if actionlist.name == actname:
    					my_sett.remove(actioncount);
    					break
    				actioncount += 1
    		return{'FINISHED'}		
    
    		
    class ExportUDKAnimData(bpy.types.Operator):
    
        """Export Skeleton Mesh / Animation Data file(s)"""
    
        bl_idname = "export_anim.udk" # this is important since its how bpy.ops.export.udk_anim_data is constructed
        bl_label = "Export PSK/PSA"
        __doc__ = """One mesh and one armature else select one mesh or armature to be exported"""
    
        # List of operator properties, the attributes will be assigned
        # to the class instance from the operator settings before calling.
    
        filepath = StringProperty(
                subtype='FILE_PATH',
                )
        filter_glob = StringProperty(
                default="*.psk;*.psa",
                options={'HIDDEN'},
                )
        udk_option_smoothing_groups = bpy.types.Scene.udk_option_smoothing_groups
        udk_option_clamp_uv = bpy.types.Scene.udk_option_clamp_uv
        udk_option_verbose = bpy.types.Scene.udk_option_verbose
        udk_option_filename_src = bpy.types.Scene.udk_option_filename_src
        udk_option_export = bpy.types.Scene.udk_option_export
    
        @classmethod
        def poll(cls, context):
            return context.active_object != None
    
        def execute(self, context):
            scene = bpy.context.scene
            scene.udk_option_export_psk	= (scene.udk_option_export == '0' or scene.udk_option_export == '2')
            scene.udk_option_export_psa	= (scene.udk_option_export == '1' or scene.udk_option_export == '2')
    		
            filepath = get_dst_path()
    		
    		# cache settings
            restore_frame = scene.frame_current
    		
            message = "Finish Export!"
            try:
                export(filepath)
    
            except Error as err:
                print(err.message)
                message = err.message
    		
    		# restore settings
            scene.frame_set(restore_frame)
            
            self.report({'WARNING', 'INFO'}, message)
            return {'FINISHED'}
            
        def invoke(self, context, event):
            wm = context.window_manager
            wm.fileselect_add(self)
    
    John Phan's avatar
    John Phan committed
            return {'RUNNING_MODAL'}
    		
    
    def menu_func(self, context):
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        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
    
    #===========================================================================
    # Entry
    #===========================================================================
    
    	#print("REGISTER")
    	bpy.utils.register_module(__name__)
    	bpy.types.INFO_MT_file_export.append(menu_func)
    
    	#print("UNREGISTER")
    	bpy.utils.unregister_module(__name__)
    	bpy.types.INFO_MT_file_export.remove(menu_func)
    
    John Phan's avatar
    John Phan committed
    	print(header("UDK Export PSK/PSA 2.6", 'CENTER'))
    
    	register()
    	
    #loader
    #filename = "D:/Projects/BlenderScripts/io_export_udk_psa_psk_alpha.py"
    
    Guillermo S. Romero's avatar
    Guillermo S. Romero committed
    #exec(compile(open(filename).read(), filename, 'exec'))