UE开发

UE的LoadObject接口底层机制

UE的LoadObject接口底层机制详解

2026-08-21

10 min

分类

UE开发

最近在看 UE 的 Pak 加载流程时,有一个地方比较容易绕进去:LoadObject 传入的明明只是 /Game/... 这样的对象路径,最后却能从已经挂载的 Pak 中把模型加载出来。要理解这件事,关键是先把 UObject、UPackage、Cook 后的资源文件和 .pak 区分开。

UE LoadObject 底层机制全流程图.png
UE LoadObject 底层机制全流程图.png

UE 创建资产时,通常会先创建一个 UPackage,再把具体的 UObject 创建到这个 Package 下。例如:

UPackage* Package =
    CreatePackage(TEXT("/Game/BIM/SM_3D"));

UStaticMesh* Mesh =
    NewObject<UStaticMesh>(
        Package,
        TEXT("SM_3D")
    );

这样生成的 StaticMesh 对象路径就是:

/Game/BIM/SM_3D.SM_3D

前半部分 /Game/BIM/SM_3D 是 PackageName,后面的 SM_3D 是 ObjectName。这里的 UPackage 只是 UE 在逻辑上组织 UObject 的单位,并不是最后生成的 .pak 文件。

资产保存并经过 Cook 后,会生成运行时真正需要读取的 Package 文件,例如:

SM_3D.uasset
SM_3D.uexp
SM_3D.ubulk

之后 UnrealPak 再把这些 Cook 后的文件收集到 .pak 中,同时可以做压缩、加密以及建立文件索引。因此整个打包过程可以简单看成:

UObject
→ UPackage
→ Cook
→ uasset / uexp / ubulk
→ UnrealPak
→ xxx.pak

运行时调用:

LoadObject<UStaticMesh>(
    nullptr,
    TEXT("/Game/BIM/SM_3D.SM_3D")
);

UE 首先会解析对象路径,得到:

PackageName = /Game/BIM/SM_3D
ObjectName  = SM_3D

/Game 是 UE 的逻辑 Package 根路径,通常对应当前项目的 Content 目录,所以 /Game/BIM/SM_3D 最终会对应到类似:

<Project>/Content/BIM/SM_3D.uasset

到这里其实还没有涉及 Pak。Package Loader 只是知道自己需要读取 BIM/SM_3D 这个 Package,接下来才会把请求交给底层文件系统。

Pak 的 MountPoint 就是在这里起作用的。假设 BIM.pak 中保存了:

BIM/SM_3D.uasset
BIM/SM_3D.uexp

运行时将这个 Pak 挂载到:

<Project>/Content/

那么从 UE 文件系统的角度看,就相当于出现了:

<Project>/Content/BIM/SM_3D.uasset
<Project>/Content/BIM/SM_3D.uexp

这些文件并没有真的解压到磁盘目录中,数据仍然保存在 BIM.pak 里。MountPoint 只是建立了一层虚拟路径关系:

MountPoint + Pak 内相对路径
=
UE 文件系统看到的路径

因此当 Package Loader 请求读取:

<Project>/Content/BIM/SM_3D.uasset

时,请求会进入 IPlatformFile 文件系统。如果当前使用的是 Pak 文件系统,就会经过 FPakPlatformFile。它会检查已经挂载的 Pak,发现这个请求路径落在 BIM.pak 的 MountPoint 下,于是转换成 Pak 内对应的相对路径:

BIM/SM_3D.uasset

随后通过 Pak Index 找到这个文件在 .pak 中对应的 Offset、Size 以及压缩块信息,再直接从 Pak 中读取数据。如果文件经过压缩,就先解压,然后把最终字节交回 Package Loader,最后反序列化成 UStaticMesh。

整个过程可以概括成:

LoadObject("/Game/BIM/SM_3D.SM_3D")
        ↓
解析 PackageName
        ↓
/Game/BIM/SM_3D
        ↓
映射为 Package 文件路径
        ↓
Content/BIM/SM_3D.uasset
        ↓
IPlatformFile 文件读取
        ↓
FPakPlatformFile
        ↓
根据 MountPoint 匹配已挂载 Pak
        ↓
Pak Index 查找文件
        ↓
从 Pak 中读取数据
        ↓
Package Loader 反序列化
        ↓
UStaticMesh

这里最容易混淆的是 UPackage 和 .pak。UPackage 是 UObject 的逻辑组织单位,而 .pak 只是 Cook 后文件的归档容器。另外,LoadObject 本身并不知道资源最终来自 Pak,它只负责根据对象路径找到对应 Package;真正决定文件是从磁盘读取还是从 Pak 读取的是底层文件系统。

所以从整体上看,UE 这一套加载机制实际上就是:

对象路径
→ Package 路径
→ 文件路径
→ Pak 虚拟文件系统
→ 二进制数据
→ UObject

也正因为这一层做了隔离,Pak 挂载完成之后,上层仍然可以继续使用普通的 LoadObject,不需要专门提供一个 LoadObjectFromPak。

评论 (1)

参与讨论,分享你的看法。评论审核通过后展示。

112026-08-22 15:27

🐂