feat: 模型异步加载——assimp 解析移后台线程(SunTemple 3s 卡顿消除)

Model 拆两段式:ParseFromDisk(static 纯 CPU,assimp 解析 → 几何 +
材质引用,worker 可调)/ FromParsed(GPU 构建:纹理上传 / mesh 缓冲 /
材质描述符,主线程),同步路径等价两段串行。第二个异步任务类型落地,
线程收割骨架抽成 Core/AsyncTask<T>(thread + atomic + Take,覆盖式
Run;pending 接力语义留调用方)。

实测(SunTemple 1056 mesh):解析 2.5s 全程在 worker,主线程持续
渲染;GPU 构建 0.56s。assets 层经 IAssetUploader/AssetManager 重载
传预解析产物(路径缓存去重,路径已缓存则产物丢弃)。

已知边界:纹理解码(backpack 4k PNG ~1s)仍在 GPU 段主线程——
Texture 需支持预解码像素注入,后续演进。
This commit is contained in:
2026-09-24 19:31:14 +08:00
parent 6df3be2846
commit 99e6712cdf
9 changed files with 260 additions and 26 deletions
@@ -150,6 +150,8 @@ namespace Engine
AssetManager& operator=(const AssetManager&) = delete;
ModelRef LoadModel(const std::string& path);
// 异步路径:解析已在后台线程完成(路径已缓存则产物丢弃去重)
ModelRef LoadModel(const std::string& path, ParsedModel&& parsed);
Model* GetModel(ModelRef h) const { return m_Models.Get(h); }
void UnloadModel(ModelRef h) { m_Models.Unload(h); }
@@ -30,6 +30,10 @@ namespace Engine::Assets {
// 磁盘模型 → 解析 + GPU 上传(失败返回 nullptr)
virtual Scope<Model> LoadModel(const std::string& path) = 0;
// 异步路径:解析已在后台线程完成,此调用只做 GPU 构建(主线程)
virtual Scope<Model> LoadModel(const std::string& path,
ParsedModel&& parsed) = 0;
// 程序化纯色平面(size 为半边长)
virtual Scope<Model> CreatePlane(f32 halfSize, u8 r, u8 g, u8 b) = 0;