14 KiB
Renderer 下一阶段:方向光阴影与光照闭环计划
日期:2026-04-04
1. 阶段背景
当前 shader / material / rendering 主线已经完成了这一阶段应有的基础闭环:
Shader已具备properties / passes / resources / backend variants运行时契约Material已具备 schema 驱动的属性、纹理、常量布局与 pass resource binding planSceneRenderer / CameraRenderer / BuiltinForwardPipeline已经打通ObjectId / DepthOnly / ShadowCaster已具备独立 pass 与 request 骨架- 三后端
D3D12 / OpenGL / Vulkan的当前渲染集成测试已全绿
但这仍然只是“能稳定出图的基础 forward renderer”,还不是“能承担引擎默认场景渲染”的完整运行时。
下一阶段不应该优先做 render graph,也不应该先追求更复杂的编辑器功能,而应该把当前 renderer 推进成一个真正可用的默认前向渲染器。
这一阶段的主线目标只有一句话:
把当前 renderer 从“无阴影的基础出图器”推进到“具备方向光、阴影、基础多光源闭环,并可稳定承接 Scene/Game 视图”的运行时渲染器。
2. 为什么下一步是这个
当前代码结构已经说明了下一阶段的最短主路径:
RenderSceneExtractor里已经有RenderLightingData.mainDirectionalLightBuiltinForwardPipeline已经在 per-object constants 中消费主方向光方向和颜色CameraRenderRequest已经有shadowCaster / depthOnly / objectIdrequestBuiltinShadowCasterPass / BuiltinDepthOnlyPass已经存在
也就是说:
- 光照数据通路已经有最小入口
- 阴影 pass 的执行骨架已经有了
- 缺的是把这些骨架真正接成 frame 级闭环
如果这时跳去做 render graph,只会把尚未收紧的运行时逻辑包上一层更复杂的调度壳。
如果这时去做更复杂的 editor 特效,也是在建立在“runtime lighting 还不完整”的地基上。
所以本阶段应当严格沿着 Unity 风格的自然演进路径推进:
- 先把默认前向运行时补完整
- 再谈更高层调度与优化
3. 与 Unity 式架构的对齐原则
本阶段继续遵循现有总设计,不偏离 RHI -> Renderer -> Editor/Runtime 这条主分层:
RHI只负责统一 GPU 抽象,不承载场景渲染逻辑Renderer负责场景提取、光照数据组织、shadow/depth/object-id/forward 等 pass 执行Editor只是 renderer 的宿主与附加 overlay/pass 使用方,不拥有独立的一套 runtime 渲染逻辑
与 Unity 对齐时,要注意以下边界:
- 阴影图、主光照、相机渲染请求,这些属于 runtime renderer 的正式能力
- grid、outline、gizmo、icon,这些属于 editor 专属叠加能力
- editor 需要复用 renderer,但不能反向污染 runtime 主链
因此,这一阶段做的方向光阴影、基础多光源、GameView/SceneView 统一接入,都是正式主线。
GPU picking、editor outline、gizmo 美术化这些,都不应抢主线优先级。
4. 当前真实现状
从当前代码看,renderer 已具备但尚未闭环的点如下。
4.1 已经具备的能力
SceneRenderer已支持多 camera request、camera stack、surface render areaCameraRenderer已支持pre -> shadowCaster -> depthOnly -> main pipeline -> objectId -> postBuiltinForwardPipeline已支持ForwardLit / Unlit的统一 shader/material contractBuiltinObjectIdPass已正式接入 object-id 渲染路径BuiltinDepthOnlyPass / BuiltinShadowCasterPass已经具备 pass 级执行能力RenderSceneExtractor已能提取主方向光
4.2 尚未闭环的能力
- 阴影图尚未由
SceneRenderer/CameraRenderer正式规划、分配、执行与回收 - forward 主通道尚未消费 shadow map 结果
- 光照仍停留在“单主方向光最小数据”,没有正式多光源提交模型
- shadow request 目前更像通用 hook,而不是 renderer 自动生成的正式帧请求
- 缺少以“阴影正确性”为目标的正式集成测试场景
- 缺少以“多光源正确性”为目标的正式集成测试场景
4.3 这意味着什么
当前 renderer 的问题已经不再是“架构没有”,而是:
架构有了,但 runtime lighting/shadow 这条主业务链尚未贯通。
5. 本阶段总体目标
本阶段拆成四个连续目标:
- 建立正式的方向光阴影闭环
- 建立正式的前向多光源数据通路
- 统一 SceneView / GameView 对 runtime renderer 的使用方式
- 为下一阶段的 post-process 与 renderer 扩展收紧边界
其中优先级严格如下:
Directional Light + Shadow MapForward 多光源Scene/Game 视图统一使用正式 renderer 能力补文档、补测试、清理旧临时路径
6. 分阶段实施计划
6.1 Phase A:方向光阴影闭环
目标
让场景中的主方向光真正生成 shadow map,并在主 forward pass 中被采样,形成跨三后端稳定一致的阴影结果。
具体工作
A1. 正式定义 shadow frame 数据模型
新增或收紧 renderer 内部数据结构,至少明确:
- 主方向光是否需要阴影
- shadow map 尺寸与格式
- light-space view/projection 矩阵
- shadow caster 渲染 surface
- forward receiver 采样所需的阴影参数
这里的目标不是先做复杂 cascades,而是先做单张 directional shadow map MVP。
A2. 由 renderer 自动生成 shadow caster request
不能继续依赖测试或上层调用者手工拼 shadowCaster request。
应由 SceneRenderer 或 CameraRenderer 在主 camera 渲染前自动生成:
- 主方向光对应的 shadow camera data
- shadow surface
- clear flags
- shadow pass 执行顺序
也就是说,要把“有 shadow pass 骨架”提升成“runtime renderer 正式调度 shadow pass”。
A3. 收紧 BuiltinShadowCasterPass
确认并补齐以下行为:
- 只渲染
castShadows = true的可见物体 - 正确处理 section/material pass 选择
- 只依赖 shadow caster 所需最小资源
- 在三后端下都使用统一的深度输出语义
A4. 在 BuiltinForwardPipeline 中消费 shadow map
forward pass 至少补齐:
- shadow map SRV 绑定
- light-space position 计算
- shadow compare
- 基础 bias
- 基础 PCF 或最小稳定采样
这一阶段不追求高级阴影质量,但必须追求:
- 没有明显自阴影灾难
- 没有跨后端严重不一致
- 测试图可稳定固化 GT
A5. 增加阴影集成测试
新增至少一个正式场景:
tests/Rendering/integration/directional_shadow_scene
场景要求:
- 至少包含一盏方向光
- 至少包含一个会投影的物体
- 至少包含一个接收阴影的地面或大平面
- 阴影边界、方向、遮挡关系都足够稳定,适合 GT 比对
验收标准
- 三后端都能稳定生成方向光阴影
- forward pass 正式消费 shadow map
directional_shadow_scene三后端 GT 全绿- 不破坏现有全部 rendering integration
6.2 Phase B:前向多光源闭环
目标
把当前只支持主方向光的 lighting 数据模型,推进为可正式承接多个灯光的前向运行时。
具体工作
B1. 扩展 RenderLightingData
从当前的:
mainDirectionalLight
扩展到至少可描述:
main directional lightadditional directional lightspoint lightsspot lights
注意这里不一定一步到位做完整 Unity 灯光体系,但要保证数据模型不会很快被推翻。
B2. 明确本阶段多光源策略
当前阶段建议使用:
- 单主方向光
- 有上限的 additional lights
- CPU 侧整理一份稳定 light list
- GPU 侧通过常量缓冲或结构化数据提交
本阶段不做:
- clustered lighting
- tiled lighting
- deferred lighting
这是为了保证先把可验证的前向路径收紧。
B3. 扩展 forward shader/material contract
补齐多光源所需的 shader 输入:
- additional light count
- light position / direction / color / range / spot angle
- shadowed main light 与 non-shadowed additional lights 的职责边界
要求仍沿用当前的 shader/material/pass contract,不要回退成硬编码散乱常量。
B4. 新增多光源集成测试
新增至少两个场景:
multi_light_scenespot_light_scene
场景目标:
- 验证 point/spot 的衰减与照明范围
- 验证 additional lights 会真实影响画面
- 验证三后端输出保持一致
验收标准
RenderSceneExtractor能提取正式多光源数据BuiltinForwardPipeline能消费多光源- 新增多光源场景三后端 GT 全绿
- 方向光阴影能力不被破坏
6.3 Phase C:SceneView / GameView runtime 接入收紧
目标
让 editor 的场景与游戏视图都建立在同一套 runtime renderer 能力上,而不是继续沿着临时 editor 路径分叉。
具体工作
C1. 明确 runtime pass 与 editor overlay pass 的边界
正式定义:
- runtime 正式 pass:shadow caster、depth only、forward、object-id、offscreen copy 等
- editor 附加 pass:grid、outline、icon、gizmo 等
要求:
- runtime pass 可脱离 editor 独立工作
- editor pass 只能叠加,不能挟持 runtime 主流程
C2. GameView 走正式相机渲染请求
GameView 必须通过标准 CameraRenderRequest 驱动 renderer,不能再依赖 editor 特殊逻辑直接拼接。
C3. SceneView 继续复用 renderer
SceneView 应:
- 复用正式相机渲染链
- 在其上叠加 editor overlay
- 允许 object-id / outline / grid 等继续作为 editor 增量能力存在
验收标准
- SceneView 与 GameView 都走正式 renderer 主链
- editor 专属 overlay 不污染 runtime pass
- 不出现“editor 正常、runtime 不正常”或反之的分叉
6.4 Phase D:收口与稳定性整理
目标
在新能力落地后,把这一阶段的测试、文档、边界彻底收紧。
具体工作
D1. 补齐测试矩阵
至少确保以下持续可跑:
shader_testsmaterial_testsmesh_testsrendering_unit_tests- 全部
tests/Rendering/integration
新增场景至少包括:
directional_shadow_scenemulti_light_scenespot_light_scene
D2. 清理临时路径
逐项检查并收紧:
- 是否仍有测试手工拼 shadow request
- 是否仍有 runtime/editor 职责混用
- 是否仍有与 shader/material contract 相冲突的旧 lighting 常量路径
D3. 文档归档
这一阶段结束后,应补一份阶段收口说明,并把过期计划归档到 docs/plan/used/。
验收标准
- 阴影、多光源、Scene/Game 接入均通过测试
- 当前计划中的临时方案被收紧到清晰边界内
- 下一阶段可以自然承接 skybox/post-process,而不是继续补地基
7. 测试策略
这一阶段的测试必须比前一阶段更严格,因为它开始影响真正的场景表现。
7.1 单元测试
重点补以下测试:
RenderSceneExtractor的多光源提取- shadow request 自动生成逻辑
- shadow matrix / light camera 参数构建
- forward shader resource binding 对 shadow map 的消费
- additional lights 排序与裁剪规则
7.2 集成测试
必须新增:
directional_shadow_scenemulti_light_scenespot_light_scene
保底回归集:
textured_quad_sceneunlit_sceneobject_id_scenebackpack_scenebackpack_lit_scenecamera_stack_scenetransparent_material_scenecull_material_scenedepth_sort_scenematerial_state_sceneoffscreen_scene
7.3 三后端要求
本阶段所有新增集成测试都必须同时覆盖:
D3D12OpenGLVulkan
如果某一步只在单后端通过,不算完成。
这一阶段绝不接受“先在一个后端跑通,另外两个后面再补”的收口标准。
8. 明确不做
为了避免主线失控,这一阶段明确不做下面这些:
render graphdeferred rendererclustered/tiled lightingcascaded shadow mapsPCSS / VSM / EVSM等高级阴影方案post-process大框架shader graph- editor gizmo 的进一步美术化与交互打磨
这些都应该建立在“方向光阴影 + 基础多光源 + runtime renderer 稳定闭环”完成之后。
9. 风险点与处理策略
9.1 风险:阴影路径把 pass/resource contract 搞散
处理策略:
- 阴影采样与 shadow caster 仍必须走正式 shader/material/pass contract
- 不允许为了赶进度,在 pipeline 内重新堆一套散乱硬编码绑定
9.2 风险:editor 需求重新污染 runtime 主线
处理策略:
- SceneView 只复用 renderer
- grid/outline/gizmo 始终作为 editor overlay
- runtime 主链以 GameView/真实场景渲染为准
9.3 风险:三后端阴影精度差异导致 GT 不稳定
处理策略:
- 第一版 shadow scene 场景构图应保守
- 阈值控制应严格,但允许合理的小误差
- 优先追求稳定一致,而不是追求复杂阴影表现
9.4 风险:多光源一步做太大
处理策略:
- 先做“有限 additional lights 的前向提交”
- 不提前引入 forward+ 或 deferred
- 以可验证场景为主,不以理论最优为目标
10. 提交与执行节奏
这一阶段继续按“每一步可验证、每一步可提交”的节奏推进:
- 先做
Phase A的数据模型与 shadow request 自动生成 - 测试通过后提交
- 再做
ShadowCaster -> Forward的 shadow map 消费 - 测试通过后提交
- 再做
Phase B的多光源数据模型与 shader 消费 - 测试通过后提交
- 最后做
Phase C / D的接入收口与文档归档
每一步的“通过”都必须包含:
- 至少相关 unit tests 通过
- 至少相关 integration tests 通过
- 如影响主线,必须补跑 rendering regression
11. 成功标准
本阶段完成时,应满足以下判断:
- renderer 能正式生成并消费方向光阴影
- renderer 能正式消费基础多光源
- SceneView 与 GameView 都建立在统一 runtime renderer 主链上
- editor overlay 与 runtime pass 边界清晰
- rendering 测试体系在三后端下持续稳定
12. 一句话总结
下一阶段的核心不是“做更多花哨渲染功能”,而是:
把当前已经具备架构基础的 renderer,推进成一个真正能承担默认场景渲染的 Unity 风格前向运行时。