# 导出PSK插件地址 - https://github.com/Befzz/blender3d_import_psk_psa/releases - https://github.com/DarklightGames/io_scene_psk_psa/releases # 清空数据 bpy.ops.wm.read_factory_settings(use_empty=True) # PSK ```python import bpy import os import math from io_import_scene_unreal_psa_psk_280 import * pskPath = 'C:\\Users\\BlueRose\\Desktop\\BLUEPROTOCOL\\Game\\Character\\Enemy' for root, subdirs, files in os.walk(pskPath): for dirName in subdirs: print(root + '\\'+ dirName) for modelroot, modeldirs, modelfiles in os.walk(root + '\\'+ dirName +'\\Model'): for f in modelfiles: if f.endswith('.psk'): psk_file = os.path.join(modelroot, f) fbx_file = os.path.splitext(psk_file)[0] + ".fbx" # 清空场景 bpy.ops.object.select_all(action='SELECT') bpy.ops.object.delete() pskimport(psk_file, bReorientBones = False) # 使用SmoothShading for obj in bpy.data.objects: if obj.type=='MESH': obj.data.use_auto_smooth = True obj.data.auto_smooth_angle = math.radians(180) currentmesh = obj.data for setting in currentmesh.polygons: setting.use_smooth = True # 输出骨骼模型 bpy.ops.object.select_all(action='SELECT') bpy.ops.export_scene.fbx(filepath=fbx_file,add_leaf_bones=False) ``` 直接生成fbx版本 ```python import bpy import os import math from io_import_scene_unreal_psa_psk_280 import * pskPath = 'C:\\Users\\BlueRose\\Desktop\\ScarletNexus\\Game\\Character\\wp\\wp0100\\04_Mesh' for modelroot, modeldirs, modelfiles in os.walk(pskPath): for f in modelfiles: if f.endswith('.psk'): psk_file = os.path.join(modelroot, f) fbx_file = os.path.splitext(psk_file)[0] + ".fbx" # 清空场景 bpy.ops.object.select_all(action='SELECT') bpy.ops.object.delete() pskimport(psk_file, bReorientBones = False) # 使用SmoothShading for obj in bpy.data.objects: if obj.type=='MESH': obj.data.use_auto_smooth = True obj.data.auto_smooth_angle = math.radians(180) currentmesh = obj.data for setting in currentmesh.polygons: setting.use_smooth = True # 输出骨骼模型 bpy.ops.object.select_all(action='SELECT') bpy.ops.export_scene.fbx(filepath=fbx_file,add_leaf_bones=False) ``` 使用BetterExport的版本: ```python import bpy import os import math from io_import_scene_unreal_psa_psk_280 import * from better_fbx import * pskPath = 'C:\\Users\\BlueRose\\Desktop\\ScarletNexus\\Game\\Character\\wp\\wp0100\\04_Mesh' for modelroot, modeldirs, modelfiles in os.walk(pskPath): for f in modelfiles: if f.endswith('.psk'): psk_file = os.path.join(modelroot, f) fbx_file = os.path.splitext(psk_file)[0] + ".fbx" # 清空场景 bpy.ops.object.select_all(action='SELECT') bpy.ops.object.delete() pskimport(psk_file, bReorientBones = False) # 使用SmoothShading for obj in bpy.data.objects: if obj.type=='MESH': obj.data.use_auto_smooth = True obj.data.auto_smooth_angle = math.radians(180) currentmesh = obj.data for setting in currentmesh.polygons: setting.use_smooth = True bpy.ops.object.select_all(action='SELECT') bpy.ops.better_export.fbx(filepath=fbx_file,my_fbx_format="binary",use_selection=True,use_visible=True,use_only_root_empty_node=False) ``` # PSA 注意:该脚本因为Blender运行bug,会导致输出的FBX文件越来越大,越来越慢。一次转换的量不建议超过50个。建议分几个文件夹,同时开多个Blender一起转换。 ```python import bpy import os import math from io_import_scene_unreal_psa_psk_280 import * pskPath = 'C:\\Users\\BlueRose\\Desktop\\BLUEPROTOCOL\\Game\\Character\\Enemy\\E000_00\\Model\\SK_CH_E000_00.psk' psaDirPath = 'C:\\Users\\BlueRose\\Desktop\\BLUEPROTOCOL\\Game\\Animations\\Enemy\\E000' # 清空场景并且导入模型 for root, subdirs, files in os.walk(psaDirPath): for f in files: if f.endswith('.psa'): bpy.ops.scene.new(type='EMPTY') bpy.ops.object.select_all(action='SELECT') bpy.ops.object.delete() pskimport(pskPath, bReorientBones = False, bImportmesh = False, bImportbone = True) psa_file = os.path.join(root, f) pskDirPath = os.path.dirname(pskPath) fbx_file = os.path.join(pskDirPath,f) fbx_file = os.path.splitext(fbx_file)[0] + ".fbx" print(fbx_file) psaimport(psa_file) bpy.ops.object.select_all(action='SELECT') bpy.ops.export_scene.fbx(filepath=fbx_file,add_leaf_bones=False) bpy.ops.scene.new(type='EMPTY') bpy.ops.object.select_all(action='SELECT') bpy.ops.object.delete() ``` **绯红结系批量转换代码**: ```python import bpy import os import math from io_import_scene_unreal_psa_psk_280 import * from better_fbx import * for action in bpy.data.actions: bpy.data.actions.remove(action) # 'C:\\Users\\BlueRose\\Desktop\\ScarletNexus\\Game\\Character\\ch\\ch0100\\04_Mesh\\SM_ch0100.pskx' # 'C:\\Users\\BlueRose\\Desktop\\ScarletNexus\\Game\\Character\\no\\no0000\\04_Mesh\\SM_no0000_orbit.psk' pskPath = 'C:\\Users\\BlueRose\\Desktop\\ScarletNexus\\Game\\Character\\ch\\ch0100\\04_Mesh\\SM_ch0100.pskx' psaPath = 'C:\\Users\\BlueRose\\Desktop\\ScarletNexus\\Game\\Character\\ch\\ch0100\\25_SpAttack\\Battle\\c04\\AS_ElectricPole_ch0100_c04_ch0100.psa' fbxExportPath = 'C:\\Users\\BlueRose\\Desktop\\ScarletNexus\\Game\\Character\\ch\\ch0100\\25_SpAttack\\Battle\\c04\\' # 清空并且设置为60fps bpy.ops.scene.new(type='EMPTY') bpy.ops.object.select_all(action='SELECT') bpy.ops.object.delete() bpy.context.scene.render.fps = 60 # 导入骨骼以及动画(所有NLA) pskimport(pskPath, bReorientBones = False, bImportmesh = False, bImportbone = True) psaimport(psaPath, bActionsToTrack = True) for obj in bpy.data.objects: print(obj.type) if obj.type=='ARMATURE': currentSkeleton = obj print(currentSkeleton.animation_data.action) for action in bpy.data.actions: # print(action) currentSkeleton.animation_data.action = action bpy.ops.better_export.fbx(filepath= fbxExportPath+ action.name + ".fbx",my_fbx_format="binary",use_selection=False,use_visible=True) # print(currentSkeleton.animation_data.action) # print(bpy.data.objects["SM_ch0100.ao"].animation_data.action) ``` ## 添加平滑组 ```python import bpy import os import math for obj in bpy.data.objects: if obj.type=='MESH': obj.data.use_auto_smooth = True obj.data.auto_smooth_angle = math.radians(180) currentmesh = obj.data for setting in currentmesh.polygons: setting.use_smooth = True ``` ## NLA Action遍历 ```c++ import bpy import os import math for action in bpy.data.actions: print(action) action.name bpy.data.actions["AS_ch0100_016_AL_walk"].name = "AS_ch0100_016_AL_walk" bpy.context.object.animation_data.nla_tracks.active = bpy.context.object.animation_data.nla_tracks[0] # You can set an object's action like: # object.animation_data.action = action print(bpy.data.objects["SM_ch0100.ao"].animation_data.action) ``` ``` 取得当前激活状态的NLA Action ```python for i in bpy.data.objects: for j in i.animation_data.nla_tracks.values(): for k in j.strips.values(): if k.active: print(k) ``` # 其他 获取UModel解包游戏所需的AES Key:https://cs.rin.ru/forum/viewtopic.php?t=100672 ## 蓝色协议 AES Key:0xEA9051DDACE1CCF98A0510F0E370BD986A75C74756E0309E6A578A47AF564255 UE版本为:4.27.2 ## 绯红结系 AES Key:0x48AE8311350417BDC50A440FCD0E98B2FA6BCEAE3EDA8D0E24881F205E6C4540 UE版本为:4.26 ```bash D:\OtherTools\GameAssets\umodel_win32\umodel_scarlet_nexus_v5.exe -path=C:\Game\ScarletNexus -out=C:\Users\BlueRose\Desktop\ScarletNexus -game=ue4.26 -aes=0x48AE8311350417BDC50A440FCD0E98B2FA6BCEAE3EDA8D0E24881F205E6C4540 D:\OtherTools\GameAssets\umodel_win32\umodel_scarlet_nexus_v5.exe -path=D:\SteamLibrary\steamapps\common\ScarletNexus -out=C:\Users\BlueRose\Desktop\ScarletNexus -game=ue4.26 -aes=0x48AE8311350417BDC50A440FCD0E98B2FA6BCEAE3EDA8D0E24881F205E6C4540 D:\OtherTools\GameAssets\umodel_win32\umodel_scarlet_nexus_legacy.exe -path=D:\SteamLibrary\steamapps\common\ScarletNexus -out=C:\Users\BlueRose\Desktop\ScarletNexus -game=ue4.26 -aes=0x48AE8311350417BDC50A440FCD0E98B2FA6BCEAE3EDA8D0E24881F205E6C4540 ``` 需要特殊的UModel进行提取:https://www.gildor.org/smf/index.php/topic,7814.0.html#msg40636 下载地址:https://drive.google.com/file/d/1S_037OmnxY28cQymu8NMwFApsBahFqx6/view 导出动画方法: 1. 选择骨骼模型,右键点击Open(add to locate set),之后按o。 2. 选择动画资产(AS开头),右键点击Open(add to locate set)。 3. 点击Tools - ExportCurrentObject,就可以导出指定的动画。 4. 如果选择多个动画的情况下,在Blender psk/psa插件中可以勾选`All actions to NLA track` 5. 导出动画时,在烘焙动画选项中选择全部动作、NLA片段。所有动画数据都会以NLA Clip的方式存储。 6. 导入UE就可以显示所有的动画数据。 **导出的时候还需要注意:1、FPS是不是设置成30,默认是24。2、导出选项需要去掉添加叶子骨骼节点的选项** ### 资产笔记 角色模型分为Ch与Co前缀,Ch是Ch/Chxxx中的模型,Co是00_Common/Coxxx中的模型。 - Effect:游戏特效,里面的一些贴图与Mesh可以拿来做刀光。 - Character - 00_Common:主角插在身上的Link线以及其他长在怪物身上的电灯泡与花。 - ch:各种角色相关资产。 - Animation:各种动画。 - 400_DM:角色受到攻击。 - - SAS:男主的SAS技能。 - BrainCrash:击破处决动画。 - DriveMode:驱动模式。(随机触发的爆发状态) - BrainField:一些Qte 伤害动画。(主要是一些Boss的) - GameOver:游戏失败的角色动画。 - SPAttack:游戏中的SP攻击,也就是Qte念力攻击。 - Intercept:拦截游戏中另一个主角的SPAttack。 - wp:各个角色的武器 - wp0100:男主武器。 - wp0200:女主武器。 - wp0300:花火武器。棍子 - wp0400:拳套。 - wp0800:警棍。 - wp0900:手弩。 - wp1000:电锯。 - wp1100:手里剑。 - em:怪物模型。 - BrainCrash:里面主要是怪物处决的Qte动画。AS_BC_emxxxx_前缀后面代表对应的角色模型。 - np:NPC模型。 长得像石头的 - /Game/Character/00_Common/04_Mesh/SM_CableEnergyMesh.uasset - /Game/Character/no/no0000/04_Mesh/SM_no0000_orbit.uasset - /Game/Character/00_Common/co0300/04_Mesh/SM_co0300.uasset - /Game/DLC/Ver0102/Environment/Location/LC70/SM_pr_LC70_Block.uasset # UModel 快捷键: - h:显示所有命令。 - 空格:播放动画。 - s:显示骨骼。 - 【】:选择下/上一个动画。 - 《》:选择下/上一帧。 ## CMD启动 ```bash D:\OtherTools\GameAssets\umodel_win32\umodel_scarlet_nexus_v5.exe -path=C:\Game\ScarletNexus -out=C:\Users\BlueRose\Desktop\ScarletNexus -game=ue4.26 -aes=0x48AE8311350417BDC50A440FCD0E98B2FA6BCEAE3EDA8D0E24881F205E6C4540 ``` 显示所有命令选项: ```bash D:\OtherTools\GameAssets\umodel_win32\umodel_scarlet_nexus_v5.exe -help ``` ```bash Usage: umodel [command] [options] [ []] umodel [command] [options] umodel @ name of package to load - this could be a file name with or without extension, or wildcard name of object to load class of object to load (useful, when trying to load object with ambiguous name) path to the game (see -path option) Commands: -view (default) visualize object; when no specified will load whole package -list list contents of package -export export specified object or whole package -save save specified packages Help information: -help display this help page -version display umodel version information -taglist list of tags to override game autodetection (for -game=nnn option) -gamelist list of supported games Developer commands: -log=file write log to the specified file -dump dump object information to console -pkginfo load package and display its information -testexport perform fake export Options: -path=PATH path to game installation directory; if not specified, program will search for packages in current directory -game=tag override game autodetection (see -taglist for variants) -pkgver=nnn override package version (advanced option!) -pkg=package load extra package (in addition to ) -obj=object specify object(s) to load -gui force startup UI to appear -aes=key provide AES decryption key for encrypted pak files, key is ASCII or hex string (hex format is 0xAABBCCDD), multiple options could be provided for multi-key games -aes=@file.txt read AES decryption key(s) from a text file Compatibility options: -nomesh disable loading of SkeletalMesh classes in a case of unsupported data format -noanim disable loading of MeshAnimation classes -nostat disable loading of StaticMesh class -novert disable loading of VertMesh class -notex disable loading of Material classes -nomorph disable loading of MorphTarget class -nolightmap disable loading of Lightmap textures -sounds allow export of sounds -3rdparty allow 3rd party asset export (ScaleForm, FaceFX) -lzo|lzx|zlib force compression method for UE3 fully-compressed packages Platform selection: -ps3 Playstation 3 -ps4 Playstation 4 -nsw Nintendo Switch -ios iOS (iPhone/iPad) -android Android Viewer options: -meshes view meshes only -materials view materials only (excluding textures) -anim= specify AnimSet to automatically attach to mesh Export options: -out=PATH export everything into PATH instead of the current directory -all used with -dump, will dump all objects instead of specified one -uncook use original package name as a base export directory (UE3) -groups use group names instead of class names for directories (UE1-3) -uc create unreal script when possible -psk use ActorX format for meshes (default) -md5 use md5mesh/md5anim format for skeletal mesh -gltf use glTF 2.0 format for mesh -lods export all available mesh LOD levels -dds export textures in DDS format whenever possible -png export textures in PNG format instead of TGA -notgacomp disable TGA compression -nooverwrite prevent existing files from being overwritten (better performance) ``` ## 取得资产路径 1. 批量选择动画资产 2. 右键点击Copy package path /Game/Character/ch/ch0200/05_Animation/AS_ch0200_906_FC_smile_m.uasset /Game/Character/ch/ch0200/05_Animation/AS_ch0200_901_FC_default_m.uasset /Game/Character/ch/ch0200/05_Animation/AS_ch0200_906_FC_smile_m.uasset /Game/Character/ch/ch0200/05_Animation/AS_ch0200_911_FC_angry_m.uasset /Game/Character/ch/ch0200/05_Animation/AS_ch0200_916_FC_sad_m.uasset /Game/Character/ch/ch0200/05_Animation/AS_ch0200_921_FC_surprise_m.uasset /Game/Character/ch/ch0200/05_Animation/AS_ch0200_926_FC_fear_m.uasset /Game/Character/ch/ch0200/05_Animation/AS_ch0200_931_FC_aversion_m.uasset /Game/Character/ch/ch0200/05_Animation/AS_ch0200_936_FC_damage_m.uasset /Game/Character/ch/ch0200/05_Animation/AS_ch0200_937_FC_dead.uasset /Game/Character/ch/ch0200/05_Animation/AS_ch0200_941_FC_serious_m.uasset /Game/Character/ch/ch0200/05_Animation/AS_ch0200_946_FC_blushing_m.uasset /Game/Character/ch/ch0200/05_Animation/AS_ch0200_951_FC_ex01_m.uasset /Game/Character/ch/ch0200/05_Animation/AS_ch0200_AL_pose001_ST.uasset /Game/Character/ch/ch0200/05_Animation/AS_ch0200_AL_pose002_ST.uasset /Game/Character/ch/ch0200/05_Animation/AS_ch0200_AL_pose003_ST.uasset /Game/Character/ch/ch0200/05_Animation/AS_ch0200_AL_pose004_ST.uasset /Game/Character/ch/ch0200/05_Animation/AS_ch0200_AL_pose005_ST.uasset /Game/Character/ch/ch0200/05_Animation/AS_ch0200_AL_pose006_ST.uasset /Game/Character/ch/ch0200/05_Animation/AS_ch0200_AL_pose007_ST.uasset # 解决Blender导出问题的根骨骼问题 使用Blender的**Better Fbx Importer & Exporter** addon就可以解决问题。