Files
XCEngine/docs/used/Renderer阶段收口_旧兼容路径清理与正式化计划_完成归档_2026-04-08.md

15 KiB
Raw Blame History

Renderer阶段收口旧兼容路径清理与正式化计划

日期:2026-04-08

1. 背景

当前 Rendering 模块的主执行架构已经基本成型:

  • RenderSceneExtractor
  • SceneRenderRequestPlanner
  • SceneRenderer / CameraRenderer
  • built-in forward / shadow / object-id / outline / final-color / skybox

这些主链路已经能稳定支撑:

  • runtime 场景渲染
  • editor scene/game viewport
  • 多光源、阴影、object-id、outline、skybox 等现有能力

因此,当前 Rendering 的主要问题已经不再是“能不能画出来”,而是:

  • 还残留一些旧路线兼容代码
  • 一些 built-in 运行契约仍然依赖隐式推断
  • 少量路径仍然带有明显的过渡期实现痕迹

如果这些问题不在当前阶段彻底收口,后续继续推进:

  • Renderer 模块扩展
  • Material / Shader editor
  • Unity 风格 SRP 底层承接

就会持续建立在一层“虽然能跑,但不是正式规则”的兼容逻辑之上。

这不符合当前阶段的目标。

当前阶段的正确方向不是新增更多渲染功能,而是:

  • 清理旧兼容路径
  • 去掉运行时语义猜测
  • 把 built-in shader / material / pass contract 进一步正式化

2. 当前已确认的问题

基于本轮对 engine/include/XCEngine/Renderingengine/src/Renderingengine/src/Resources/Shaderengine/src/Resources/Mesh 的代码审查,当前确认存在以下问题。

2.1 Mesh 导入仍可生成“无 shader / 无 schema”的旧材质路线

当前 MeshLoader 导入子材质时,仍然直接写入:

  • baseColor
  • baseColorTexture
  • opacity
  • twoSided

而不是直接落到正式 shader schema 对应的属性名与纹理槽位。

这导致 runtime 渲染阶段仍然需要兜底兼容这些旧名字。

典型位置:

  • engine/src/Resources/Mesh/MeshLoader.cpp
  • engine/include/XCEngine/Rendering/Materials/RenderMaterialResolve.h

2.2 Rendering 仍通过属性别名表推断 built-in 材质语义

当前 RenderMaterialResolve.h 中,仍然保留了大量 builtin 属性/纹理别名表,例如:

  • baseColor
  • _BaseColor
  • color
  • _Color
  • baseColorTexture
  • _BaseColorTexture
  • _MainTex
  • texture

这意味着 runtime 当前并不是“按 shader schema 正式解析”,而是:

  • 优先找 semantic
  • 找不到就继续按一批旧属性名字猜

这属于典型过渡兼容逻辑,不应成为正式长期实现。

2.3 BuiltinForward / Depth / Shadow 仍存在 per-material fallback constant 路线

当前如果材质没有正式 schema constant layout管线仍会临时构造

  • FallbackPerMaterialConstants

并继续提交 draw。

这说明 runtime 仍允许“非正式材质实例”继续进入正式绘制链路。

这条路径虽然提高了兼容性,但本质上绕开了已经建立的 shader/material 正式模型。

2.4 Built-in pass resource binding 仍依赖隐式硬编码

当前 builtin shader pass 如果未显式声明 resources,运行时仍会通过:

  • TryBuildImplicitBuiltinPassResourceBindings

自动补一套绑定布局。

这意味着资源绑定契约并不完全存在于 shader 资产中,而是仍有一部分硬编码在 C++ 中。

这会带来两个问题:

  1. shader 资产与 runtime 存在双份真相
  2. 后续继续演进 shader/material/editor 时,容易再次产生隐式规则

2.5 HLSL register 重写仍保留 legacy alias

当前 ShaderVariantUtils.h 仍保留:

  • ResolveLegacyHlslBindingDeclarationAlias

以及基于 gBaseColorTexture / gLinearSampler 一类旧命名的重写逻辑。

这说明 shader runtime 编译阶段仍在兼容旧命名风格。

这属于典型“过渡兼容层”,应在 built-in shader 显式资源契约完成后清掉。

2.6 Built-in pass 选择仍存在隐式默认规则

当前如果 shader 没有显式 builtin metadataMatchesBuiltinPass(...) 仍会把它默认当成:

  • ForwardLit

这意味着 shader 即使没有明确声明自己属于哪个 built-in pass也有可能继续进入主几何管线。

这不利于长期正式化。

2.7 Shader artifact 仍兼容多代旧 schema

当前 shader artifact loader 仍兼容:

  • XCSHD01
  • XCSHD02
  • XCSHD03
  • XCSHD04
  • 当前 schema

但 shader artifact 本质上是 Library 中的可重建中间产物,不属于必须长期 runtime 兼容的用户资产格式。

如果继续保留多代 schema 分支,会让 shader 资源链路长期背着历史包袱。


3. 本阶段设计原则

本计划执行时,必须严格遵守以下原则。

3.1 正式路径只能有一条

对 built-in shader / material / pass 来说,正式路径必须是:

导入/authoring -> shader schema -> material instance -> explicit pass contract -> render pipeline

不能继续允许 runtime 依赖旧命名、旧别名、旧格式去自动猜测。

3.2 兼容应尽量前移到导入/重建阶段,而不是留在 runtime

如果确实存在历史资产问题,应优先采用:

  • 重新导入
  • 重新生成 artifact
  • 一次性迁移

而不是继续在 runtime loader / renderer 中保留长期兼容分支。

3.3 Built-in shader 契约必须显式写进 shader 资产

以下内容必须属于 shader/pass 资产本身,而不是 runtime 猜出来:

  • pass 类型
  • pass metadata
  • resource binding
  • property semantic

3.4 Rendering 不再为“无正式 shader/schema 的材质”兜底渲染

当前阶段的目标是“收口”,不是“继续最大化兼容”。

因此:

  • 非正式材质应尽快在导入层修正
  • runtime 应逐步拒绝无 schema 的正式绘制路径

3.5 每一步都必须可验证

每个阶段完成后必须配套:

  • unit test
  • 必要的 integration test
  • editor 编译/回归

不能只凭画面“看起来没问题”判断完成。


4. 本阶段目标

本阶段完成后Rendering 模块应达到以下状态:

  1. Mesh 导入出来的材质直接走正式 shader/material 体系
  2. runtime 不再依赖 baseColor / _MainTex 等别名表去维持 built-in 主链
  3. built-in pass resource binding 由 shader 资产显式声明,不再依赖隐式硬编码补全
  4. built-in pass 分类必须显式声明,不再存在“默认 ForwardLit”
  5. shader artifact runtime loader 不再长期兼容多代旧 schema
  6. 对应测试体系同步升级,保证收口后功能不回退

5. 明确不在本阶段处理的内容

以下内容不属于本阶段目标:

  • render graph
  • deferred renderer
  • 新一轮后处理功能扩展
  • C# SRP 脚本侧 API
  • ShaderGraph
  • 高级材质编辑器功能扩展

这些方向都依赖本阶段先把底层 contract 收紧。


6. 分阶段执行计划

Phase 1建立基线与目标测试

目标

先把当前遗留兼容路径的行为边界用测试钉住,并同步写出“目标行为”的新测试。

任务

  • 审查并整理当前覆盖以下行为的测试:
    • RenderMaterialResolve
    • builtin forward pipeline resource binding
    • mesh material import
    • shader artifact load
  • 新增/调整测试,使其明确区分:
    • 当前历史兼容行为
    • 本阶段目标正式行为
  • 对以下目标先写失败测试或待切换测试:
    • imported mesh material 必须绑定正式 builtin shader
    • imported material property 必须落到正式 schema 名称
    • builtin pass 若无显式 metadata不得进入主 pipeline
    • builtin shader 若无显式 resources不得依赖隐式 binding 补全

验收标准

  • 能清楚列出哪些测试在保护旧行为,哪些测试在保护目标行为
  • 后续每个阶段都能基于这些测试判断是否真正收口

Phase 2收口 Mesh 导入材质到正式 shader/material 路径

目标

彻底去掉 imported mesh material 的“无 shader / 裸属性名”旧路线。

任务

  • 调整 MeshLoader 导入逻辑:
    • imported material 直接绑定正式 builtin shader
    • 默认按现有主线落到 builtin lit/forward 合同
  • 导入属性与纹理时,直接写正式 property name / texture slot
    • 例如 _BaseColor
    • _MainTex
    • _Cutoff
    • 其他已正式声明的 builtin 属性
  • 不再向 imported material 写入仅靠 runtime 别名识别的裸字段:
    • baseColor
    • baseColorTexture
    • color
    • texture
  • 更新 mesh import 相关测试、render extractor 测试、相关 integration 资源测试

验收标准

  • mesh import 结果中的材质都带有正式 shader 引用
  • mesh import 结果中的属性/纹理绑定名称与 shader schema 对齐
  • 不再需要 runtime 靠旧别名才能让导入材质正常渲染

Phase 3移除 runtime builtin 材质语义别名与 fallback 常量路径

目标

让 built-in pipeline 只吃正式 schema 材质,不再继续兼容旧材质命名。

任务

  • 清理 RenderMaterialResolve.h 中的旧别名解析表:
    • base color property alias
    • base texture alias
    • skybox texture alias
    • alpha cutoff alias
  • 保留并强化基于 shader property semantic 的正式解析路径
  • 移除 FallbackPerMaterialConstants 路线
  • 当材质未携带正式 schema constant layout 时:
    • 显式报错 / 记录诊断
    • 拒绝进入需要正式材质常量的绘制路径
  • 调整 forward / depth / shadow / skybox 相关单测

验收标准

  • builtin pipeline 不再依赖属性别名表维持主链
  • builtin pipeline 不再手工构造 per-material fallback constant 继续绘制
  • runtime 只接受正式 shader/material 契约

Phase 4显式化 builtin pass resource binding contract

目标

让 builtin shader pass 的资源绑定契约完全存在于 shader 资产中,而不是藏在 runtime 硬编码里。

任务

  • 为所有 builtin shader pass 补齐显式 resources 描述
  • 覆盖至少以下 shader
    • forward-lit.shader
    • depth-only.shader
    • shadow-caster.shader
    • object-id.shader
    • skybox.shader
    • final-color.shader
    • 其他当前仍在主链中的 builtin shader
  • 清理 TryBuildImplicitBuiltinPassResourceBindings
  • 清理 ShaderVariantUtils.h 中围绕 implicit/legacy binding 的兼容逻辑:
    • legacy alias register rewrite
    • 依赖 gXxx 名称重写的分支
  • 调整 shader loader / rendering pipeline / builtin pass 单测

验收标准

  • builtin shader pass 缺少显式资源绑定时,构建或运行应明确失败
  • runtime 不再替 shader 资产自动补 binding layout
  • HLSL runtime 编译不再依赖 legacy alias register 重写

Phase 5显式化 builtin pass metadata 与 pass 选择规则

目标

去掉“默认 ForwardLit”一类隐式 pass 归类规则。

任务

  • 收紧 BuiltinPassMetadataUtils
    • built-in pass 匹配必须依赖显式 pass name / tag
    • 删除“无 metadata 默认归 ForwardLit”的逻辑
  • 审查并统一 builtin shader 的 pass metadata
    • Name
    • LightMode
    • 其它当前正式要求的 tag
  • 对进入 builtin 主线的 shader 建立硬约束:
    • 没有显式 builtin metadata 的 shader不得继续被当作主几何 shader 使用
  • 更新 pass 匹配测试和 shader authoring 测试

验收标准

  • builtin pass 选择全部基于显式 metadata
  • 不存在 runtime 默认猜一个 pass 类型的行为

Phase 6清理旧 shader artifact schema 兼容

目标

让 shader artifact runtime loader 与 material artifact 一样,收口到 current schema。

任务

  • 清理 ShaderArtifactLoader.cpp 中对旧 schema 的分支兼容:
    • XCSHD01
    • XCSHD02
    • XCSHD03
    • XCSHD04
  • 将旧 Library artifact 的处理方式改为:
    • 识别为过期
    • 触发重新导入 / 重新生成
    • 或直接报错要求重建 Library
  • 更新 asset database / shader load 相关测试
  • 明确记录此阶段会带来的影响:
    • Library 无法直接沿用
    • 需要一次性刷新或重建

验收标准

  • shader artifact loader 只接受 current schema
  • 对旧 artifact 的处理边界清晰且可测试

Phase 7全量验证与阶段收口

目标

确认 Rendering 在去掉旧兼容层之后没有破坏现有功能。

任务

  • 编译并运行:
    • material_tests
    • rendering_unit_tests
    • asset_tests
    • editor_tests
    • 受影响的 mesh/shader 资源测试
  • 重新编译 XCEditor
  • 重点回归:
    • scene viewport
    • game viewport
    • object-id picking
    • selection outline
    • skybox
    • 阴影
    • 多光源
    • backpack / sphere / quad 等 integration scene
  • 形成阶段收口报告

验收标准

  • 所有直接相关测试通过
  • editor 编译通过
  • 关键 integration scene 渲染行为不回退
  • 能明确宣告 runtime 旧兼容路径已移除

7. 风险与注意事项

7.1 这是一次“切正式路径”的收口,不是小修小补

本计划一旦执行,就会主动删除一部分兼容逻辑。

因此不能以“尽量少改代码”为目标,而应以:

  • 正式路径唯一
  • contract 清晰
  • 后续 SRP 可承接

为目标。

7.2 Library 重建属于预期影响

一旦收掉旧 shader artifact schema 兼容,旧 Library 里的 shader artifact 失效是正常现象。

这不应被视为回归,而应被视为阶段性收口的合理代价。

7.3 必须避免引入新的“临时兼容层”

执行过程中需要特别警惕以下错误做法:

  • 新加一层 alias 表,试图“先兼容一下”
  • 把 runtime fallback 换个名字继续保留
  • 在 editor 或 import 层再次引入一套过渡数据模型

如果遇到结构性问题,正确做法是:

  • 直接改到正式模型
  • 同步补测试

而不是再加一层短期兜底。


8. 建议执行顺序

建议严格按以下顺序推进:

  1. Phase 1 测试基线整理
  2. Phase 2 mesh 导入材质正式化
  3. Phase 3 runtime 材质别名与 fallback 常量清理
  4. Phase 4 builtin pass 显式资源绑定
  5. Phase 5 builtin pass metadata 显式化
  6. Phase 6 shader artifact schema 收口
  7. Phase 7 全量验证

原因是:

  • 如果不先把 imported material 拉回正式路径
  • 后面的 runtime alias / fallback 清理就一定会打断现有资源链路

9. 本阶段完成后的预期状态

本计划完成后Rendering 模块应达到以下状态:

  1. built-in shader/material/pass contract 全部走正式显式路径
  2. runtime 不再依赖旧命名猜测材质语义
  3. runtime 不再替非正式材质拼接 fallback 常量布局
  4. builtin shader 资源绑定契约完全由 shader 资产声明
  5. builtin pass 类型选择完全依赖显式 metadata
  6. shader artifact runtime loader 不再背负旧 schema 包袱
  7. 整个 Rendering 模块更适合作为后续 Unity 风格 SRP 的底层承接

10. 一句话总结

当前 Rendering 真正需要的不是继续加功能,而是把残留的旧兼容路径彻底拔干净。

这一阶段的本质,是把:

  • imported material
  • built-in shader binding
  • pass metadata
  • shader artifact

全部拉回到同一套正式 contract 上,为后续 Renderer / Material / Shader / SRP 的继续推进打地基。