diff --git a/docs/plan/Material Inspector与Shader属性面板收口计划_2026-04-07.md b/docs/plan/Material Inspector与Shader属性面板收口计划_2026-04-07.md new file mode 100644 index 00000000..8df78a41 --- /dev/null +++ b/docs/plan/Material Inspector与Shader属性面板收口计划_2026-04-07.md @@ -0,0 +1,387 @@ +# Material Inspector与Shader属性面板收口计划 + +日期:2026-04-07 + +## 1. 背景 + +当前 Rendering / Shader / Material 主线已经基本建立起正式架构: + +- Shader 侧已经具备统一的 authoring/schema 能力。 +- Material 运行时与 artifact 路径已经逐步从旧兼容逻辑中收口。 +- Editor 中的 Material Inspector 仍然没有完全切换到“由 Shader schema 驱动”的正式工作流。 + +当前最突出的实际问题有两类: + +1. Material 选择 Shader 后,Shader 中声明的属性没有被正式暴露到 Inspector 面板上。 +2. Material 面板上还残留了一些历史字段或临时 UI,用户无法清晰判断哪些是正式能力,哪些只是过渡产物。 + +此外,当前工程条件已经允许做更彻底的清理: + +- `project/` 中旧材质资产可直接编辑。 +- 当前不存在必须长期兼容的历史材质资产包袱。 + +因此,这一阶段的目标不是“继续兼容旧面板”,而是把 Material 编辑链路彻底切换到正式路径,并为后续 Shader/Material 编辑器扩展打好基础。 + +## 2. 本阶段目标 + +本阶段要完成以下目标: + +1. 让 Material Inspector 成为 Shader schema 驱动的正式编辑入口。 +2. 让材质面板只暴露当前正式架构中的概念,不再混入旧字段和误导性配置。 +3. 保证 Editor 面板、运行时 `Material`、源资产、artifact、reimport 之间的数据一致性。 +4. 用单测和必要的编辑器验证把这条链路收口,而不是停留在“能显示”层面。 + +## 3. 不在本阶段处理的内容 + +以下内容不属于本阶段主目标,避免范围失控: + +- 自定义 Material Drawer 系统。 +- Shader Graph / 节点式材质编辑器。 +- 面向美术工作流的复杂 Material 预设库。 +- SRP 层级的材质检查器定制机制。 +- 完整的 Shader GUI 仿 Unity 高级扩展体系。 + +这些能力后续可以做,但必须建立在当前正式链路已经稳定收口的前提上。 + +## 4. 当前已确认的问题 + +### 4.1 Inspector 没有正式反射 Shader 属性 + +当前 Material Inspector 还没有完整读取 Shader schema 并按类型生成属性控件,导致: + +- Shader 中声明的属性无法完整暴露。 +- 用户无法直接编辑当前材质真正生效的参数。 +- 材质默认值、覆盖值、纹理槽与资源引用状态之间关系不清晰。 + +### 4.2 材质面板仍存在历史路径残留 + +之前材质层面曾承担过一些本不应由材质承担的职责,例如: + +- 材质自己选择 builtin pass。 +- Inspector 里出现与当前正式架构不一致的旧字段。 + +这类逻辑已经开始清理,但 Editor 面板仍需同步彻底收口。 + +### 4.3 Editor 与运行时 Material 状态可能脱节 + +如果面板的编辑状态不是直接围绕正式 `Material` 数据模型建立,就容易出现: + +- Inspector 显示值与运行时实际值不一致。 +- 资源重载后 UI 状态失真。 +- artifact / reimport 后材质参数丢失或回退异常。 + +### 4.4 缺少围绕正式工作流的测试闭环 + +仅靠手工点 Inspector 验证不足以支撑后续迭代。必须补足以下覆盖: + +- Shader 切换后属性集合重建。 +- 默认值与显式覆盖值的切换。 +- Texture 属性与资源引用链路。 +- Keyword 与 Render State 的持久化。 +- artifact/reimport 后数据一致性。 + +## 5. 设计原则 + +本阶段严格遵循以下原则: + +### 5.1 Shader 定义什么,Material 就暴露什么 + +Material 不是独立定义属性结构的地方。属性结构必须由 Shader schema 决定,Inspector 只是将其可视化并允许编辑。 + +### 5.2 Material 只承载实例数据,不承载管线选择策略 + +材质应承载: + +- Shader 引用 +- Shader schema 对应的属性值 +- Keyword 状态 +- 合法的 render state 覆盖 + +材质不应再承载: + +- 独立指定 builtin pass 的旧路径 +- 与 Shader metadata 冲突的临时策略字段 + +### 5.3 Editor 不发明第二套数据模型 + +Inspector 的中间态必须服务于正式数据模型,而不是绕开 `Material` 自己维护一套平行逻辑。 + +### 5.4 面板必须可验证 + +每一步改动都必须能通过测试或明确的编辑器验证闭环证明正确,不接受只靠目测“看起来差不多”。 + +## 6. 分阶段执行计划 + +## Phase 1:现状审查与残留路径清点 + +### 目标 + +彻底梳理当前 Material Inspector、Material 资源、Shader schema、artifact 序列化之间的实际数据流。 + +### 任务 + +- 审查 `InspectorPanel` 当前 Material 面板的数据来源和写回路径。 +- 审查 `Material` 当前正式字段与历史遗留字段。 +- 审查 `MaterialLoader`、`AssetDatabase`、artifact schema 当前是否仍保留不必要兼容路径。 +- 识别 Material 面板中哪些字段是正式路径,哪些属于旧方案残留。 + +### 完成标准 + +- 列清楚当前正式数据流。 +- 列清楚必须删除的旧字段/旧 UI。 +- 列清楚缺失的 schema 反射入口。 + +## Phase 2:Material Inspector 数据模型收口 + +### 目标 + +让 Material 面板的数据模型只围绕正式架构组织。 + +### 任务 + +- 移除 Material 层面的旧 pass 选择 UI 与残余兼容路径。 +- 整理 Inspector 内部状态结构,只保留: + - Shader 资源引用 + - Shader schema 对应属性 + - Keywords + - Render Queue / Render State + - Tags(仅保留当前正式允许暴露的部分) +- 避免 Inspector 保存与运行时 `Material` 不一致的冗余字段。 + +### 完成标准 + +- 面板字段与正式 `Material` 模型一一对应。 +- 旧字段彻底不再出现在材质编辑界面和保存链路中。 + +## Phase 3:Shader schema 驱动的属性面板生成 + +### 目标 + +Material Inspector 能基于 Shader schema 动态生成属性编辑 UI。 + +### 任务 + +- 读取 Shader 声明的属性定义与默认值。 +- 按属性类型渲染控件: + - `float` + - `int` + - `bool` + - `float2/3/4` + - `texture` +- 正确显示每个属性的: + - 属性名 + - 显示名 + - 默认值 + - 当前覆盖值 + - 纹理槽绑定状态 + - 资源引用路径/AssetRef 状态 +- 明确“未覆盖时使用 Shader 默认值”的表现形式。 + +### 完成标准 + +- 选定 Shader 后,Inspector 中能稳定暴露该 Shader 的正式属性集合。 +- 面板能正确编辑并持久化这些属性。 + +## Phase 4:Editor 与运行时一致性收口 + +### 目标 + +保证 Material Inspector 编辑结果与运行时 `Material`、artifact、reimport 行为一致。 + +### 任务 + +- 对齐 Inspector 写回逻辑与 `Material` 正式 API。 +- 验证 Shader 切换时属性重建、默认值回退、无效属性清理。 +- 验证纹理属性在源资产、artifact、异步资源加载中的一致性。 +- 验证关键词与 render state 在 reload/reimport 后不丢失。 + +### 完成标准 + +- Inspector 改动能被运行时正确读取。 +- Reload / Reimport / Artifact Round Trip 后材质数据不漂移。 + +## Phase 5:测试补齐与阶段验收 + +### 目标 + +为正式工作流建立可持续回归验证。 + +### 任务 + +- 补充或更新 `material_tests`。 +- 补充或更新 `asset_tests`。 +- 若材质解析或 builtin pass 匹配受影响,补充必要的 `rendering_unit_tests`。 +- 重新编译 `XCEditor`,执行人工冒烟验证。 + +### 验收项 + +- `material_tests` 全绿。 +- `asset_tests` 全绿。 +- 必要的 `rendering_unit_tests` 全绿。 +- `XCEditor` 编译通过。 +- Material Inspector 中 Shader 属性暴露、编辑、保存、重载行为正确。 + +## 7. 预期交付结果 + +本阶段完成后,工程应达到以下状态: + +1. Material 面板正式切换为 Shader schema 驱动。 +2. 材质不再承担旧 pass 选择职责。 +3. Inspector 中只剩下当前正式架构允许存在的字段。 +4. 材质属性、纹理槽、关键词、render state 都能稳定编辑并正确持久化。 +5. Shader / Material 后续扩展拥有清晰入口,不再建立在旧兼容逻辑之上。 + +## 8. 风险与注意事项 + +### 8.1 Shader 切换会触发属性重建 + +必须定义清楚以下规则: + +- 与新 Shader schema 匹配的属性如何保留。 +- 不匹配的旧属性如何移除。 +- 默认值何时回退,何时保留用户覆盖。 + +### 8.2 Texture 属性不仅是 UI 问题 + +Texture 属性同时涉及: + +- Inspector 显示 +- AssetRef +- 资源路径 +- artifact 存储 +- 延迟加载 + +因此不能只改面板显示,必须连同资源路径一起验证。 + +### 8.3 Render State 需要坚持“正式最小集” + +Material 面板不应再次演化成随意堆字段的临时入口。所有 render state 暴露都必须建立在当前正式支持的能力之上。 + +## 9. 建议执行顺序 + +建议严格按以下顺序落地: + +1. 先完成旧字段与旧路径清点。 +2. 再重构 Inspector 数据模型。 +3. 再接 Shader schema 驱动属性 UI。 +4. 再收口 Editor 与运行时一致性。 +5. 最后统一补测与验收。 + +不能反过来先堆 UI,再回头补数据模型,否则很容易再次生成新的临时方案。 + +## 10. 阶段结论 + +当前最应该推进的不是继续增加 Material 编辑功能花样,而是把 Material Inspector 这条正式链路做对、做稳、做干净。 + +只要这一阶段收口完成,后续无论是: + +- 更完整的 Shader authoring +- Material 默认面板 +- 针对 Renderer/SRP 的材质体系扩展 +- 更接近 Unity 的 Shader/Material 编辑工作流 + +都会建立在清晰、稳定、可验证的基础之上。 + +## 11. Phase 1 审查结果 + +状态:已完成 + +本阶段已对当前 Material Inspector、运行时 `Material`、Shader schema、material source/artifact 路径进行了实际代码审查,结论如下。 + +### 11.1 当前 Inspector 数据模型先天不完整 + +当前 `InspectorPanel::MaterialAssetState` 只维护了以下内容: + +- `shaderPath` +- `renderQueue` +- `renderState` +- `tags` + +它没有正式承载以下关键数据: + +- Shader schema 属性列表 +- 材质属性当前值 +- 纹理槽与贴图引用 +- 关键词状态 +- Render State Override 开关本身 + +这意味着当前 Inspector 不是“少画了几个控件”,而是其内部状态模型本身就无法表示正式的材质编辑数据。 + +### 11.2 当前 Inspector 保存链路会丢失材质的正式内容 + +当前 `BuildMaterialAssetFileText()` 仅写出: + +- `shader` +- `renderQueue` +- `tags` +- `renderState` + +它不会写出: + +- `properties` +- `textures` +- `keywords` + +因此,只要一个材质已经拥有 Shader 属性、纹理槽或关键词,若用户通过当前 Inspector 保存一次,该材质源文件就可能被覆盖成一个严重简化后的版本,导致正式材质数据丢失。 + +### 11.3 当前 Inspector 的实时写回同样不完整 + +当前 `ApplyResolvedMaterialStateToResource()` 仅把面板状态写回到运行时 `Material` 的以下部分: + +- `SetShader` +- `SetRenderQueue` +- `SetRenderState` +- `ClearTags` / `SetTag` + +它不会写回: + +- Shader schema 属性值 +- 纹理绑定 +- 关键词 + +因此 Inspector 当前即使支持继续加控件,如果不先重构数据模型,运行时同步仍然会不完整。 + +### 11.4 Render State Override 当前没有被正式建模 + +运行时 `Material::SetRenderState()` 会自动把 `HasRenderStateOverride` 置为 `true`。 + +但当前 Inspector: + +- 没有暴露 “是否启用 Render State Override” +- 保存时始终写出完整 `renderState` +- 应用时始终调用 `SetRenderState` + +这意味着只要用户通过当前材质面板保存,材质就会被强制推进到显式 Render State Override 路径。这个行为不符合正式设计,必须在下一阶段一起修正。 + +### 11.5 运行时底层能力其实已经基本齐备 + +当前 runtime/resource 层已经具备正式所需的大部分能力: + +- `ShaderPropertyDesc` 已包含 `name / displayName / type / defaultValue / semantic` +- `Shader` 已提供 `GetProperties()` / `FindProperty()` / keyword declaration 能力 +- `Material` 已提供完整的 `SetFloat/SetInt/SetBool/SetTexture...` +- `Material` 已支持 Shader schema 默认值同步 +- `MaterialLoader` 已支持解析 `properties / textures / keywords / tags / renderState` +- material artifact 当前已支持这些正式数据的持久化 + +也就是说,当前问题的主要矛盾不在资源系统,而在 Editor 侧没有接入正式模型。 + +### 11.6 当前阶段的根本性结论 + +下一阶段不能直接在现有材质面板上继续堆控件。 + +必须先完成: + +1. `MaterialAssetState` 的正式重构 +2. Save/Reload/Apply 链路对 `properties / textures / keywords / renderState override` 的建模 +3. Inspector 与运行时 `Material` 之间的一致性重建 + +只有先做完这些,后续的 Shader schema 驱动属性 UI 才不会继续建立在错误基础上。 + +### 11.7 Phase 2 的直接执行范围 + +基于本阶段审查结果,下一阶段将直接进入以下工作: + +1. 扩展 `MaterialAssetState`,让其正式承载属性、纹理槽、关键词与 render state override。 +2. 重构 `Populate / Apply / Save / Reload` 这四条关键链路。 +3. 彻底消除当前“保存一次就丢属性”的结构性问题。