15 KiB
Renderer 下一阶段:多光源正式化与 Lighting 闭环计划
日期:2026-04-05
1. 阶段定位
当前 rendering 主线已经完成了“默认 runtime forward renderer 第一阶段”的主体闭环:
SceneRenderer -> CameraRenderer -> RenderPipeline主链已经落地- 主方向光阴影已经由 renderer 自动规划并接入 forward pass
SceneView / GameView已统一接到 runtime renderer 主链object-id已经是正式的 GPU 路线- 三后端已有一批稳定的 rendering integration coverage
因此,当前阶段真正未收口的主线不再是:
render graph- editor 专属效果扩展
- 更复杂的后处理系统
而是:
把当前“只支持主方向光”的 lighting runtime,推进成一个正式可扩展的多光源 forward runtime。
这份计划只聚焦这一条主线。
2. 为什么现在必须先做多光源
当前源码真实状态已经说明问题:
RenderLightingData仍然只有mainDirectionalLight和mainDirectionalShadowRenderSceneExtractor只会提取一个主方向光BuiltinForwardPipeline只消费这一套最小 lighting 数据LightComponent虽然已经有Directional / Point / Spot三种类型,但 runtime renderer 还没有把它们正式接通
这意味着现在的 renderer 已经不是“不能用”,而是:
单方向光路径可用,但正式多光源路径缺失。
如果这时去做 render graph,只是给尚未完全闭环的 runtime lighting 套上更复杂的调度壳。
如果这时去继续堆 editor 视觉功能,也是在建立在不完整 runtime 光照基础之上。
所以正确顺序必须是:
- 先把多光源正式化
- 再进入 skybox / environment / post-process seam
- 最后才考虑 render graph 这类更高层调度框架
3. 与 Unity 风格架构的对齐原则
本阶段继续严格遵守当前工程的核心分层:
RHI只负责 GPU 抽象Renderer负责 scene extraction、lighting data、pass orchestration、shader/material contractEditor只作为 renderer 宿主与 overlay 使用方,不拥有独立 runtime lighting 主链
与 Unity 风格对齐时,本阶段遵守以下原则:
- 主方向光与 additional lights 属于 runtime renderer 正式能力
- editor 的 grid / outline / gizmo / icon 不是本阶段主线
- shader/material 仍然走统一
.shader + Pass + backend variants路线,而不是退回后端硬编码 - 当前阶段先做“有限 additional lights 的前向提交”,不直接跳到 clustered / deferred
4. 当前真实现状
4.1 已完成的部分
- 自动方向光阴影规划已经存在
CameraRenderer已有正式 pass 顺序:preScenePassesshadowCasterdepthOnlymain pipelineobjectIdpostScenePassesoverlayPasses
BuiltinForwardPipeline已形成正式 shader/material/pass contract- editor Scene/Game viewport 已经走 runtime renderer 主链
object-idpicking 已经是正式主路径
4.2 还没收口的部分
RenderLightingData没有正式 additional light 数据模型RenderSceneExtractor没有 point / spot / additional directional 的提取与排序BuiltinForwardPipeline没有正式的 additional light GPU 提交路径- 当前 forward lit shader 常量组织仍偏“单主光最小路径”
- integration matrix 中还没有
multi_light_scene与spot_light_scene
5. 本阶段总目标
本阶段的目标只有一句话:
建立一个正式、稳定、可测试、三后端一致的 bounded forward multi-light runtime。
收口后应达到:
Directional / Point / Spot三类光源能通过 runtime renderer 正式影响画面- 主方向光阴影能力保持不回退
- 三后端使用同一套 shader/material contract
- Scene/Game View 继续直接复用同一条 runtime renderer 光照路径
- 为下一阶段 skybox / environment / post-process 留出清晰接入点
6. 非目标
本阶段明确不做:
render graph- deferred rendering
- tiled / clustered lighting
- cascaded shadow maps
- point / spot shadow
- GI / IBL / probe / reflection probe
- PBR 大重构
- editor 专属渲染效果继续扩张
7. 设计方案
7.1 正式化 lighting 数据模型
建议把当前 RenderLightingData 从:
mainDirectionalLightmainDirectionalShadow
扩展为:
mainDirectionalLightmainDirectionalShadowadditionalLights
其中 additionalLights 的单项建议包含:
typeenabledcolorintensitypositiondirectionrangespotAnglecastsShadows
这里的关键原则是:
- 主方向光继续单独建模
- additional lights 统一为一个正式数组,而不是分散塞进临时常量
- 当前阶段允许 additional lights 无阴影
- 数据模型要能自然承接后续 per-object light list 或 clustered light list,而不是很快被推翻
7.2 限定本阶段的 light strategy
本阶段不追求“无限灯光”,而采用有限 additional lights 前向提交。
建议首版规则:
- 保留 1 个
main directional light - 额外提交最多
8个additional lights additional lights可以包含:- 非主方向光的 directional
- point
- spot
之所以建议先定成 8:
- 与常见 forward runtime 的第一阶段预算接近
- 常量布局、三后端一致性和 integration GT 更容易稳定
- 以后即使扩到
16或改成 per-object list,也不会推翻整体 contract
7.3 CPU 侧提取、裁剪与排序策略
RenderSceneExtractor 需要正式负责 additional light 提取。
首版建议策略:
- 过滤掉无效灯光
- component disabled
- game object inactive
- 不在 camera culling mask 内
- 选择主方向光
- 仍沿用“最重要的 directional light 单独提升为 main light”的策略
- 其余光源进入 additional list
- 对 additional list 做稳定排序
- 截断到最大上限
为了保证输出稳定、便于 GT 固化,建议排序规则写死为:
- additional directional lights 优先
- point / spot 在后
- 同类型内按影响力降序
- 影响力相同则按 object/entity id 稳定排序
影响力计算不必一步到位做复杂物理模型,首版只需要稳定且可解释。建议:
- directional:按
intensity - point / spot:按
intensity / max(distance^2, epsilon)的近似影响值
这里先按 camera 视角做 bounded list,不在本阶段直接引入 per-object light assignment。
7.4 收紧 shader / material / pass contract
当前 forward path 的一个根本问题是:场景级 lighting 数据仍部分塞在 PerObjectConstants 里。
这对 additional lights 来说不是正式方案。
因此本阶段需要把 forward lit 资源合约收紧为:
PerObject- 只保留与单个 draw object 强相关的数据
- 例如
model / inverse model / view / projection
PerMaterial- 继续承载材质数据
Lighting- 新增正式 scene/frame lighting constant buffer
- 包含主光与 additional lights
ShadowReceiver- 继续承载主方向光阴影矩阵与 shadow 参数
BaseColorTextureLinearClampSamplerShadowMapTextureShadowMapSampler
这一步非常关键,因为它决定后续扩展是否正规:
- scene/frame lighting 不再随每个 draw 重复写入
PerObject - additional light 数组有正式宿主
- 三后端可以共享同一份高层资源声明
7.5 三后端 shader 路线必须保持统一
本阶段继续沿用当前已经建立起来的 shader 路线:
- 高层作者视图仍是统一
.shader - 每个
Pass通过 backend variants 指向:- OpenGL GLSL
- Vulkan GLSL
- D3D12 HLSL
也就是说:
- 不在材质系统层面分裂成三套 API 专属 shader 入口
- forward lit pass 的资源声明只保留一份 canonical contract
- 三后端只在 stage variant 实现层分开
这点必须继续保持,因为它是后续 Unity-like shader authoring 的前提。
7.6 Forward shader 的首版光照职责边界
本阶段只要求把光照主路径打通,不把 PBR 一起打包进来。
建议职责边界:
main directional light- 支持现有阴影
additional directional lights- 无阴影
point lights- 范围衰减
spot lights- 范围衰减 + 锥角衰减
首版 shading model 以稳定为主:
- 延续当前 forward lit 的 diffuse / lambert 风格
- 不在本阶段引入新的 specular / BRDF 复杂度
7.7 Spot light 参数策略
当前 LightComponent 只有一个 spotAngle,没有 innerSpotAngle。
为了避免本阶段扩散到组件/序列化/UI 全链路重构,建议首版这样处理:
outer cone直接使用spotAngleinner cone由 runtime 以固定比例推导- 例如
inner = outer * 0.8
- 例如
- 等 shader/material 与 renderer 多光源闭环稳定后,再决定是否把
innerSpotAngle正式上升为组件字段
这能保证当前阶段先把 runtime 多光源打通,而不是被 editor 数据建模拖慢。
7.8 BuiltinForwardPipeline 的正式改造方向
BuiltinForwardPipeline 本阶段要完成的,不只是“shader 多写几行光照循环”,而是正式接管以下职责:
- 创建/维护
Lighting常量资源 - 每帧更新一份 bounded additional light 数据
- 在 draw 时稳定绑定
Lighting与ShadowReceiver - 保持
Unlit / ObjectId / DepthOnly / ShadowCaster不被污染
简化后目标是:
- lit path 正式消费 multi-light 数据
- unlit path 保持简单
- object-id / shadow-caster 不承担 lighting 语义
8. 实施分阶段
8.1 Phase A:Lighting Contract 正式化
目标
把 scene/frame lighting 常量从 PerObject 里拆出来,建立正式 Lighting 合约。
具体工作
- 重构 forward lit shader 的资源声明
- 新增
Lighting常量缓冲结构 - 将主方向光数据迁移到
Lighting - 保留
ShadowReceiver只处理阴影接收参数 - 调整
BuiltinForwardPipeline的 descriptor set 解析与绑定逻辑
验收标准
- 主方向光现有画面不回退
- 三后端 forward lit pass 都能正确解析新资源布局
unlit / object-id / shadow-caster不受影响
8.2 Phase B:CPU Additional Light Extraction
目标
让 RenderSceneExtractor 正式产出 bounded additional lights。
具体工作
- 扩展
RenderLightingData - 增加 additional light 数据结构
- 实现过滤、排序、截断策略
- 补 unit tests,覆盖:
- 主光选择
- additional list 排序
- 上限裁剪
- point / spot 提取正确性
验收标准
- extractor 可稳定输出 additional light 列表
- 输出顺序稳定、可预测
- 现有单主光场景输出保持一致
8.3 Phase C:Forward Multi-Light Consumption
目标
让 BuiltinForwardPipeline 和 builtin forward lit shader 正式消费 additional lights。
具体工作
- 新增 additional light 常量布局
- 在 shader 中加入 bounded light loop
- 实现 point / spot 的首版 attenuation
- 保持 main directional shadow 不回退
- 为 additional directional / point / spot 明确统一数学路径
验收标准
- 多灯光真实影响画面
- 主方向光阴影仍正确
- 三后端输出保持一致,没有明显分叉
8.4 Phase D:正式集成测试补齐
目标
把 multi-light 路径钉死在 integration matrix 中。
新增场景
tests/Rendering/integration/multi_light_scenetests/Rendering/integration/spot_light_scene
场景设计要求
multi_light_scene:
- 至少 1 个主方向光
- 至少 2 个 additional lights
- 场景几何要让不同灯光覆盖区域明显分离
- GT 图必须一眼能看出 additional lights 是否生效
spot_light_scene:
- 一个明显的 spot hot area
- 同时能看到范围边界和角度边界
- 最好包含一个立体物体和一个地面,避免只看平面亮斑
附加要求
- 三后端都必须有 GT
- 除整图 GT 比对外,可补少量像素采样断言,以降低误报成本
- 必须把
directional_shadow_scene、backpack_lit_scene一起纳入回归验证
验收标准
multi_light_scene三后端全绿spot_light_scene三后端全绿- 现有 lighting 相关 integration 不回退
8.5 Phase E:文档与阶段收口
目标
让本阶段结束后,rendering 主线边界重新清晰。
具体工作
- 更新
tests/TEST_SPEC.md - 更新 renderer 相关 API / guide 文档
- 把本阶段已完成的旧计划归档到
docs/used - 输出“多光源阶段收口说明”
验收标准
- 文档、测试矩阵、实现三者口径一致
- 下一阶段可以自然承接 skybox / environment / post-process
9. 测试策略
本阶段测试必须分三层执行:
9.1 Unit
RenderSceneExtractormulti-light 提取BuiltinForwardPipelinelighting resource layout / descriptor binding- light attenuation 数学辅助函数
9.2 Integration
multi_light_scenespot_light_scene- 回归:
directional_shadow_scenebackpack_lit_scenecamera_stack_scenetransparent_material_scenecull_material_scenedepth_sort_scenematerial_state_sceneoffscreen_scene
9.3 Editor Runtime Smoke
- SceneView 光照结果与 GameView 主路径一致
- object-id picking 不因 lighting contract 变更而回退
- editor overlay 不污染 runtime lighting
10. 风险与控制
风险 1:把 multi-light 直接塞进 PerObject
后果:
- descriptor update 开销恶化
- 语义继续混乱
- 后续 skybox / environment / post-process 继续难收口
控制策略:
- 本阶段第一步就强制建立
Lighting常量资源
风险 2:additional lights 排序不稳定导致 GT 抖动
后果:
- 三后端图像对比不稳定
- 回归测试容易出现“偶发错图”
控制策略:
- 排序规则必须写死
- 相同影响力要有稳定 tie-breaker
风险 3:spot light 参数扩散到组件/UI/序列化全链路
后果:
- 本阶段失焦
- runtime 主线再次拖长
控制策略:
- 首版先用单
spotAngle+ 固定 inner ratio
风险 4:三后端 shader 细节分叉
后果:
- D3D12 / OpenGL / Vulkan 结果不一致
控制策略:
- 高层资源 contract 只保留一份 canonical 声明
- integration 以三后端同时跑为硬约束
11. 阶段完成判定
满足以下条件时,本阶段可以认为收口:
RenderLightingData已正式支持 additional lightsBuiltinForwardPipeline已正式消费 bounded additional lightsmulti_light_scene与spot_light_scene三后端通过directional_shadow_scene与backpack_lit_scene无回退- Scene/Game View 继续通过统一 runtime renderer 显示一致光照结果
- 文档与测试矩阵已同步
12. 本阶段之后的正确下一步
多光源阶段收口后,renderer 的下一阶段才应该进入:
- skybox / environment seam
- post-process 正式入口
- 更完整的 renderer frame composition
而不是立即跳去:
render graph- deferred
- editor-only 视觉堆叠
13. 与旧计划的关系
2026-04-04 的《Renderer 下一阶段:方向光阴影与光照闭环计划》已经完成了其中大部分更高优先级内容:
- 自动方向光阴影
- Scene/Game runtime renderer 接入
- object-id 正式化
- 当前 forward runtime 主链稳定化
因此它已经不适合作为当前执行入口,现已归档。
本文件从 2026-04-05 起接管 rendering 主线的正式下一阶段。