842 lines
20 KiB
Markdown
842 lines
20 KiB
Markdown
|
|
# Renderer 下一阶段:Unity 风格 Shader 体系正式化计划
|
|||
|
|
|
|||
|
|
日期:`2026-04-06`
|
|||
|
|
|
|||
|
|
## 1. 阶段结论
|
|||
|
|
|
|||
|
|
当前 renderer 主线已经可以阶段性收口,但 `Shader / Material / Pass` 体系还没有真正统一。
|
|||
|
|
|
|||
|
|
现在仓库里的 shader 体系处于一个过渡态:
|
|||
|
|
|
|||
|
|
- 逻辑上已经有 `Shader -> Pass -> Variant` 模型
|
|||
|
|
- authoring 外观上已经接近 Unity ShaderLab
|
|||
|
|
- 运行时已经能按 pass 和 backend variant 选择 shader
|
|||
|
|
- 三后端已经能稳定跑通 builtin shader
|
|||
|
|
|
|||
|
|
但它仍然不是 Unity 风格的正式体系,因为当前 authoring 仍然暴露了太多 backend 与 binding 细节:
|
|||
|
|
|
|||
|
|
- `.shader` 文件里仍然显式写 `#pragma backend D3D12/OpenGL/Vulkan`
|
|||
|
|
- `.shader` 文件里仍然显式写 `Resources { name(type, set, binding) }`
|
|||
|
|
- material 仍然可以显式指定 `shaderPass`
|
|||
|
|
- shader 关键字、变体、include、pass state、SubShader 选择还没有真正成体系
|
|||
|
|
|
|||
|
|
所以这一阶段的主线不是继续做新渲染效果,而是把 shader 体系升级成:
|
|||
|
|
|
|||
|
|
- **authoring 层完全按 Unity 风格书写**
|
|||
|
|
- **三后端编译路径统一收敛到 importer / compiler 层**
|
|||
|
|
- **runtime 只消费正式 shader artifact / material contract**
|
|||
|
|
|
|||
|
|
这一步不是 SRP 本身,但它是后续 SRP 能否成立的硬地基。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 2. 阶段目标
|
|||
|
|
|
|||
|
|
本阶段要达成的核心目标只有一件事:
|
|||
|
|
|
|||
|
|
**把当前“伪 ShaderLab + 后端直连”的过渡体系,升级为“Unity 风格 authoring + 引擎内部统一 shader IR + 三后端编译产物”的正式体系。**
|
|||
|
|
|
|||
|
|
完成后应达到:
|
|||
|
|
|
|||
|
|
1. shader authoring 采用 Unity 风格 `.shader` 语法,不再要求作者显式写 backend variant 分发表。
|
|||
|
|
2. 新语法不再要求作者手写 `set/binding` 级资源绑定表。
|
|||
|
|
3. HLSL 成为 raster shader 的单一 authoring 语言源。
|
|||
|
|
4. D3D12 / Vulkan / OpenGL 的差异退到 importer / compiler / artifact 层。
|
|||
|
|
5. material 只管 property / keyword / texture / render state,不再负责点名 pass。
|
|||
|
|
6. renderer 按 `LightMode` / pass contract 选 pass,而不是靠 material 的临时字符串兜底。
|
|||
|
|
7. builtin shader 全部迁移到新体系并保持三后端回归稳定。
|
|||
|
|
8. 保留 legacy shader 兼容层,避免一次性炸掉现有工程内容。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 3. 非目标
|
|||
|
|
|
|||
|
|
本阶段明确不做:
|
|||
|
|
|
|||
|
|
- SRP 本体
|
|||
|
|
- render graph
|
|||
|
|
- deferred / clustered
|
|||
|
|
- Shader Graph
|
|||
|
|
- Surface Shader
|
|||
|
|
- 完整 Unity ShaderLab 100% 全语法一次性覆盖
|
|||
|
|
- volume 系统
|
|||
|
|
- 更多新渲染效果
|
|||
|
|
|
|||
|
|
本阶段也不追求一口气把 Unity 的所有 authoring 特性补完,例如:
|
|||
|
|
|
|||
|
|
- `Fallback`
|
|||
|
|
- `UsePass`
|
|||
|
|
- `CustomEditor`
|
|||
|
|
- `GrabPass`
|
|||
|
|
- tessellation / geometry / ray tracing authoring
|
|||
|
|
|
|||
|
|
这些可以后续补,但不应阻塞当前阶段把“统一 shader 体系”先做正确。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 4. 当前真实状态与根本问题
|
|||
|
|
|
|||
|
|
### 4.1 当前已经具备的能力
|
|||
|
|
|
|||
|
|
当前工程已经具备:
|
|||
|
|
|
|||
|
|
- `.shader` 文件解析能力
|
|||
|
|
- `Shader` 的 pass / property / resource / variant 数据模型
|
|||
|
|
- builtin shader 资产化
|
|||
|
|
- material property / texture / render state / tag 载体
|
|||
|
|
- renderer 中按 builtin pass metadata 选择可用 shader pass
|
|||
|
|
|
|||
|
|
这意味着当前不是从零开始设计。
|
|||
|
|
|
|||
|
|
### 4.2 当前最根本的问题
|
|||
|
|
|
|||
|
|
当前最大的问题不是“没有 shader 体系”,而是“authoring 层和 runtime 层的边界还没收干净”。
|
|||
|
|
|
|||
|
|
具体表现为:
|
|||
|
|
|
|||
|
|
1. **authoring 层暴露后端差异**
|
|||
|
|
- `.shader` 文件直接写 `#pragma backend D3D12/OpenGL/Vulkan`
|
|||
|
|
- shader 作者必须知道后端与源码文件映射
|
|||
|
|
|
|||
|
|
2. **authoring 层暴露 RHI binding 细节**
|
|||
|
|
- `.shader` 文件显式写 `Resources { ConstantBuffer / Texture2D / Sampler, set, binding }`
|
|||
|
|
- 这更像 Vulkan/D3D12 binding 清单,不是 Unity 风格 shader authoring
|
|||
|
|
|
|||
|
|
3. **material 还带着临时 pass 选择职责**
|
|||
|
|
- `Material::SetShaderPass()` 仍然存在
|
|||
|
|
- renderer 仍然优先吃 material 显式指定的 pass
|
|||
|
|
- 这会阻碍未来 RendererFeature / SRP 规范化
|
|||
|
|
|
|||
|
|
4. **关键字与变体体系缺失**
|
|||
|
|
- 没有正式的 `multi_compile / shader_feature`
|
|||
|
|
- 没有变体剥离与编译缓存策略
|
|||
|
|
|
|||
|
|
5. **include 与共享库体系缺失**
|
|||
|
|
- 没有正式的 shader include 搜索路径、预处理、公共库组织
|
|||
|
|
|
|||
|
|
6. **pass state 仍然不在 shader authoring 的统一语义内**
|
|||
|
|
- 诸如 `Cull / ZWrite / ZTest / Blend / ColorMask / Stencil` 还没有完整进入 shader authoring contract
|
|||
|
|
|
|||
|
|
7. **三后端仍然是物理三套源码直连**
|
|||
|
|
- 当前虽然“逻辑上一个 shader asset”
|
|||
|
|
- 但作者本质上还在维护三套 shader stage 文件
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 5. 核心设计结论
|
|||
|
|
|
|||
|
|
### 5.1 目标不是“看起来像 Unity”,而是“真正采用 Unity 风格 authoring 模型”
|
|||
|
|
|
|||
|
|
最终目标应当是:
|
|||
|
|
|
|||
|
|
- 一个 `.shader` 文件描述一个逻辑 shader
|
|||
|
|
- shader 内部有 `Properties / SubShader / Pass / Tags / State / Program`
|
|||
|
|
- renderer 消费的是 import 后的统一 IR / artifact
|
|||
|
|
- backend 差异不暴露给 shader 作者
|
|||
|
|
|
|||
|
|
### 5.2 HLSL 作为单一 authoring 语言源
|
|||
|
|
|
|||
|
|
本阶段必须明确:
|
|||
|
|
|
|||
|
|
- **新体系下 raster shader 统一使用 HLSL authoring**
|
|||
|
|
- D3D12 直接编 HLSL
|
|||
|
|
- Vulkan 由 HLSL 编到 SPIR-V
|
|||
|
|
- OpenGL 由 HLSL 编到 SPIR-V,再转 GLSL 430
|
|||
|
|
|
|||
|
|
原因:
|
|||
|
|
|
|||
|
|
- 如果 authoring 仍然保留 GLSL/HLSL 三套并行,永远不可能真正统一写法
|
|||
|
|
- 只有 single-source authoring,才能接近 Unity 的真实体验
|
|||
|
|
|
|||
|
|
### 5.3 backend 差异必须退到 importer / compiler 层
|
|||
|
|
|
|||
|
|
新 authoring 文件中不应再出现:
|
|||
|
|
|
|||
|
|
- `#pragma backend ...`
|
|||
|
|
- backend 专属 stage 文件路径表
|
|||
|
|
|
|||
|
|
这些内容应由 importer 根据 target backend 生成产物。
|
|||
|
|
|
|||
|
|
### 5.4 resource binding 不再由 shader 作者手写 `Resources(set,binding)`
|
|||
|
|
|
|||
|
|
Unity 风格 shader authoring 不要求作者手写 descriptor set / binding。
|
|||
|
|
|
|||
|
|
因此新体系下应改为:
|
|||
|
|
|
|||
|
|
- material 暴露属性来自 `Properties`
|
|||
|
|
- engine 内建 constant buffer / texture / sampler 来自约定与 reflection
|
|||
|
|
- importer 通过 HLSL reflection + 约定库推导 runtime resource layout
|
|||
|
|
|
|||
|
|
也就是说:
|
|||
|
|
|
|||
|
|
- authoring 层写“语义”
|
|||
|
|
- importer 层生成“绑定布局”
|
|||
|
|
- runtime 层消费“绑定布局”
|
|||
|
|
|
|||
|
|
### 5.5 pass 选择必须回归 renderer,而不是 material
|
|||
|
|
|
|||
|
|
新体系中:
|
|||
|
|
|
|||
|
|
- material 只绑定 shader 与 property / keyword / texture
|
|||
|
|
- renderer 按 `LightMode` 选 pass
|
|||
|
|
- `Material::shaderPass` 进入弃用与最终移除路径
|
|||
|
|
|
|||
|
|
这与 Unity 的 `ShaderTagId / LightMode` 思路对齐,也更利于未来 SRP。
|
|||
|
|
|
|||
|
|
### 5.6 必须保留 legacy 兼容层
|
|||
|
|
|
|||
|
|
当前仓库已经有一批 builtin shader 和测试资产。
|
|||
|
|
|
|||
|
|
因此不能激进地“一刀切重做”,而应:
|
|||
|
|
|
|||
|
|
- legacy `.shader` 继续可加载
|
|||
|
|
- 新 Unity 风格 `.shader` 进入新 importer 路径
|
|||
|
|
- builtin shader 分批迁移
|
|||
|
|
- runtime 统一落在同一套 `Shader` / artifact / variant 模型上
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 6. 目标架构
|
|||
|
|
|
|||
|
|
建议把 shader 体系正式分成 5 层。
|
|||
|
|
|
|||
|
|
### 6.1 Authoring 层
|
|||
|
|
|
|||
|
|
职责:
|
|||
|
|
|
|||
|
|
- 让开发者以 Unity 风格书写 shader
|
|||
|
|
|
|||
|
|
建议语法子集:
|
|||
|
|
|
|||
|
|
- `Shader`
|
|||
|
|
- `Properties`
|
|||
|
|
- `SubShader`
|
|||
|
|
- `Pass`
|
|||
|
|
- `Tags`
|
|||
|
|
- `LOD`
|
|||
|
|
- `HLSLINCLUDE`
|
|||
|
|
- `HLSLPROGRAM`
|
|||
|
|
- `ENDHLSL`
|
|||
|
|
- `#pragma vertex`
|
|||
|
|
- `#pragma fragment`
|
|||
|
|
- `#pragma target`
|
|||
|
|
- `#pragma multi_compile`
|
|||
|
|
- `#pragma shader_feature`
|
|||
|
|
- `#pragma shader_feature_local`
|
|||
|
|
- `Cull`
|
|||
|
|
- `ZWrite`
|
|||
|
|
- `ZTest`
|
|||
|
|
- `Blend`
|
|||
|
|
- `ColorMask`
|
|||
|
|
- `Stencil`
|
|||
|
|
- `Offset`
|
|||
|
|
|
|||
|
|
### 6.2 Importer / Parser 层
|
|||
|
|
|
|||
|
|
职责:
|
|||
|
|
|
|||
|
|
- 解析 Unity 风格 `.shader`
|
|||
|
|
- 生成统一的内部 `ShaderIR`
|
|||
|
|
|
|||
|
|
建议引入:
|
|||
|
|
|
|||
|
|
- `ShaderAuthoringParser`
|
|||
|
|
- `ShaderIR`
|
|||
|
|
- `ShaderSubShaderIR`
|
|||
|
|
- `ShaderPassIR`
|
|||
|
|
- `ShaderKeywordDecl`
|
|||
|
|
- `ShaderPassStateDesc`
|
|||
|
|
- `ShaderProgramIR`
|
|||
|
|
|
|||
|
|
### 6.3 Compiler / Reflection 层
|
|||
|
|
|
|||
|
|
职责:
|
|||
|
|
|
|||
|
|
- 编译 authoring 中的 HLSL
|
|||
|
|
- 为不同 backend 生成最终编译产物
|
|||
|
|
- 生成 resource layout / constant layout / keyword variant metadata
|
|||
|
|
|
|||
|
|
建议技术路径:
|
|||
|
|
|
|||
|
|
- D3D12:`DXC -> DXIL/DXBC`
|
|||
|
|
- Vulkan:`DXC -> SPIR-V`
|
|||
|
|
- OpenGL:`DXC -> SPIR-V -> SPIRV-Cross -> GLSL 430`
|
|||
|
|
|
|||
|
|
输出:
|
|||
|
|
|
|||
|
|
- 每个 pass / stage / keyword-set / backend 的编译产物
|
|||
|
|
- 反射出的 constant buffer / texture / sampler 布局
|
|||
|
|
|
|||
|
|
### 6.4 Artifact 层
|
|||
|
|
|
|||
|
|
职责:
|
|||
|
|
|
|||
|
|
- 保存运行时真正消费的 shader 产物
|
|||
|
|
|
|||
|
|
建议引入新版 artifact:
|
|||
|
|
|
|||
|
|
- `xcshader2` 或继续升级现有 `xcshader`
|
|||
|
|
|
|||
|
|
artifact 内容至少包含:
|
|||
|
|
|
|||
|
|
- shader 名称 / guid
|
|||
|
|
- properties
|
|||
|
|
- subshader / pass tags
|
|||
|
|
- pass state
|
|||
|
|
- keyword declarations
|
|||
|
|
- keyword variant table
|
|||
|
|
- backend binaries / backend source payload
|
|||
|
|
- reflected resource layout
|
|||
|
|
- include 依赖与 hash
|
|||
|
|
|
|||
|
|
### 6.5 Runtime 层
|
|||
|
|
|
|||
|
|
职责:
|
|||
|
|
|
|||
|
|
- renderer 根据 pass contract、keywords、backend 选择最终 variant
|
|||
|
|
- material 根据 property/texture 生成常量与资源绑定
|
|||
|
|
- pipeline cache 根据 shader variant + render state 建 key
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 7. Unity 风格 authoring 范围定义
|
|||
|
|
|
|||
|
|
### 7.1 第一阶段必须支持的语法
|
|||
|
|
|
|||
|
|
第一阶段建议正式支持:
|
|||
|
|
|
|||
|
|
```shaderlab
|
|||
|
|
Shader "XCEngine/Example/Lit"
|
|||
|
|
{
|
|||
|
|
Properties
|
|||
|
|
{
|
|||
|
|
_BaseColor ("Base Color", Color) = (1,1,1,1)
|
|||
|
|
_BaseMap ("Base Map", 2D) = "white" {}
|
|||
|
|
_Cutoff ("Alpha Cutoff", Range(0,1)) = 0.5
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
HLSLINCLUDE
|
|||
|
|
#include "ShaderLibrary/Core.hlsl"
|
|||
|
|
ENDHLSL
|
|||
|
|
|
|||
|
|
SubShader
|
|||
|
|
{
|
|||
|
|
Tags { "RenderType"="Opaque" "Queue"="Geometry" }
|
|||
|
|
LOD 200
|
|||
|
|
|
|||
|
|
Pass
|
|||
|
|
{
|
|||
|
|
Name "ForwardLit"
|
|||
|
|
Tags { "LightMode"="ForwardLit" }
|
|||
|
|
Cull Back
|
|||
|
|
ZWrite On
|
|||
|
|
ZTest LEqual
|
|||
|
|
Blend One Zero
|
|||
|
|
|
|||
|
|
HLSLPROGRAM
|
|||
|
|
#pragma target 4.5
|
|||
|
|
#pragma vertex Vert
|
|||
|
|
#pragma fragment Frag
|
|||
|
|
#pragma multi_compile _ XC_MAIN_LIGHT_SHADOWS
|
|||
|
|
#pragma shader_feature_local _ XC_ALPHA_TEST
|
|||
|
|
ENDHLSL
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 7.2 第一阶段暂不支持的语法
|
|||
|
|
|
|||
|
|
第一阶段可暂缓:
|
|||
|
|
|
|||
|
|
- `Fallback`
|
|||
|
|
- `UsePass`
|
|||
|
|
- `GrabPass`
|
|||
|
|
- `CustomEditor`
|
|||
|
|
- `Category`
|
|||
|
|
- `Dependency`
|
|||
|
|
- Surface Shader
|
|||
|
|
- CG fixed-function 时代遗留语义
|
|||
|
|
|
|||
|
|
这些需要列入兼容性说明,但不应阻塞首版落地。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 8. 统一的 shader library 与 include 体系
|
|||
|
|
|
|||
|
|
这一层是“写法统一”能否成立的关键。
|
|||
|
|
|
|||
|
|
### 8.1 必须引入正式的 include 库
|
|||
|
|
|
|||
|
|
建议新增:
|
|||
|
|
|
|||
|
|
- `engine/assets/shaderlib/ShaderLibrary/Core.hlsl`
|
|||
|
|
- `engine/assets/shaderlib/ShaderLibrary/Common.hlsl`
|
|||
|
|
- `engine/assets/shaderlib/ShaderLibrary/SpaceTransforms.hlsl`
|
|||
|
|
- `engine/assets/shaderlib/ShaderLibrary/Lighting.hlsl`
|
|||
|
|
- `engine/assets/shaderlib/ShaderLibrary/MaterialInput.hlsl`
|
|||
|
|
- `engine/assets/shaderlib/ShaderLibrary/Shadow.hlsl`
|
|||
|
|
|
|||
|
|
目标:
|
|||
|
|
|
|||
|
|
- builtin shader 共用统一宏与公共函数
|
|||
|
|
- authoring 层不再重复声明一堆 per-object / lighting 结构
|
|||
|
|
|
|||
|
|
### 8.2 统一的内建常量组
|
|||
|
|
|
|||
|
|
建议统一为接近 Unity 的内建分组:
|
|||
|
|
|
|||
|
|
- `UnityPerFrame` 或 `XCPerFrame`
|
|||
|
|
- `UnityPerCamera` 或 `XCPerCamera`
|
|||
|
|
- `UnityPerDraw` 或 `XCPerDraw`
|
|||
|
|
- `UnityPerMaterial` 或 `XCPerMaterial`
|
|||
|
|
|
|||
|
|
建议引擎内部最终保留 `XC*` 前缀实现名,但 authoring 宏层提供 Unity 风格别名。
|
|||
|
|
|
|||
|
|
### 8.3 内建纹理/采样器由 include 库与 reflection 管理
|
|||
|
|
|
|||
|
|
例如:
|
|||
|
|
|
|||
|
|
- 主纹理
|
|||
|
|
- 阴影图
|
|||
|
|
- 环境图
|
|||
|
|
- sampler state
|
|||
|
|
|
|||
|
|
这些都不再由 `.shader` 手填 `Resources(set,binding)`。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 9. Material 体系同步改造
|
|||
|
|
|
|||
|
|
shader 统一如果不带 material 一起改,最后会停在半路。
|
|||
|
|
|
|||
|
|
### 9.1 material 的职责边界
|
|||
|
|
|
|||
|
|
新体系里 material 负责:
|
|||
|
|
|
|||
|
|
- 选择 shader
|
|||
|
|
- 保存 property override
|
|||
|
|
- 保存 texture override
|
|||
|
|
- 保存 keyword 开关
|
|||
|
|
- 保存材质级 render queue / tag override(如保留)
|
|||
|
|
|
|||
|
|
新体系里 material 不再负责:
|
|||
|
|
|
|||
|
|
- 指定 `shaderPass`
|
|||
|
|
- 硬编码 backend 资源名
|
|||
|
|
- 猜测 shader 内的 descriptor set / binding
|
|||
|
|
|
|||
|
|
### 9.2 material constant buffer 正式化
|
|||
|
|
|
|||
|
|
必须建立:
|
|||
|
|
|
|||
|
|
- `Properties` -> `UnityPerMaterial/XCPerMaterial` 布局
|
|||
|
|
- importer 生成 property layout
|
|||
|
|
- material 按 layout 打包 GPU 常量
|
|||
|
|
- layout/hash 进入 pipeline/material cache key
|
|||
|
|
|
|||
|
|
### 9.3 keyword 体系正式化
|
|||
|
|
|
|||
|
|
建议引入:
|
|||
|
|
|
|||
|
|
- `global keywords`
|
|||
|
|
- `local keywords`
|
|||
|
|
- material keyword set
|
|||
|
|
- variant lookup key
|
|||
|
|
|
|||
|
|
material 应持有:
|
|||
|
|
|
|||
|
|
- `ShaderKeywordSet`
|
|||
|
|
|
|||
|
|
renderer 运行时根据:
|
|||
|
|
|
|||
|
|
- shader
|
|||
|
|
- pass
|
|||
|
|
- keyword set
|
|||
|
|
- backend
|
|||
|
|
|
|||
|
|
选择最终 shader variant。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 10. Renderer 运行时契约调整
|
|||
|
|
|
|||
|
|
### 10.1 pass 选择规则统一为 `LightMode`
|
|||
|
|
|
|||
|
|
renderer 选 pass 时只看:
|
|||
|
|
|
|||
|
|
- 当前 pipeline 阶段需要的 `LightMode`
|
|||
|
|
- shader/subshader/pass 是否匹配
|
|||
|
|
- backend 是否有有效 variant
|
|||
|
|
|
|||
|
|
例如:
|
|||
|
|
|
|||
|
|
- 主几何:`ForwardLit` / `Unlit`
|
|||
|
|
- 阴影:`ShadowCaster`
|
|||
|
|
- 深度:`DepthOnly`
|
|||
|
|
- ObjectId:`ObjectId`
|
|||
|
|
- FinalOutput:`FinalColor`
|
|||
|
|
|
|||
|
|
### 10.2 material 显式 `shaderPass` 进入弃用路径
|
|||
|
|
|
|||
|
|
建议执行顺序:
|
|||
|
|
|
|||
|
|
1. 第一阶段保留字段,但标记为 legacy
|
|||
|
|
2. runtime 优先按 pass contract / LightMode 选 pass
|
|||
|
|
3. 只有 legacy 资产才允许 fallback 到 `shaderPass`
|
|||
|
|
4. migration 完成后移除 `shaderPass` 主路径职责
|
|||
|
|
|
|||
|
|
### 10.3 builtin pass metadata 继续保留,但收进 importer/runtime
|
|||
|
|
|
|||
|
|
当前基于 semantic 的 builtin pass binding 解析仍然有价值,但应改成:
|
|||
|
|
|
|||
|
|
- authoring/IR 层表达语义
|
|||
|
|
- compiler/reflection 层生成 binding plan
|
|||
|
|
- runtime 只消费 binding plan
|
|||
|
|
|
|||
|
|
而不是继续靠散落的名字匹配和 fallback。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 11. 三后端统一策略
|
|||
|
|
|
|||
|
|
### 11.1 D3D12
|
|||
|
|
|
|||
|
|
目标:
|
|||
|
|
|
|||
|
|
- 直接消费 HLSL 编译产物
|
|||
|
|
- 反射得到 root signature / resource layout 所需元数据
|
|||
|
|
|
|||
|
|
第一阶段可继续沿用 `ps_5_0 / vs_5_0`,但建议同时规划升级:
|
|||
|
|
|
|||
|
|
- 后续逐步转 `SM 6.x`
|
|||
|
|
|
|||
|
|
### 11.2 Vulkan
|
|||
|
|
|
|||
|
|
目标:
|
|||
|
|
|
|||
|
|
- 统一吃由 HLSL 编到 SPIR-V 的产物
|
|||
|
|
- 摆脱独立 `.vk.glsl` 长期维护
|
|||
|
|
|
|||
|
|
### 11.3 OpenGL
|
|||
|
|
|
|||
|
|
目标:
|
|||
|
|
|
|||
|
|
- 不再长期维护独立 `.glsl` authoring 文件
|
|||
|
|
- importer 自动生成 OpenGL 目标 GLSL 430
|
|||
|
|
|
|||
|
|
这一步会是整个阶段最大的工程风险之一,但它是“写法统一”绕不开的核心点。
|
|||
|
|
|
|||
|
|
### 11.4 迁移期间的策略
|
|||
|
|
|
|||
|
|
在新体系落稳前,允许:
|
|||
|
|
|
|||
|
|
- legacy backend-specific variant 继续存在
|
|||
|
|
- 新 Unity 风格 shader 走统一 HLSL single-source 路径
|
|||
|
|
|
|||
|
|
两套 importer 并行一段时间,最终再逐步淘汰 legacy path。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 12. 分阶段实施计划
|
|||
|
|
|
|||
|
|
### Phase A:冻结目标与建立兼容边界
|
|||
|
|
|
|||
|
|
目标:
|
|||
|
|
|
|||
|
|
- 明确“什么叫 Unity 风格 shader”
|
|||
|
|
- 明确 legacy 与新 authoring 的兼容边界
|
|||
|
|
|
|||
|
|
工作项:
|
|||
|
|
|
|||
|
|
1. 写清 Unity 风格支持子集。
|
|||
|
|
2. 明确旧 `.shader` 的 legacy 模式规则。
|
|||
|
|
3. 明确新 authoring 中禁止出现:
|
|||
|
|
- `#pragma backend`
|
|||
|
|
- `Resources(set,binding)`
|
|||
|
|
4. 明确 material 中 `shaderPass` 的弃用策略。
|
|||
|
|
|
|||
|
|
完成标准:
|
|||
|
|
|
|||
|
|
- 文档、命名、兼容边界全部写死
|
|||
|
|
|
|||
|
|
### Phase B:建立新的 Shader Authoring Parser 与 IR
|
|||
|
|
|
|||
|
|
目标:
|
|||
|
|
|
|||
|
|
- 新 `.shader` authoring 能导入到统一 `ShaderIR`
|
|||
|
|
|
|||
|
|
工作项:
|
|||
|
|
|
|||
|
|
1. 新增 parser,支持:
|
|||
|
|
- `Shader / Properties / SubShader / Pass / Tags`
|
|||
|
|
- `HLSLINCLUDE / HLSLPROGRAM`
|
|||
|
|
- `#pragma vertex / fragment / target / multi_compile / shader_feature`
|
|||
|
|
- pass state DSL
|
|||
|
|
2. 生成 `ShaderIR`
|
|||
|
|
3. 支持 include 依赖收集
|
|||
|
|
4. 保留 legacy importer
|
|||
|
|
|
|||
|
|
完成标准:
|
|||
|
|
|
|||
|
|
- authoring parser 单测齐全
|
|||
|
|
- 可以把一个 Unity 风格 shader 解析成稳定 IR
|
|||
|
|
|
|||
|
|
### Phase C:建立单一 HLSL 编译链
|
|||
|
|
|
|||
|
|
目标:
|
|||
|
|
|
|||
|
|
- 打通 `HLSL -> D3D12/Vulkan/OpenGL` 编译管线
|
|||
|
|
|
|||
|
|
工作项:
|
|||
|
|
|
|||
|
|
1. 接入 DXC 编译 HLSL。
|
|||
|
|
2. Vulkan 产出 SPIR-V。
|
|||
|
|
3. OpenGL 产出 GLSL 430。
|
|||
|
|
4. 建立 reflection 数据抽取:
|
|||
|
|
- cbuffer
|
|||
|
|
- texture
|
|||
|
|
- sampler
|
|||
|
|
- entry point
|
|||
|
|
- keywords
|
|||
|
|
5. 缓存编译产物与依赖 hash。
|
|||
|
|
|
|||
|
|
完成标准:
|
|||
|
|
|
|||
|
|
- 一份 HLSL authoring 能生成三后端产物
|
|||
|
|
- OpenGL 不再依赖手写 `.glsl` 作为新体系长期主路径
|
|||
|
|
|
|||
|
|
### Phase D:Material 与 property/keyword/runtime binding 正式化
|
|||
|
|
|
|||
|
|
目标:
|
|||
|
|
|
|||
|
|
- material 能正式驱动新 shader artifact
|
|||
|
|
|
|||
|
|
工作项:
|
|||
|
|
|
|||
|
|
1. 引入正式 property layout。
|
|||
|
|
2. 引入 material keyword set。
|
|||
|
|
3. 生成 `PerMaterial` 常量缓冲布局。
|
|||
|
|
4. texture/sampler 绑定从 reflection/约定生成。
|
|||
|
|
5. 让 material 运行时不再关心 `set/binding`。
|
|||
|
|
|
|||
|
|
完成标准:
|
|||
|
|
|
|||
|
|
- material property / texture / keyword 真正接入 GPU 绑定链
|
|||
|
|
|
|||
|
|
### Phase E:renderer pass 选择与 pipeline cache 收口
|
|||
|
|
|
|||
|
|
目标:
|
|||
|
|
|
|||
|
|
- renderer 完全按 pass contract 驱动 shader
|
|||
|
|
|
|||
|
|
工作项:
|
|||
|
|
|
|||
|
|
1. 按 `LightMode` 选 pass。
|
|||
|
|
2. `shaderPass` 降级为 legacy fallback。
|
|||
|
|
3. pipeline cache key 引入:
|
|||
|
|
- shader artifact id
|
|||
|
|
- pass id
|
|||
|
|
- keyword variant id
|
|||
|
|
- render state
|
|||
|
|
4. builtin pass 的 runtime contract 全部切到新 artifact。
|
|||
|
|
|
|||
|
|
完成标准:
|
|||
|
|
|
|||
|
|
- renderer 主路径不再依赖 material 显式 pass 指定
|
|||
|
|
|
|||
|
|
### Phase F:分批迁移 builtin shader
|
|||
|
|
|
|||
|
|
建议迁移顺序:
|
|||
|
|
|
|||
|
|
1. `unlit`
|
|||
|
|
2. `forward-lit`
|
|||
|
|
3. `depth-only`
|
|||
|
|
4. `shadow-caster`
|
|||
|
|
5. `object-id`
|
|||
|
|
6. `skybox`
|
|||
|
|
7. `color-scale-post-process`
|
|||
|
|
8. `final-color`
|
|||
|
|
|
|||
|
|
完成标准:
|
|||
|
|
|
|||
|
|
- builtin shader 全部有新 authoring 版本
|
|||
|
|
- 旧版 backend 分发文件不再是长期主定义来源
|
|||
|
|
|
|||
|
|
### Phase G:文档、测试、旧路径收口
|
|||
|
|
|
|||
|
|
目标:
|
|||
|
|
|
|||
|
|
- 让新旧体系的边界最终收口
|
|||
|
|
|
|||
|
|
工作项:
|
|||
|
|
|
|||
|
|
1. 更新 `tests/TEST_SPEC.md` 中 shader/material 测试矩阵。
|
|||
|
|
2. 增加 authoring parser / compiler / runtime 回归测试。
|
|||
|
|
3. 更新开发文档。
|
|||
|
|
4. 标记 legacy 路径弃用阶段。
|
|||
|
|
|
|||
|
|
完成标准:
|
|||
|
|
|
|||
|
|
- 新体系文档、测试、builtin 迁移都完成
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 13. 测试策略
|
|||
|
|
|
|||
|
|
### 13.1 Parser / Importer 单测
|
|||
|
|
|
|||
|
|
必须覆盖:
|
|||
|
|
|
|||
|
|
- Properties 解析
|
|||
|
|
- SubShader / Pass / Tags 解析
|
|||
|
|
- HLSLINCLUDE / HLSLPROGRAM 解析
|
|||
|
|
- pragma 解析
|
|||
|
|
- pass state 解析
|
|||
|
|
- include 依赖收集
|
|||
|
|
- legacy / 新 authoring 双路径兼容
|
|||
|
|
|
|||
|
|
### 13.2 Compiler 单测
|
|||
|
|
|
|||
|
|
必须覆盖:
|
|||
|
|
|
|||
|
|
- 单一 HLSL 源能生成三后端产物
|
|||
|
|
- reflection 结果稳定
|
|||
|
|
- keyword variant 正确展开
|
|||
|
|
- 编译错误日志可读、可定位到 authoring 源文件
|
|||
|
|
|
|||
|
|
### 13.3 Material 单测
|
|||
|
|
|
|||
|
|
必须覆盖:
|
|||
|
|
|
|||
|
|
- property 默认值
|
|||
|
|
- property override
|
|||
|
|
- texture binding
|
|||
|
|
- keyword set
|
|||
|
|
- 常量缓冲布局打包
|
|||
|
|
|
|||
|
|
### 13.4 Rendering 单测
|
|||
|
|
|
|||
|
|
必须覆盖:
|
|||
|
|
|
|||
|
|
- renderer 按 `LightMode` 选 pass
|
|||
|
|
- legacy `shaderPass` fallback 行为
|
|||
|
|
- keyword variant 参与 pipeline cache key
|
|||
|
|
- final color / post-process / shadow / object-id 不回退
|
|||
|
|
|
|||
|
|
### 13.5 集成测试
|
|||
|
|
|
|||
|
|
至少回归:
|
|||
|
|
|
|||
|
|
- `material_state_scene`
|
|||
|
|
- `transparent_material_scene`
|
|||
|
|
- `camera_stack_scene`
|
|||
|
|
- `directional_shadow_scene`
|
|||
|
|
- `multi_light_scene`
|
|||
|
|
- `skybox_scene`
|
|||
|
|
- `post_process_scene`
|
|||
|
|
- `final_color_scene`
|
|||
|
|
- `object_id_scene`
|
|||
|
|
|
|||
|
|
要求:
|
|||
|
|
|
|||
|
|
- 三后端全部跑通
|
|||
|
|
- GT 不回退
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 14. 风险与控制策略
|
|||
|
|
|
|||
|
|
### 风险 1:OpenGL 是统一写法最难的一环
|
|||
|
|
|
|||
|
|
原因:
|
|||
|
|
|
|||
|
|
- OpenGL 当前直接吃 GLSL
|
|||
|
|
- 统一 authoring 要求它改为编译链生成目标 GLSL
|
|||
|
|
|
|||
|
|
控制策略:
|
|||
|
|
|
|||
|
|
- 先把 importer/IR 做好
|
|||
|
|
- OpenGL 先走“生成 GLSL 文本产物”路径
|
|||
|
|
- legacy OpenGL GLSL 文件在迁移期保留 fallback
|
|||
|
|
|
|||
|
|
### 风险 2:一次性追 full Unity 语法会把阶段拖爆
|
|||
|
|
|
|||
|
|
控制策略:
|
|||
|
|
|
|||
|
|
- 明确 first-class 子集
|
|||
|
|
- 先做 SRP 真正依赖的 authoring 基础
|
|||
|
|
- 非关键语法延后
|
|||
|
|
|
|||
|
|
### 风险 3:material / pass 迁移会破坏当前 builtin renderer
|
|||
|
|
|
|||
|
|
控制策略:
|
|||
|
|
|
|||
|
|
- legacy runtime path 保留一段时间
|
|||
|
|
- builtin shader 分批迁移
|
|||
|
|
- 每迁移一个 shader 就跑对应 integration
|
|||
|
|
|
|||
|
|
### 风险 4:编译错误如果不可读,会极大拖慢落地
|
|||
|
|
|
|||
|
|
控制策略:
|
|||
|
|
|
|||
|
|
- 必须做 authoring 源到 backend 编译日志的映射
|
|||
|
|
- 错误日志要带 shader 名、pass 名、stage、backend、源文件行号
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 15. 收口判定
|
|||
|
|
|
|||
|
|
满足下面条件时,本阶段可视为完成:
|
|||
|
|
|
|||
|
|
1. 新 `.shader` authoring 采用 Unity 风格子集。
|
|||
|
|
2. 新体系 shader authoring 中不再出现 `#pragma backend`。
|
|||
|
|
3. 新体系 shader authoring 中不再出现 `Resources(set,binding)`。
|
|||
|
|
4. HLSL single-source 能生成 D3D12 / Vulkan / OpenGL 三后端产物。
|
|||
|
|
5. material 已正式接入 property / keyword / texture binding runtime。
|
|||
|
|
6. renderer 按 `LightMode` 正式选择 pass。
|
|||
|
|
7. `shaderPass` 只剩 legacy fallback,不再是主路径。
|
|||
|
|
8. builtin shader 已完成新体系迁移。
|
|||
|
|
9. 三后端关键集成测试全部通过。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 16. 与后续 SRP 的承接关系
|
|||
|
|
|
|||
|
|
这一阶段完成后,才能真正自然地承接:
|
|||
|
|
|
|||
|
|
- `RenderPipelineAsset`
|
|||
|
|
- `RenderPipeline`
|
|||
|
|
- `RendererFeature`
|
|||
|
|
- `ScriptableRenderPass`
|
|||
|
|
- C# 层对 shader/material/keyword 的控制
|
|||
|
|
|
|||
|
|
承接关系应当是:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
Unity-style Shader Authoring
|
|||
|
|
-> Shader Importer / IR / Artifact
|
|||
|
|
-> Native Material & Pass Runtime
|
|||
|
|
-> Native Renderer Pass Contract
|
|||
|
|
-> C# SRP / RendererFeature
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
也就是说:
|
|||
|
|
|
|||
|
|
- 这一阶段不是 SRP
|
|||
|
|
- 但这是 SRP 成立前必须先做完的最后一层底座
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 17. 一句话总结
|
|||
|
|
|
|||
|
|
当前 shader 体系不是没有,而是还停在“过渡态”。
|
|||
|
|
|
|||
|
|
下一阶段的正确方向不是继续堆更多 shader 功能,而是:
|
|||
|
|
|
|||
|
|
- **把 `.shader` 的 authoring 真正统一成 Unity 风格**
|
|||
|
|
- **把 backend 差异与 binding 细节收回 importer / compiler 层**
|
|||
|
|
- **把 material / pass / variant/runtime contract 一次性做正式**
|
|||
|
|
|
|||
|
|
只有这样,后面的 SRP 才不会建立在一层伪统一的 shader 体系上。
|