From 2138195b6990b95b79c3631aa47752b50abfb694 Mon Sep 17 00:00:00 2001 From: ssdfasd <2156608475@qq.com> Date: Fri, 3 Apr 2026 11:50:13 +0800 Subject: [PATCH] docs: sync mesh renderer component docs --- .../MeshRendererComponent/ClearMaterials.md | 8 + .../MeshRendererComponent/Deserialize.md | 35 +++- .../MeshRendererComponent/GetMaterial.md | 29 ++- .../GetMaterialAssetRefs.md | 34 ++++ .../MeshRendererComponent/GetMaterialCount.md | 5 + .../GetMaterialHandle.md | 12 ++ .../MeshRendererComponent/GetMaterialPath.md | 27 +-- .../MeshRendererComponent/GetMaterialPaths.md | 12 ++ .../MeshRendererComponent.md | 167 ++++++++++++------ .../MeshRendererComponent/Serialize.md | 19 +- .../MeshRendererComponent/SetMaterial.md | 16 +- .../MeshRendererComponent/SetMaterialPath.md | 34 ++-- .../MeshRendererComponent/SetMaterials.md | 10 +- 13 files changed, 324 insertions(+), 84 deletions(-) create mode 100644 docs/api/XCEngine/Components/MeshRendererComponent/GetMaterialAssetRefs.md diff --git a/docs/api/XCEngine/Components/MeshRendererComponent/ClearMaterials.md b/docs/api/XCEngine/Components/MeshRendererComponent/ClearMaterials.md index 67b98fe6..fe81c5ee 100644 --- a/docs/api/XCEngine/Components/MeshRendererComponent/ClearMaterials.md +++ b/docs/api/XCEngine/Components/MeshRendererComponent/ClearMaterials.md @@ -12,6 +12,14 @@ void ClearMaterials(); - `m_materials` - `m_materialPaths` +- `m_materialRefs` +- `m_pendingMaterialLoads` +- `m_asyncMaterialLoadRequested` + +## 注意事项 + +- 它不会重置 `castShadows`、`receiveShadows` 或 `renderLayer`。 +- 调用后 `GetMaterialCount()` 会回到 `0`。 ## 相关文档 diff --git a/docs/api/XCEngine/Components/MeshRendererComponent/Deserialize.md b/docs/api/XCEngine/Components/MeshRendererComponent/Deserialize.md index 7c1dfd7e..4069ba50 100644 --- a/docs/api/XCEngine/Components/MeshRendererComponent/Deserialize.md +++ b/docs/api/XCEngine/Components/MeshRendererComponent/Deserialize.md @@ -11,15 +11,44 @@ void Deserialize(std::istream& is) override; 当前实现会: 1. 先清空材质并重置默认标志。 -2. 解析 `materials`、`castShadows`、`receiveShadows` 和 `renderLayer`。 -3. 对每个非空材质路径调用 `ResourceManager::Get().Load()` 尝试重新加载。 +2. 解析 `materialPaths`、`materialRefs`、`castShadows`、`receiveShadows` 和 `renderLayer`。 +3. 兼容读取历史 `materials=` 键,并把它当作 `materialPaths=` 处理。 +4. 让 `m_materials`、`m_materialPaths`、`m_materialRefs`、pending 数组和 async 标记数组在槽位数量上重新对齐。 + +随后每个槽位按下面的优先级恢复: + +1. 如果 `materialRef` 有效,先尝试按 `AssetRef` 恢复。 +2. 如果当前处于 deferred scene load,优先尝试把 `AssetRef` 重新解析回路径,但不立即同步加载材质。 +3. 如果没有有效 `AssetRef`,或者按 `AssetRef` 恢复失败,再退回到路径恢复。 +4. 只有在非 deferred 路径下,才会直接调用 [SetMaterialPath](SetMaterialPath.md) 做同步加载。 + +这意味着“反序列化完成”并不等于“所有材质句柄都已经可用”。 ## 当前实现说明 -- 如果某个材质加载失败,对应路径仍会保留,但句柄可能为空。 - 默认值是:`castShadows = true`、`receiveShadows = true`、`renderLayer = 0`。 +- 如果某个槽位最终只恢复出了路径或 `AssetRef`,对应 `m_materials[index]` 仍可能为空。 +- 在 deferred scene load 模式下,真正的兑现通常要等首次 [GetMaterial](GetMaterial.md) 或 [GetMaterialHandle](GetMaterialHandle.md) 调用时才会触发。 + +## 项目资产恢复语义 + +当前实现特别强调项目资产的稳定恢复: + +- 当场景文本里有有效 `materialRef=` 时,组件会尽量依赖它,而不是单纯依赖字符串路径。 +- 如果 `AssetRef` 能解析到当前项目中的材质,路径会被重新规范化回 `Assets/...`。 +- 如果解析失败,仍会回退到文本路径。 + +这和商业引擎常见的“文本可读路径 + 稳定内部引用”双轨设计一致,优点是既便于调试,也能提高资源重命名后的恢复成功率。 + +## 兼容性说明 + +- 仍兼容历史 `materials=` 文本。 +- 新版 [Serialize](Serialize.md) 不再输出 `materials=`。 ## 相关文档 - [返回类型总览](MeshRendererComponent.md) - [Serialize](Serialize.md) +- [GetMaterial](GetMaterial.md) +- [GetMaterialHandle](GetMaterialHandle.md) +- [GetMaterialAssetRefs](GetMaterialAssetRefs.md) diff --git a/docs/api/XCEngine/Components/MeshRendererComponent/GetMaterial.md b/docs/api/XCEngine/Components/MeshRendererComponent/GetMaterial.md index 70145f78..9fd31df5 100644 --- a/docs/api/XCEngine/Components/MeshRendererComponent/GetMaterial.md +++ b/docs/api/XCEngine/Components/MeshRendererComponent/GetMaterial.md @@ -12,10 +12,37 @@ Resources::Material* GetMaterial(size_t index) const; ## 返回值 -- 若索引有效则返回对应材质。 +- 若当前槽位已经有可用材质,返回对应 `Material*`。 - 否则返回 `nullptr`。 +## 行为说明 + +按当前实现,这个访问器会先做两件事: + +1. `EnsureDeferredAsyncMaterialLoadStarted(index)` +2. `ResolvePendingMaterials()` + +因此它不是纯只读 getter,而是一个“读访问 + 尝试推进材质兑现”的接口。 + +## `nullptr` 的含义 + +返回 `nullptr` 并不只代表“索引越界”,还可能表示: + +- 槽位存在,但路径为空。 +- 槽位存在,材质还没完成异步加载。 +- 同步或异步加载失败。 +- 槽位越界。 + +如果调用方需要区分这些情况,应结合 [GetMaterialPath](GetMaterialPath.md) 和 [GetMaterialAssetRefs](GetMaterialAssetRefs.md) 一起判断。 + +## 使用建议 + +- 渲染提取或真正需要访问 `Material` 对象时使用它。 +- 如果只是想读取序列化主数据、调试路径或避免副作用,不要把它当作元数据 getter 使用。 + ## 相关文档 - [返回类型总览](MeshRendererComponent.md) - [GetMaterialHandle](GetMaterialHandle.md) +- [GetMaterialPath](GetMaterialPath.md) +- [GetMaterialAssetRefs](GetMaterialAssetRefs.md) diff --git a/docs/api/XCEngine/Components/MeshRendererComponent/GetMaterialAssetRefs.md b/docs/api/XCEngine/Components/MeshRendererComponent/GetMaterialAssetRefs.md new file mode 100644 index 00000000..1be40077 --- /dev/null +++ b/docs/api/XCEngine/Components/MeshRendererComponent/GetMaterialAssetRefs.md @@ -0,0 +1,34 @@ +# MeshRendererComponent::GetMaterialAssetRefs + +获取当前所有材质槽的资产引用数组。 + +```cpp +const std::vector& GetMaterialAssetRefs() const; +``` + +## 返回值 + +- 返回内部 `m_materialRefs` 的常量引用。 + +## 行为说明 + +每个槽位的 `AssetRef` 可能在以下路径里被更新: + +- [SetMaterialPath](SetMaterialPath.md) 成功把路径映射到项目资产时 +- [SetMaterial](SetMaterial.md) / [SetMaterials](SetMaterials.md) 成功从材质路径回填时 +- [Deserialize](Deserialize.md) 直接读到 `materialRefs=` 字段时 +- 异步材质兑现后,再按最终路径回填时 + +## 注意事项 + +- 这是只读元数据访问器,不会触发加载。 +- 数组长度和材质槽数量保持对齐,但某些槽位的 `AssetRef` 可能是无效的。 +- `builtin://` 这类虚拟路径、普通运行时路径或当前无法解析到项目资产的路径,通常都不会得到有效 `AssetRef`。 + +## 相关文档 + +- [返回类型总览](MeshRendererComponent.md) +- [GetMaterialPaths](GetMaterialPaths.md) +- [GetMaterialPath](GetMaterialPath.md) +- [Serialize](Serialize.md) +- [Deserialize](Deserialize.md) diff --git a/docs/api/XCEngine/Components/MeshRendererComponent/GetMaterialCount.md b/docs/api/XCEngine/Components/MeshRendererComponent/GetMaterialCount.md index 4363fb4d..9be2fcda 100644 --- a/docs/api/XCEngine/Components/MeshRendererComponent/GetMaterialCount.md +++ b/docs/api/XCEngine/Components/MeshRendererComponent/GetMaterialCount.md @@ -10,6 +10,11 @@ size_t GetMaterialCount() const; - 当前 `m_materials.size()`。 +## 当前实现说明 + +- 它表示“材质槽数量”,不是“成功加载的材质数量”。 +- 反序列化保留下来的空槽位和尾部空槽位也会计入这个数量。 + ## 相关文档 - [返回类型总览](MeshRendererComponent.md) diff --git a/docs/api/XCEngine/Components/MeshRendererComponent/GetMaterialHandle.md b/docs/api/XCEngine/Components/MeshRendererComponent/GetMaterialHandle.md index fc2ffd50..1afdd01f 100644 --- a/docs/api/XCEngine/Components/MeshRendererComponent/GetMaterialHandle.md +++ b/docs/api/XCEngine/Components/MeshRendererComponent/GetMaterialHandle.md @@ -15,11 +15,23 @@ const Resources::ResourceHandle& GetMaterialHandle(size_t i - 若索引有效则返回对应句柄引用。 - 否则返回一个静态空句柄引用。 +## 行为说明 + +和 [GetMaterial](GetMaterial.md) 一样,当前实现会在返回前先执行: + +1. `EnsureDeferredAsyncMaterialLoadStarted(index)` +2. `ResolvePendingMaterials()` + +因此它也可能在首次访问时启动一次异步加载,而不是单纯返回缓存引用。 + ## 注意事项 - 越界时返回的是共享的静态空句柄,而不是临时对象。 +- 即使索引有效,返回的句柄也可能仍为空,因为异步结果尚未完成或加载失败。 +- 如果调用方只想读取路径 / `AssetRef` 元数据,应优先使用 [GetMaterialPath](GetMaterialPath.md) 或 [GetMaterialAssetRefs](GetMaterialAssetRefs.md)。 ## 相关文档 - [返回类型总览](MeshRendererComponent.md) - [GetMaterial](GetMaterial.md) +- [GetMaterialAssetRefs](GetMaterialAssetRefs.md) diff --git a/docs/api/XCEngine/Components/MeshRendererComponent/GetMaterialPath.md b/docs/api/XCEngine/Components/MeshRendererComponent/GetMaterialPath.md index c09d8544..29f9c736 100644 --- a/docs/api/XCEngine/Components/MeshRendererComponent/GetMaterialPath.md +++ b/docs/api/XCEngine/Components/MeshRendererComponent/GetMaterialPath.md @@ -1,28 +1,35 @@ -# GetMaterialPath +# MeshRendererComponent::GetMaterialPath -**所属类型**: [MeshRendererComponent](MeshRendererComponent.md) - -## 签名 +获取指定材质槽当前缓存的路径字符串。 ```cpp const std::string& GetMaterialPath(size_t index) const; ``` -## 作用 - -返回指定材质槽当前记录的资源路径字符串。 - ## 当前实现行为 - 如果 `index` 在范围内,返回 `m_materialPaths[index]`。 - 如果越界,返回一个静态空字符串引用,而不是抛异常。 +## 语义说明 + +- 这是纯元数据访问器,不会触发异步加载。 +- 返回的是组件当前内存中的路径缓存,不等于最终序列化文本里的 `materialPaths=` 输出。 +- 对于有效项目资产槽位,序列化时路径可能被省略到 `materialRefs=` 中,但运行时这里仍然可能保留 `Assets/...` 路径。 + ## 使用建议 -这个接口更适合做编辑器显示、序列化检查和路径级调试;真正的运行时材质对象访问仍应优先看 [GetMaterial](GetMaterial.md) 或 [GetMaterialHandle](GetMaterialHandle.md)。 +适合用于: + +- 编辑器 Inspector 或调试 UI +- 路径级日志输出 +- 需要避免触发加载副作用的代码路径 + +真正需要访问 `Material` 对象时,仍应看 [GetMaterial](GetMaterial.md) 或 [GetMaterialHandle](GetMaterialHandle.md)。 ## 相关文档 -- [MeshRendererComponent](MeshRendererComponent.md) +- [返回类型总览](MeshRendererComponent.md) - [GetMaterial](GetMaterial.md) +- [GetMaterialAssetRefs](GetMaterialAssetRefs.md) - [SetMaterialPath](SetMaterialPath.md) diff --git a/docs/api/XCEngine/Components/MeshRendererComponent/GetMaterialPaths.md b/docs/api/XCEngine/Components/MeshRendererComponent/GetMaterialPaths.md index 73b26a3d..ff5fe349 100644 --- a/docs/api/XCEngine/Components/MeshRendererComponent/GetMaterialPaths.md +++ b/docs/api/XCEngine/Components/MeshRendererComponent/GetMaterialPaths.md @@ -10,8 +10,20 @@ const std::vector& GetMaterialPaths() const; - 当前缓存的材质路径数组引用。 +## 行为说明 + +- 数组槽位与 `m_materials`、`m_materialRefs` 的槽位语义保持对齐。 +- 这是只读元数据访问器,不会触发加载。 +- 这里返回的是内存里的完整路径缓存,不是最终文本序列化时的 fallback 输出。 + +## 何时使用 + +- 需要批量显示或检查所有材质槽路径时。 +- 需要避免对每个槽位逐个访问 [GetMaterial](GetMaterial.md) 产生副作用时。 + ## 相关文档 - [返回类型总览](MeshRendererComponent.md) +- [GetMaterialAssetRefs](GetMaterialAssetRefs.md) - [Serialize](Serialize.md) - [Deserialize](Deserialize.md) diff --git a/docs/api/XCEngine/Components/MeshRendererComponent/MeshRendererComponent.md b/docs/api/XCEngine/Components/MeshRendererComponent/MeshRendererComponent.md index 903290dd..eb693e1b 100644 --- a/docs/api/XCEngine/Components/MeshRendererComponent/MeshRendererComponent.md +++ b/docs/api/XCEngine/Components/MeshRendererComponent/MeshRendererComponent.md @@ -6,64 +6,127 @@ **头文件**: `XCEngine/Components/MeshRendererComponent.h` -**描述**: 保存材质槽、阴影开关和渲染层等绘制配置,声明“这个对象上的 Mesh 应该如何被渲染”。 +**描述**: 保存材质槽、资产引用、阴影开关和渲染层等绘制配置,把场景对象与具体 `Material` 资源绑定起来。 ## 角色概述 -`MeshRendererComponent` 负责的是“绘制配置”,不是“几何来源”。 +`MeshRendererComponent` 负责回答“这个对象上的 mesh 应该用什么材质、以什么附加状态被渲染”。它不提供几何来源,也不直接发起 draw call;当前链路里它主要扮演四个角色: -- [MeshFilterComponent](../MeshFilterComponent/MeshFilterComponent.md) 负责网格 -- `MeshRendererComponent` 负责材质槽和渲染附加参数 +- 为运行时保存可直接使用的 `Material` 句柄。 +- 为场景文本保存稳定的材质路径数组。 +- 为项目资产保存 `AssetRef`,让场景在资源移动或重命名后仍有机会恢复材质绑定。 +- 为脚本层、编辑器和渲染提取层提供统一的材质槽视图。 -两者配合后,`RenderSceneExtractor` 才能把场景对象整理成可提交到渲染管线的可见项。 +和它配套工作的主要对象是: -## 当前实现行为 +- [MeshFilterComponent](../MeshFilterComponent/MeshFilterComponent.md):负责 mesh 资源本身。 +- `ResourceManager`:负责按路径或 `AssetRef` 加载 `Material`,也负责延迟异步加载。 +- [RenderSceneExtractor](../../Rendering/RenderSceneExtractor/RenderSceneExtractor.md):只有 mesh 和材质都可用时,才会把对象整理成可见渲染项。 -### 1. 同时维护材质 handle 和路径数组 +这种拆分很接近商业引擎里常见的 `MeshFilter + MeshRenderer` 思路。好处是“几何来源”和“绘制配置”可以分别序列化、分别编辑,也更适合后续做资源热更新、材质复用和编辑器 Inspector。 -内部维护两套并行数组: +## 当前状态模型 -- `m_materials` -- `m_materialPaths` +当前实现维护了五份与材质槽相关的状态: -这和 `MeshFilterComponent` 的思路一致,目的是同时满足: +| 状态 | 类型 | 作用 | +|------|------|------| +| `m_materials` | `std::vector>` | 当前已兑现的运行时材质句柄。 | +| `m_materialPaths` | `std::vector` | 可序列化、可调试的路径数组。 | +| `m_materialRefs` | `std::vector` | 项目资产数据库可解析的稳定引用。 | +| `m_pendingMaterialLoads` | `std::vector>` | 异步加载尚未收口时的挂起结果。 | +| `m_asyncMaterialLoadRequested` | `std::vector` | 防止同一槽位重复发起异步加载。 | -- 运行时快速拿资源 -- 序列化时稳定写路径 +这几组数组会尽量保持同一槽位语义对齐。换句话说,`slot 3` 的 handle、path、`AssetRef`、pending state 都是在描述“第 3 个材质槽”。 -### 2. 材质槽会按需自动扩容 +## 绑定与解析流程 -`SetMaterialPath()` 和 `SetMaterial()` 在写入指定槽位前,都会先调用内部 `EnsureMaterialSlot(index)`。 +### 1. 路径驱动的绑定 -因此: +[SetMaterialPath](SetMaterialPath.md) 会: -- 可以直接写入一个较大的槽位索引 -- 中间缺失槽位会被自动补成空材质 +- 先确保槽位存在。 +- 清掉该槽位旧的异步挂起状态。 +- 写入新的 `m_materialPaths[index]`。 +- 立即调用 `ResourceManager::Load(path)` 做一次同步加载尝试。 +- 再调用 `TryGetAssetRef(path, ResourceType::Material, ...)` 尝试回填 `AssetRef`。 -`tests/Components/test_mesh_render_components.cpp` 已覆盖这一行为。 +即使同步加载失败,路径仍会保留;如果这条路径能映射到项目资产,`m_materialRefs[index]` 也可能仍然有效。 -### 3. 越界读取是“安全空值”语义 +要注意一个很容易误解的点:按当前源码,`SetMaterialPath()` 本身仍是“立即同步加载”的接口,它不会因为 deferred scene load 模式而自动改成纯记录路径。 -按当前实现: +### 2. 句柄驱动的绑定 -- `GetMaterial(index)` 越界时返回 `nullptr` -- `GetMaterialHandle(index)` 越界时返回静态空 handle -- `GetMaterialPath(index)` 越界时返回静态空字符串 +[SetMaterial](SetMaterial.md) 会: -这让上层调用少了很多显式边界判断,但也意味着调用者不能把空返回值误读成“这个槽位一定存在但内容为空”。 +- 保存句柄。 +- 通过 `material->GetPath()` 反推路径。 +- 再按路径尝试回填 `AssetRef`。 -### 4. 反序列化按路径重建槽位 +这让“运行时直接塞一个已经加载好的材质”与“场景序列化仍能恢复路径/资产引用”两件事可以同时成立。 -`Deserialize()` 会: +### 3. 反序列化后的恢复策略 -- 先清空旧材质与标记 -- 解析 `materials=` 字段 -- 用 `|` 分隔多材质路径 -- 对每个槽位调用 `SetMaterialPath()` 尝试重新加载 +[Deserialize](Deserialize.md) 现在会同时处理: -即使资源此刻没有加载成功,路径数组也会被保留下来。这一点同样有测试覆盖。 +- `materialPaths=` +- `materialRefs=` +- 历史兼容键 `materials=` -## 阴影和渲染层的现实状态 +恢复优先级大致是: + +1. 如果 `materialRef` 有效,优先尝试按 `AssetRef` 恢复。 +2. 如果当前是 deferred scene load,尽量先把 `AssetRef` 解析回路径,但不立即同步兑现材质。 +3. 如果没有可用 `AssetRef`,再按路径恢复。 + +### 4. 首次访问时的异步兑现 + +[GetMaterial](GetMaterial.md) 和 [GetMaterialHandle](GetMaterialHandle.md) 虽然是 `const`,但当前实现会通过 `const_cast` 内部触发: + +1. `EnsureDeferredAsyncMaterialLoadStarted(index)` +2. `ResolvePendingMaterials()` + +也就是说,这两个访问器不只是“读缓存”,还会推动路径恢复后的材质兑现流程向前走。 + +从行为上看,它们的主用途是支持 deferred scene load,但按当前源码,只要某个槽位“有路径、还没有 material、也还没发起过请求”,首次访问就可能触发一次异步加载尝试。 + +## 序列化语义 + +当前序列化会输出五段键值: + +```text +materialPaths=; +materialRefs=; +castShadows=1; +receiveShadows=1; +renderLayer=0; +``` + +其中最关键的设计点是: + +- `materialRefs` 是主身份信息,面向项目资产恢复。 +- `materialPaths` 更像回退字段,只在该槽位没有有效 `AssetRef` 时才真正写出路径。 + +例如一个项目资产材质槽,当前文本很可能是: + +```text +materialPaths=; +materialRefs=<有效 guid,localId,type>; +``` + +这不是数据丢失,而是说明当前序列化更信任 `AssetRef` 作为稳定身份。 + +## 与渲染链路的关系 + +当前 `RenderSceneUtility` 会把 `MeshRendererComponent*` 直接挂进可见渲染对象,再由后续材质提取逻辑读取材质槽。 + +这意味着: + +- `MeshRendererComponent` 是否“有槽位”不重要。 +- 重要的是在真正提取材质时,对应槽位能否拿到有效 `Material`。 +- 在 deferred / async 场景里,对象可能已经有 `MeshFilterComponent + MeshRendererComponent`,但某个时刻材质仍为空,直到异步结果被 `ResolvePendingMaterials()` 收口。 + +## 阴影与渲染层的现实状态 当前组件公开了: @@ -71,35 +134,36 @@ - `GetReceiveShadows()` / `SetReceiveShadows()` - `GetRenderLayer()` / `SetRenderLayer()` -但按当前 [RenderSceneExtractor](../../Rendering/RenderSceneExtractor/RenderSceneExtractor.md) 实现,场景提取时还没有看到这些字段被真正消费。也就是说: +但按当前源码检索,这几个字段目前主要被: -- 这些字段当前可以保存 -- 也可以被序列化 -- 但它们还没有完整接入当前已取证的渲染提取路径 +- 组件测试、场景序列化测试 +- Mono scripting internal call -文档必须把这一点说清楚,避免用户把“字段存在”误解成“功能已完整生效”。 +消费;还没有看到它们被当前已取证的渲染提取路径真正读取。也就是说: -## 序列化语义 +- 它们当前可以保存。 +- 可以被序列化。 +- 也可以被脚本层读写。 +- 但不能简单等同于“阴影层级和 render layer 已完整进入 renderer 主路径”。 -当前写出: +## 测试与真实使用点 -- `materials`,多个路径用 `|` 分隔 -- `castShadows` -- `receiveShadows` -- `renderLayer` +- `tests/Components/test_mesh_render_components.cpp` 覆盖了槽位扩容、双轨序列化、历史键兼容、项目材质 `AssetRef` 恢复,以及 deferred async material load。 +- `tests/Scene/test_scene.cpp` 覆盖了场景序列化后对 `castShadows` / `receiveShadows` / `renderLayer` 的恢复。 +- `engine/src/Scripting/Mono/MonoScriptRuntime.cpp` 暴露了阴影和 render layer 的脚本读写入口。 -测试还覆盖了“末尾空材质槽”会被保留的情况,这对编辑器材质槽 UI 很重要。 - -## 线程语义 +## 线程与访问语义 - 当前实现没有内部加锁。 -- 资源路径解析和材质切换默认按主线程配置路径使用。 +- 路径写入、序列化和槽位编辑默认按主线程使用。 +- `GetMaterial()` / `GetMaterialHandle()` 是带副作用的读访问器;如果调用方只想查看元数据而不触发兑现,应优先使用 [GetMaterialPath](GetMaterialPath.md)、[GetMaterialPaths](GetMaterialPaths.md) 或 [GetMaterialAssetRefs](GetMaterialAssetRefs.md)。 ## 当前实现限制 -- 当前文档目录原先缺少 `GetMaterialPath()` 和 `SetMaterialPath()` 独立方法页,本轮已补齐。 -- `castShadows`、`receiveShadows` 和 `renderLayer` 还没有完整接入当前已取证的场景提取逻辑。 -- 它只负责声明绘制配置,不等于完整 renderer feature 集合。 +- 当前只维护“平铺材质槽数组”,不处理 submesh 级独立绑定策略、材质实例化策略或 streaming 策略。 +- `GetMaterial()` / `GetMaterialHandle()` 可能在首次访问时触发异步加载,因此它们不是纯只读 getter。 +- `materialPaths` 在序列化文本里只作为 fallback 字段输出,不应把“文本里 path 为空”误解成“组件内存里没有路径缓存”。 +- `castShadows`、`receiveShadows` 和 `renderLayer` 还没有完整接入当前已取证的 renderer 主路径。 ## 相关方法 @@ -108,6 +172,7 @@ - [GetMaterialHandle](GetMaterialHandle.md) - [GetMaterialPath](GetMaterialPath.md) - [GetMaterialPaths](GetMaterialPaths.md) +- [GetMaterialAssetRefs](GetMaterialAssetRefs.md) - [SetMaterial](SetMaterial.md) - [SetMaterialPath](SetMaterialPath.md) - [SetMaterials](SetMaterials.md) diff --git a/docs/api/XCEngine/Components/MeshRendererComponent/Serialize.md b/docs/api/XCEngine/Components/MeshRendererComponent/Serialize.md index 49fec516..74cd1bb2 100644 --- a/docs/api/XCEngine/Components/MeshRendererComponent/Serialize.md +++ b/docs/api/XCEngine/Components/MeshRendererComponent/Serialize.md @@ -8,18 +8,31 @@ void Serialize(std::ostream& os) const override; ## 行为说明 -当前实现会输出类似: +当前实现不再输出旧的 `materials=` 键,而是并行写出材质路径 fallback 和稳定资产引用: ```text -materials=Mat0|Mat1; +materialPaths=|builtin://materials/default; +materialRefs=|; castShadows=1; receiveShadows=0; renderLayer=3; ``` -其中材质路径使用 `|` 分隔。 +其中: + +- `materialPaths` 和 `materialRefs` 都按材质槽顺序用 `|` 分隔。 +- 对于能稳定映射到项目资产的槽位,当前会优先写 `materialRefs`,并把同槽位 `materialPaths` 留空。 +- 对于没有有效 `AssetRef` 的槽位,例如 `builtin://` 这类虚拟路径,才会把路径写进 `materialPaths`。 +- 会保留尾部空槽位,避免编辑器材质槽数量在反序列化后缩水。 + +## 当前实现含义 + +- 场景文本现在同时保存“人类可读路径 fallback”和“项目资产稳定身份”。 +- 项目资产改名或移动后,更应依赖 `materialRefs` 恢复绑定,而不是依赖旧路径字符串。 +- 旧版依赖 `materials=` 的读取逻辑仍由 [Deserialize](Deserialize.md) 保留兼容。 ## 相关文档 - [返回类型总览](MeshRendererComponent.md) - [Deserialize](Deserialize.md) +- [GetMaterialAssetRefs](GetMaterialAssetRefs.md) diff --git a/docs/api/XCEngine/Components/MeshRendererComponent/SetMaterial.md b/docs/api/XCEngine/Components/MeshRendererComponent/SetMaterial.md index ef8c46b8..0cc081b2 100644 --- a/docs/api/XCEngine/Components/MeshRendererComponent/SetMaterial.md +++ b/docs/api/XCEngine/Components/MeshRendererComponent/SetMaterial.md @@ -1,6 +1,6 @@ # MeshRendererComponent::SetMaterial -设置单个材质槽。 +按句柄设置单个材质槽。 ```cpp void SetMaterial(size_t index, const Resources::ResourceHandle& material); @@ -12,16 +12,26 @@ void SetMaterial(size_t index, Resources::Material* material); 当前实现会: 1. 通过 `EnsureMaterialSlot()` 保证数组至少扩容到 `index + 1`。 -2. 写入 `m_materials[index]`。 -3. 根据句柄中的资源路径同步更新 `m_materialPaths[index]`。 +2. 清掉该槽位旧的 pending async load,并复位 async-request 标记。 +3. 写入 `m_materials[index]`。 +4. 根据句柄中的资源路径同步更新 `m_materialPaths[index]`。 +5. 再按该路径尝试解析 `m_materialRefs[index]`;失败则重置为无效引用。 ## 参数 - `index` - 材质槽索引。 - `material` - 要设置的材质句柄或裸指针。 +## 语义说明 + +- 这个接口以“运行时材质对象已经存在”为前提。 +- 如果材质句柄没有可解析路径,或者路径不能映射到项目资产,`m_materialRefs[index]` 会变成无效引用。 +- 和 [SetMaterialPath](SetMaterialPath.md) 相比,它更偏运行时写入,而不是路径驱动的资源恢复。 + ## 相关文档 - [返回类型总览](MeshRendererComponent.md) +- [GetMaterialAssetRefs](GetMaterialAssetRefs.md) +- [SetMaterialPath](SetMaterialPath.md) - [SetMaterials](SetMaterials.md) - [ClearMaterials](ClearMaterials.md) diff --git a/docs/api/XCEngine/Components/MeshRendererComponent/SetMaterialPath.md b/docs/api/XCEngine/Components/MeshRendererComponent/SetMaterialPath.md index 3b225052..c96641fc 100644 --- a/docs/api/XCEngine/Components/MeshRendererComponent/SetMaterialPath.md +++ b/docs/api/XCEngine/Components/MeshRendererComponent/SetMaterialPath.md @@ -1,32 +1,42 @@ -# SetMaterialPath +# MeshRendererComponent::SetMaterialPath -**所属类型**: [MeshRendererComponent](MeshRendererComponent.md) - -## 签名 +按路径设置单个材质槽。 ```cpp void SetMaterialPath(size_t index, const std::string& materialPath); ``` -## 作用 - -为指定材质槽设置资源路径,并尝试通过 `ResourceManager` 加载对应材质。 - ## 当前实现行为 - 调用内部 `EnsureMaterialSlot(index)` 自动扩容槽位数组。 -- 先记录 `m_materialPaths[index] = materialPath`。 -- 若路径为空,则重置该槽位的材质 handle。 +- 清空该槽位旧的 pending async load,并把 `m_asyncMaterialLoadRequested[index]` 复位为 `false`。 +- 记录 `m_materialPaths[index] = materialPath`。 +- 若路径为空,则同时重置 `m_materials[index]` 和 `m_materialRefs[index]`。 - 若路径非空,则调用 `ResourceManager::Get().Load(...)` 尝试加载。 +- 然后调用 `TryGetAssetRef(...)` 试着把路径映射成项目资产引用。 - 即使加载失败,路径也会保留。 +## 重要语义 + +- 这是一个同步设置接口,不是“只记录路径、等以后再加载”的接口。 +- 虚拟路径或内置路径也允许写入,但通常拿不到有效 `AssetRef`。 +- 如果后续重新设置同一槽位,旧的异步状态会被显式丢弃。 + ## 使用建议 -这比直接设置 handle 更适合编辑器材质面板和序列化恢复路径,因为路径才是当前场景文件的主持久化数据。 +这比直接设置 handle 更适合: + +- 编辑器材质面板 +- 场景文本反序列化后的路径恢复 +- 希望保留稳定文本路径的工具链 + +如果调用方已经手里拿到了一个确定可用的材质句柄,并且希望以运行时对象为主写入,则可以考虑 [SetMaterial](SetMaterial.md)。 ## 相关文档 -- [MeshRendererComponent](MeshRendererComponent.md) +- [返回类型总览](MeshRendererComponent.md) - [GetMaterialPath](GetMaterialPath.md) +- [GetMaterialAssetRefs](GetMaterialAssetRefs.md) +- [SetMaterial](SetMaterial.md) - [Serialize](Serialize.md) - [Deserialize](Deserialize.md) diff --git a/docs/api/XCEngine/Components/MeshRendererComponent/SetMaterials.md b/docs/api/XCEngine/Components/MeshRendererComponent/SetMaterials.md index 63abd887..6e11c7e5 100644 --- a/docs/api/XCEngine/Components/MeshRendererComponent/SetMaterials.md +++ b/docs/api/XCEngine/Components/MeshRendererComponent/SetMaterials.md @@ -8,7 +8,14 @@ void SetMaterials(const std::vector