20 KiB
Material Inspector与Shader属性面板收口计划
日期:2026-04-07
1. 背景
当前 Rendering / Shader / Material 主线已经基本建立起正式架构:
- Shader 侧已经具备统一的 authoring/schema 能力。
- Material 运行时与 artifact 路径已经逐步从旧兼容逻辑中收口。
- Editor 中的 Material Inspector 仍然没有完全切换到“由 Shader schema 驱动”的正式工作流。
当前最突出的实际问题有两类:
- Material 选择 Shader 后,Shader 中声明的属性没有被正式暴露到 Inspector 面板上。
- Material 面板上还残留了一些历史字段或临时 UI,用户无法清晰判断哪些是正式能力,哪些只是过渡产物。
此外,当前工程条件已经允许做更彻底的清理:
project/中旧材质资产可直接编辑。- 当前不存在必须长期兼容的历史材质资产包袱。
因此,这一阶段的目标不是“继续兼容旧面板”,而是把 Material 编辑链路彻底切换到正式路径,并为后续 Shader/Material 编辑器扩展打好基础。
2. 本阶段目标
本阶段要完成以下目标:
- 让 Material Inspector 成为 Shader schema 驱动的正式编辑入口。
- 让材质面板只暴露当前正式架构中的概念,不再混入旧字段和误导性配置。
- 保证 Editor 面板、运行时
Material、源资产、artifact、reimport 之间的数据一致性。 - 用单测和必要的编辑器验证把这条链路收口,而不是停留在“能显示”层面。
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 声明的属性定义与默认值。
- 按属性类型渲染控件:
floatintboolfloat2/3/4texture
- 正确显示每个属性的:
- 属性名
- 显示名
- 默认值
- 当前覆盖值
- 纹理槽绑定状态
- 资源引用路径/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. 预期交付结果
本阶段完成后,工程应达到以下状态:
- Material 面板正式切换为 Shader schema 驱动。
- 材质不再承担旧 pass 选择职责。
- Inspector 中只剩下当前正式架构允许存在的字段。
- 材质属性、纹理槽、关键词、render state 都能稳定编辑并正确持久化。
- Shader / Material 后续扩展拥有清晰入口,不再建立在旧兼容逻辑之上。
8. 风险与注意事项
8.1 Shader 切换会触发属性重建
必须定义清楚以下规则:
- 与新 Shader schema 匹配的属性如何保留。
- 不匹配的旧属性如何移除。
- 默认值何时回退,何时保留用户覆盖。
8.2 Texture 属性不仅是 UI 问题
Texture 属性同时涉及:
- Inspector 显示
- AssetRef
- 资源路径
- artifact 存储
- 延迟加载
因此不能只改面板显示,必须连同资源路径一起验证。
8.3 Render State 需要坚持“正式最小集”
Material 面板不应再次演化成随意堆字段的临时入口。所有 render state 暴露都必须建立在当前正式支持的能力之上。
9. 建议执行顺序
建议严格按以下顺序落地:
- 先完成旧字段与旧路径清点。
- 再重构 Inspector 数据模型。
- 再接 Shader schema 驱动属性 UI。
- 再收口 Editor 与运行时一致性。
- 最后统一补测与验收。
不能反过来先堆 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 只维护了以下内容:
shaderPathrenderQueuerenderStatetags
它没有正式承载以下关键数据:
- Shader schema 属性列表
- 材质属性当前值
- 纹理槽与贴图引用
- 关键词状态
- Render State Override 开关本身
这意味着当前 Inspector 不是“少画了几个控件”,而是其内部状态模型本身就无法表示正式的材质编辑数据。
11.2 当前 Inspector 保存链路会丢失材质的正式内容
当前 BuildMaterialAssetFileText() 仅写出:
shaderrenderQueuetagsrenderState
它不会写出:
propertiestextureskeywords
因此,只要一个材质已经拥有 Shader 属性、纹理槽或关键词,若用户通过当前 Inspector 保存一次,该材质源文件就可能被覆盖成一个严重简化后的版本,导致正式材质数据丢失。
11.3 当前 Inspector 的实时写回同样不完整
当前 ApplyResolvedMaterialStateToResource() 仅把面板状态写回到运行时 Material 的以下部分:
SetShaderSetRenderQueueSetRenderStateClearTags/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 / semanticShader已提供GetProperties()/FindProperty()/ keyword declaration 能力Material已提供完整的SetFloat/SetInt/SetBool/SetTexture...Material已支持 Shader schema 默认值同步MaterialLoader已支持解析properties / textures / keywords / tags / renderState- material artifact 当前已支持这些正式数据的持久化
也就是说,当前问题的主要矛盾不在资源系统,而在 Editor 侧没有接入正式模型。
11.6 当前阶段的根本性结论
下一阶段不能直接在现有材质面板上继续堆控件。
必须先完成:
MaterialAssetState的正式重构- Save/Reload/Apply 链路对
properties / textures / keywords / renderState override的建模 - Inspector 与运行时
Material之间的一致性重建
只有先做完这些,后续的 Shader schema 驱动属性 UI 才不会继续建立在错误基础上。
11.7 Phase 2 的直接执行范围
基于本阶段审查结果,下一阶段将直接进入以下工作:
- 扩展
MaterialAssetState,让其正式承载属性、纹理槽、关键词与 render state override。 - 重构
Populate / Apply / Save / Reload这四条关键链路。 - 彻底消除当前“保存一次就丢属性”的结构性问题。
12. Phase 2 执行结果
状态:已完成
本阶段已经完成 Material Inspector 数据模型的第一轮正式收口,重点是先把状态模型与保存链路做正确,而不是提前堆属性 UI。
12.1 已完成内容
MaterialAssetState已扩展为正式承载:keywordspropertiestexture bindingsrenderState override
PopulateMaterialAssetStateFromResource()已从运行时Material同步:- Shader 路径
- Render Queue
- Render State
- Render State Override 标志
- Tags
- Keywords
- Properties / Texture Bindings
ApplyResolvedMaterialStateToResource()已开始完整写回:- Shader
- Render Queue
- Render State
- Render State Override
- Tags
- Keywords
- Properties / Texture Bindings
BuildMaterialAssetFileText()已开始正式写出:keywordspropertiestextures- 仅在启用 override 时才写
renderState
- Inspector 已增加
Render State Override开关,避免默认把材质强行推进到显式 override 路径。
12.2 本阶段解决的核心问题
本阶段已经解决了最危险的结构性问题:
- 当前 Inspector 再保存材质时,不会像之前那样天然丢掉
properties / textures / keywords。 - Render State 是否为显式 override,已经不再是隐藏副作用,而成为正式状态的一部分。
12.3 本阶段仍未完成的部分
以下能力还没有在本阶段完成,这是下一阶段的工作重点:
- 基于 Shader schema 的属性 UI 自动生成
- 各属性类型的可视化编辑控件
- 默认值/覆盖值的明确表现
- 纹理槽的正式资源选择 UI
- 关键词与属性在 Inspector 中的可视化编辑
因此,Phase 2 的性质是“先把材质状态模型与保存链路做对”,而不是“材质面板功能已经完整”。
13. Phase 3 执行结果
状态:已完成
本阶段已经开始把正确的材质状态模型真正暴露到 Inspector 上,重点是基于 Shader schema 生成属性面板,并处理 Shader 切换时的状态重建。
13.1 已完成内容
- Inspector 已新增
Properties区块。 - 属性区会基于当前 Shader 的 schema 动态生成,而不是写死字段。
- 当前已接入的属性类型包括:
Float / RangeIntColorVectorTexture2D / TextureCube
- Texture 类型已接入资源选择控件,不再只是文本占位。
- 每个属性当前会直接显示 Shader 中声明的默认值文本,作为当前参数的基线提示。
13.2 Shader 切换行为已收口
本阶段同时处理了一个关键一致性问题:
- 当用户切换 Shader 时,Inspector 会先基于新 Shader schema 重建
MaterialAssetState - 能与新 Shader 对齐的同名属性会尽量保留原值
- 已不被新 Shader 声明的旧属性不会继续残留在保存结果里
- 与新 Shader 不匹配的旧关键词也会被清理
这样可以避免旧材质属性被继续写回到新 Shader 材质文件中,从而减少生成无效材质源文件的风险。
13.3 本阶段仍未完成的部分
以下内容还需要后续阶段继续收口:
- 属性默认值与显式覆盖值的正式“重置/回退”交互
- 关键词的可视化编辑 UI
- 更完整的属性类型与显示策略细化
- 针对 Inspector 材质链路的专门自动化测试
因此,Phase 3 的完成标准是“Shader schema 驱动的属性面板已经建立起来”,但还不是最终形态。
14. Phase 4 执行结果
状态:已完成
本阶段重点处理的是 authoring-state 与 runtime-state 的一致性问题,避免 Inspector 因为单纯从运行时对象反推而破坏材质源文件的语义。
14.1 已完成内容
- Inspector 现在会回读材质源文件中实际 authored 的:
propertiestextureskeywordsrenderState
- 材质状态中已加入“是否需要序列化回源文件”的 authored 标记。
- 保存材质时,不再无条件把所有运行时属性都写回源文件。
- 对于未在源文件中显式 authored 的属性,当前会继续保持“继承 Shader 默认值”的语义。
- 当用户在 Inspector 中修改属性或贴图后,对应项才会被标记为显式 authored 并写回源文件。
14.2 本阶段解决的核心问题
本阶段解决的是一个架构层面的隐患:
- 如果只从运行时
Material反推回材质源文件,打开并保存一次材质,就会把 Shader 默认值全部固化进.mat。 - 一旦默认值被固化,后续 Shader 默认值再调整,材质就不再继承新的默认值。
当前这条链路已经收口到更合理的状态:
- 只有显式 authored 的 override 才会写回
- 默认值仍然可以继续作为 Shader 侧的基线被继承
14.3 本阶段仍未完成的部分
以下内容仍然需要下一阶段继续完成:
- 针对 Inspector 材质链路的专门自动化测试
- 属性“重置到默认值”的正式交互
- 关键词的可视化编辑 UI
- 更完整的属性类型/显示策略覆盖
因此,Phase 4 的性质是“先把 authoring 语义做正确”,为最后的测试与收口创造条件。
15. Phase 5 执行结果
状态:已完成
本阶段重点不是继续扩材质面板功能,而是把已经形成的正式链路变成“可持续回归验证”的状态,并把测试面收口到 Inspector 实际依赖的核心逻辑上。
15.1 已完成内容
- 新增
MaterialInspectorMaterialState/MaterialInspectorMaterialStateIO辅助模块,承载:- Material Inspector 状态结构
- source authored presence 解析
- Shader 切换时的属性/关键词重同步
- 材质源文件序列化文本生成
- 新增
tests/editor/test_material_inspector_material_state_io.cpp,覆盖:- authored 属性/纹理/关键词标记识别
- Shader 切换时保留兼容 override、清理陈旧字段
- 非 authored 默认值不写回源文件
- 纹理 override 与 render state override 的正式序列化
editor_tests构建链路已接入上述 helper 与新测试文件。
15.2 已执行验证
cmake --build build --config Debug --target XCEditor -j 8cmake --build build --config Debug --target editor_tests -- /v:minimalbuild/tests/Resources/Material/Debug/material_tests.exebuild/tests/Core/Asset/Debug/asset_tests.exebuild/tests/Editor/Debug/editor_tests.exe --gtest_filter=MaterialInspectorMaterialStateIOTest.*
验证结果:
XCEditor编译通过material_tests:61 / 61 通过asset_tests:56 / 56 通过MaterialInspectorMaterialStateIOTest:4 / 4 通过
15.3 当前剩余风险
- 全量
editor_tests.exe在顺序执行EditorActionRoutingTest.*时仍存在既有的共享状态级别挂起现象。 - 该挂起并非本次新增的材质面板测试本身触发:
- 新增
MaterialInspectorMaterialStateIOTest单独执行通过 EditorActionRoutingTest.PlayModeAllowsRuntimeSceneUndoRedoButKeepsSceneDocumentCommandsBlocked单独执行通过
- 新增
- 因此,本阶段围绕 Material Inspector / Shader 属性面板的测试收口已经完成,但 Editor 其余历史测试链路仍需单独排查。