Skip to content

资产管理

数据流向

  1. 扫描 Assets/
  2. 使用 AssetDatabase 发现资产、维护 GUID / meta
  3. 通过 ImporterRegistry 把硬盘上的资产转化成 Runtime 可使用的资源
  4. 在 AssetManager 中管理 CPU 资产、异步加载、热重载
  5. 在 ResourceManager 中将 CPU 资产上传为 GPU 资源

AssetDatabase

目的是不需要完整的把资源加载到内存中,就可以通过记录信息,在 Runtime 的时候查询资产类型、路径和元数据

此处维护了

C++
struct AssetRecord
{
	AssetGuid guid;
	AssetType type = AssetType::Unknown;
	std::filesystem::path sourcePath;
	std::filesystem::path metaPath;
	std::filesystem::path importedPath;
	std::string importer;
	std::filesystem::file_time_type sourceWriteTime{};
};

主要维护 guidtypepath 三个核心数据。

guid 和 meta

meta 设计

C++
{
  "guid": "122515072b7d31c965a64a1eba21da4e",
  "imported": "Shaders/test.vert",
  "importer": "shader",
  "type": "shader_source",
  "version": 1
}

实际上可以理解为把 Record 的数据做持久化,这样 ——

  • 文件重命名或移动后,只要 .meta 一起移动,GUID 不变。
  • Importer 配置不污染 PNG、GLTF、Shader 等源文件

guid 目前比较简单的使用字符串做,后期可以优化

特别注意的,用于着色器需要编译成.spv,此时如果又为其分配一个 guid,会导致歧义—— 一个逻辑 Shader 却拥有两个身份(runtime 和 源文件,不明确到底指向哪个)

启示 —— 创作数据 != 编辑器内部资产 != 平台运行数据

Importer Registry

把解析功能从 AssetDatabase 中抽离出来(单一职责这块),做的是类似GLTFShader等磁盘上的文件的具体解析

目前实现了

  • PassthroughImporter:源文件本身就是运行时输入(人话,直接复制)
  • ShaderImporter:通过 glslc 将 Shader 源码编译为 SPIR-V。

但这非常好的预留了Strategy,未来如何需要在中间插入什么预处理 / 其他什么格式… 就可以直接在ImporterRegistry 中做注册

AssetManager

还是和之前的设计没什么区别 —— 是总的一个磁盘资产的管理者

  • 初始化 Asset Database 和 Importer
  • 根据路径或 GUID 加载资产
  • 缓存 CPU 数据

这一次加入了异步加载、热重载和显示卸载的功能

顺带提下之前的内容 —— 加载后,AssetManager 使用 SlotMap 保存 CPU 数据(定义在 Core 中的不错的结构,基于 Handle 的查找

值得注意,现在是直接返回

C++
std::shared_future<TextureHandle>
std::shared_future<MeshHandle>
std::shared_future<ShaderHandle>

可以但在关闭时会拒绝新任务,并等待活动任务结束后清理缓存,期待一手未来实现 Job System

每隔一段时间 Tick 一下 热重载方法,检测源文件时间变化,如果变化了则重新执行 Importer,同时原位替换已加载 CPU 数据(保持原 AssetHandle 有效),最后广播 AssetReloadEvent

ResourceManager

ResourceManager 做了一层 CPU Asset 到 GPU Resource 的适配层,

MeshData -> MeshGPU -> Vertex / Index Buffer TextureData -> TextureGPU -> VkImage MaterialData -> MaterialGPU -> Shader / Pipeline / UBO / Bindings

订阅了 AssetReloadEvent ,会在热重载的时候执行 UnloadAll 然后让 GPU 资源在下一次提交渲染指令的时候按需上传

不过这样做比较贵,最好是建立资产依赖图,只失效真正依赖变化资产的 Material、Pipeline、Texture 或 Mesh 之类的什么资源

Released under the MIT License.