diff --git a/docs/plan/Renderer下一阶段_Skybox环境与FrameComposition正式化计划_2026-04-05.md b/docs/plan/Renderer下一阶段_Skybox环境与FrameComposition正式化计划_2026-04-05.md new file mode 100644 index 00000000..c35cadad --- /dev/null +++ b/docs/plan/Renderer下一阶段_Skybox环境与FrameComposition正式化计划_2026-04-05.md @@ -0,0 +1,412 @@ +# Renderer 下一阶段:Skybox 环境与 Frame Composition 正式化计划 +日期:`2026-04-05` + +## 1. 阶段定位 + +多光源 forward runtime 这一阶段已经闭环: +- `Directional / Point / Spot` 已接入正式 lighting contract +- `main directional shadow` 已保持稳定 +- 三后端 lighting integration 已有完整回归矩阵 +- Scene / Game View 已复用同一条 runtime renderer 主链 + +因此 renderer 主线现在不应该继续停留在“补光照地基”,而应该进入下一阶段: + +**把当前 renderer 从“单次场景绘制”推进成“正式的相机帧合成框架”,先补齐 `Opaque -> Skybox -> Transparent -> PostProcess -> Final Output` 这条主链。** + +这一步完成后,rendering 主线才算真正具备继续承接: +- skybox / environment +- 正式后处理入口 +- 更稳定的 camera output composition +- 后续 Unity 风格 renderer feature / C# SRP 对接 + +## 2. 为什么现在必须先做这个 + +当前 renderer 虽然已经能稳定画出 lit / unlit / shadow / object-id / editor overlay,但它还不是完整的相机帧合成体系: + +- `BuiltinForwardPipeline` 目前本质上还是“一次场景遍历直接打到最终目标” +- 没有正式 `Skybox` 阶段 +- 没有正式 `Environment` 数据入口 +- 没有 runtime 级别的 `PostProcess` 输入 / 输出约定 +- 还没有“只在需要时启用 intermediate color target”的相机合成策略 + +如果这个阶段不先做,后面不管是: +- 天空盒 +- 环境贴图 +- 曝光 / 色调映射 +- 颜色调整 +- 屏幕空间效果 + +都会继续以临时 pass 拼接的方式往上叠,最后会把当前已经比较干净的 renderer 主链重新拉乱。 + +## 3. 与 Unity / SRP 对齐的原则 + +这一阶段继续严格遵守当前工程的核心分层: + +- `RHI` 只负责 GPU 抽象,不知道 skybox / environment / post-process 语义 +- `Renderer` 负责相机帧规划、scene extraction、frame composition、runtime pass orchestration +- `Editor` 仍然只是 renderer 的宿主和 overlay 使用方 + +与 Unity 风格保持对齐时,本阶段遵守以下原则: + +1. `Skybox / Environment / PostProcess` 都属于 runtime renderer 正式能力,不是 editor 特供逻辑 +2. editor 的 grid / gizmo / icon / selection outline 不进入 runtime frame composition 主链 +3. 不引入 `render graph` +4. 不直接跳到 deferred / clustered / HDRP 级复杂度 +5. 先建立正式 `frame composition seam`,再谈更复杂的 renderer feature + +## 4. 当前真实状态 + +### 4.1 已经具备的基础 + +- `CameraRenderer` 已有明确的请求装配入口 +- `SceneRenderer -> CameraRenderer -> RenderPipeline` 主链稳定 +- 已支持: + - `shadowCaster` + - `depthOnly` + - `main pipeline` + - `objectId` + - `overlayPasses` +- `RenderSceneExtractor` 已有稳定的: + - visible item 提取与排序 + - main light / additional lights 提取 +- `transparent_material_scene`、`depth_sort_scene`、`offscreen_scene` 已证明当前透明与离屏基础可用 + +### 4.2 还没正式化的缺口 + +- 没有 renderer 级 `Skybox` pass contract +- 没有 `RenderEnvironmentData` +- `BuiltinForwardPipeline` 还没有正式拆分成 `Opaque / Transparent` +- 没有“需要 post-process 时自动切到 intermediate color target”的约定 +- 没有 runtime fullscreen pass 基础设施 +- 没有证明 `Skybox + Transparent + PostProcess` 同时存在时仍然稳定的 integration coverage + +## 5. 本阶段总目标 + +本阶段只做一件事: + +**建立一条正式、稳定、三后端一致、可测试的 camera frame composition 主链。** + +收口后应达到: + +1. 场景绘制正式分为 `Opaque -> Skybox -> Transparent` +2. renderer 有正式 `Environment` 数据入口 +3. renderer 有正式 `PostProcess` 输入 / 输出入口 +4. 只在确实需要时才分配 intermediate color target +5. Scene / Game View 继续复用同一条 runtime frame composition 主链 +6. 为后续 Unity 风格 renderer feature / C# SRP 留出清晰承接点 + +## 6. 非目标 + +本阶段明确不做: + +- `render graph` +- deferred rendering +- clustered / tiled lighting +- IBL / reflection probe / light probe +- point / spot shadow +- 全量 post-process 套件 +- 完整 HDR pipeline +- editor-only 视觉效果继续扩张 + +## 7. 设计方案 + +### 7.1 正式化 Camera Frame Composition + +建议把相机级 runtime composition 明确写成固定阶段: + +1. `shadowCaster` +2. `depthOnly`(按需求) +3. `opaque scene` +4. `skybox` +5. `transparent scene` +6. `post-process` +7. `final output resolve / blit` +8. `objectId` +9. `overlay` + +关键原则: + +- `objectId` 继续独立,不混入 runtime final color 主链 +- `overlay` 继续是宿主级 / editor 级最后附加层 +- runtime 的 `Skybox / PostProcess` 是相机帧的一部分,不应再伪装成 editor overlay + +### 7.2 拆分 BuiltinForwardPipeline 的 scene 阶段 + +当前 `BuiltinForwardPipeline` 虽然能依赖 render queue 正确排序,但 skybox 正式接入后,必须让 runtime scene path 至少具备: + +- `OpaquePass` +- `TransparentPass` + +原因很直接: + +- skybox 必须有正式插入点 +- transparent 需要在 skybox 之后 +- 以后 post-process 输入也需要明确“scene color 到哪里结束” + +这里不需要推翻现有 forward lit / unlit 合约,只需要把当前单次遍历拆成正式两个阶段,并保持现有材质状态和排序行为不回退。 + +### 7.3 正式化 Environment 数据入口 + +建议新增 renderer 级环境数据模型,例如: + +- `RenderEnvironmentData` + - `clearMode` + - `skyboxMaterial` + - `skyboxEnabled` + - 后续可扩展环境颜色 / 曝光 / cubemap 引用 + +第一版原则: + +1. 先解决“环境如何进入 renderer” +2. 不在这一阶段强行上完整 IBL +3. 不把 environment 设计成 editor 专属状态 + +### 7.4 Skybox 首版策略 + +首版建议优先做 **builtin procedural skybox**,而不是一开始就把阶段拖进 cubemap / probe / importer 链路。 + +理由: + +- 目标是先打通正式 `skybox pass` +- procedural skybox 更容易稳定三后端一致 +- 更容易写 GT 和像素断言 +- 不依赖 cubemap 资源导入闭环 + +首版可以支持: + +- top / horizon / bottom color +- 视线方向驱动的渐变 + +后续再扩成 cubemap skybox,不会推翻本阶段的 frame composition 设计。 + +### 7.5 Post-Process 正式入口的最小闭环 + +本阶段不追求“后处理功能多”,只追求“后处理入口正式化”。 + +建议最小闭环: + +1. 建立 fullscreen pass 基础设施 +2. 建立 `post-process source -> destination` 约定 +3. 建立 intermediate color target 的按需分配策略 +4. 用一个简单、稳定、三后端一致的 builtin fullscreen effect 做验证 + +验证 effect 不需要复杂,建议: + +- `ColorTint` +或 +- `GammaAdjust` +或 +- `FinalCopy + optional color scale` + +关键不是效果本身,而是证明: + +- scene color 能被正式读回 +- fullscreen pass 能稳定写到目标 +- camera final output 路径已具备后续扩展能力 + +### 7.6 Intermediate Color Target 策略 + +不能把所有相机都默认改成“永远先画离屏再 blit”,否则会徒增复杂度和性能成本。 + +建议规则: + +- 默认直接渲染到最终目标 +- 当存在 `Skybox / PostProcess / 特定 composition 需求` 时,按需启用 intermediate color target +- 这个判断应由 `CameraRenderer` 或 request planner 明确控制,而不是散落在具体 pass 内部 + +### 7.7 与 Unity 风格 SRP 的承接关系 + +这一阶段完成后,renderer 主链会更接近 Unity/URP 的基本心智模型: + +- scene opaque +- skybox +- transparent +- post-process +- final target + +这一步不是为了机械模仿 Unity,而是为了给以后 C# 层 SRP / renderer feature 建立正确的宿主结构。 + +## 8. 实施分阶段 + +## 8.1 Phase A:Frame Composition 合约正式化 + +### 目标 + +把相机级帧合成顺序从“隐式拼接”改成正式 contract。 + +### 工作项 + +- 明确 runtime frame composition 阶段枚举 / 顺序 +- 调整 `CameraRenderer` 的 orchestration 结构 +- 明确 `objectId`、`overlay` 与 runtime frame composition 的边界 + +### 验收标准 + +- 相机帧阶段顺序明确且可追踪 +- 现有 `multi_light / transparent / offscreen` 不回退 + +## 8.2 Phase B:Opaque / Skybox / Transparent 正式分段 + +### 目标 + +让 builtin forward runtime scene path 具备正式 `Opaque / Transparent` 结构,并为 skybox 提供插入点。 + +### 工作项 + +- 拆分 `BuiltinForwardPipeline` +- 保持现有 render queue 语义 +- 保持透明排序与材质状态回归不破坏 + +### 验收标准 + +- `transparent_material_scene` +- `depth_sort_scene` +- `material_state_scene` + +三后端继续通过 + +## 8.3 Phase C:Skybox / Environment 首版闭环 + +### 目标 + +让 renderer 正式支持 runtime skybox。 + +### 工作项 + +- 新增 `RenderEnvironmentData` +- 新增 builtin procedural skybox pass / shader +- 将 skybox 接入 camera frame composition +- 保持 clear color fallback 行为可控 + +### 验收标准 + +- 新增 `skybox_scene` +- 同时存在 opaque + skybox + transparent 时顺序正确 +- 三后端 GT 稳定 + +## 8.4 Phase D:Post-Process 入口闭环 + +### 目标 + +建立正式 fullscreen post-process 入口,而不是继续依赖临时 pass。 + +### 工作项 + +- fullscreen pass helper +- intermediate color target 按需分配 +- final blit / resolve 规则 +- 一个最小 builtin post-process 验证效果 + +### 验收标准 + +- 新增 `post_process_scene` +- `offscreen_scene` 不回退 +- 三后端 GT 稳定 + +## 8.5 Phase E:测试与文档收口 + +### 目标 + +让本阶段收口后,`docs/plan` 的主线入口与真实实现再次一致。 + +### 工作项 + +- 更新 `tests/TEST_SPEC.md` +- 输出 renderer frame composition 阶段说明 +- 将本阶段完成计划归档到 `docs/used` + +### 验收标准 + +- 文档、实现、测试矩阵三者口径一致 + +## 9. 测试策略 + +### 9.1 Unit + +- frame composition 阶段决策 +- intermediate target 启用条件 +- skybox / post-process request 装配 + +### 9.2 Integration + +新增: + +- `skybox_scene` +- `post_process_scene` + +回归: + +- `multi_light_scene` +- `spot_light_scene` +- `directional_shadow_scene` +- `camera_stack_scene` +- `transparent_material_scene` +- `cull_material_scene` +- `depth_sort_scene` +- `material_state_scene` +- `offscreen_scene` + +### 9.3 Editor Runtime Smoke + +- SceneView / GameView 继续复用同一条 runtime frame composition +- object-id picking 不因 frame composition 改造回退 +- editor overlay 不污染 runtime skybox / post-process + +## 10. 风险与控制 + +### 风险 1:为了接 skybox 强行把所有相机都改成离屏 + +后果: + +- 复杂度和成本无意义上升 +- 调试链路变长 + +控制策略: + +- intermediate target 只按需启用 + +### 风险 2:skybox 设计一开始就绑死 cubemap / IBL + +后果: + +- 阶段再次失焦 +- 资源链路耦合过早 + +控制策略: + +- 首版先做 builtin procedural skybox + +### 风险 3:post-process 入口继续走 editor 旧路径 + +后果: + +- runtime / editor 边界重新混乱 + +控制策略: + +- runtime post-process 必须是 renderer 正式阶段 +- editor overlay 继续留在最后 + +## 11. 阶段完成判定 + +满足以下条件时,本阶段可视为收口: + +1. renderer 具备正式 `Opaque -> Skybox -> Transparent -> PostProcess -> Final Output` 结构 +2. skybox 有正式 runtime 数据入口与首版实现 +3. post-process 有正式 fullscreen 入口与最小闭环 +4. `skybox_scene` 与 `post_process_scene` 三后端通过 +5. 现有 lighting / transparency / offscreen / camera stack 回归不破坏 + +## 12. 本阶段之后的正确下一步 + +当这一步收口后,renderer 主线的下一阶段才应该考虑: + +1. cubemap skybox / environment map +2. 曝光 / tone mapping / color grading 正式化 +3. 更高阶的 renderer feature / C# SRP 承接层 + +而不是现在就跳去: + +- `render graph` +- deferred +- editor-only 特效堆叠 diff --git a/docs/used/Renderer下一阶段_多光源正式化与Lighting闭环计划_完成归档_2026-04-05.md b/docs/used/Renderer下一阶段_多光源正式化与Lighting闭环计划_完成归档_2026-04-05.md new file mode 100644 index 00000000..63e645dc --- /dev/null +++ b/docs/used/Renderer下一阶段_多光源正式化与Lighting闭环计划_完成归档_2026-04-05.md @@ -0,0 +1,526 @@ +# 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` 和 `mainDirectionalShadow` +- `RenderSceneExtractor` 只会提取一个主方向光 +- `BuiltinForwardPipeline` 只消费这一套最小 lighting 数据 +- `LightComponent` 虽然已经有 `Directional / Point / Spot` 三种类型,但 runtime renderer 还没有把它们正式接通 + +这意味着现在的 renderer 已经不是“不能用”,而是: + +**单方向光路径可用,但正式多光源路径缺失。** + +如果这时去做 `render graph`,只是给尚未完全闭环的 runtime lighting 套上更复杂的调度壳。 +如果这时去继续堆 editor 视觉功能,也是在建立在不完整 runtime 光照基础之上。 + +所以正确顺序必须是: + +1. 先把多光源正式化 +2. 再进入 skybox / environment / post-process seam +3. 最后才考虑 render graph 这类更高层调度框架 + +## 3. 与 Unity 风格架构的对齐原则 + +本阶段继续严格遵守当前工程的核心分层: + +- `RHI` 只负责 GPU 抽象 +- `Renderer` 负责 scene extraction、lighting data、pass orchestration、shader/material contract +- `Editor` 只作为 renderer 宿主与 overlay 使用方,不拥有独立 runtime lighting 主链 + +与 Unity 风格对齐时,本阶段遵守以下原则: + +1. 主方向光与 additional lights 属于 runtime renderer 正式能力 +2. editor 的 grid / outline / gizmo / icon 不是本阶段主线 +3. shader/material 仍然走统一 `.shader + Pass + backend variants` 路线,而不是退回后端硬编码 +4. 当前阶段先做“有限 additional lights 的前向提交”,不直接跳到 clustered / deferred + +## 4. 当前真实现状 + +### 4.1 已完成的部分 + +- 自动方向光阴影规划已经存在 +- `CameraRenderer` 已有正式 pass 顺序: + - `preScenePasses` + - `shadowCaster` + - `depthOnly` + - `main pipeline` + - `objectId` + - `postScenePasses` + - `overlayPasses` +- `BuiltinForwardPipeline` 已形成正式 shader/material/pass contract +- editor Scene/Game viewport 已经走 runtime renderer 主链 +- `object-id` picking 已经是正式主路径 + +### 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。** + +收口后应达到: + +1. `Directional / Point / Spot` 三类光源能通过 runtime renderer 正式影响画面 +2. 主方向光阴影能力保持不回退 +3. 三后端使用同一套 shader/material contract +4. Scene/Game View 继续直接复用同一条 runtime renderer 光照路径 +5. 为下一阶段 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` 从: + +- `mainDirectionalLight` +- `mainDirectionalShadow` + +扩展为: + +- `mainDirectionalLight` +- `mainDirectionalShadow` +- `additionalLights` + +其中 `additionalLights` 的单项建议包含: + +- `type` +- `enabled` +- `color` +- `intensity` +- `position` +- `direction` +- `range` +- `spotAngle` +- `castsShadows` + +这里的关键原则是: + +1. 主方向光继续单独建模 +2. additional lights 统一为一个正式数组,而不是分散塞进临时常量 +3. 当前阶段允许 additional lights 无阴影 +4. 数据模型要能自然承接后续 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 提取。 + +首版建议策略: + +1. 过滤掉无效灯光 + - component disabled + - game object inactive + - 不在 camera culling mask 内 +2. 选择主方向光 + - 仍沿用“最重要的 directional light 单独提升为 main light”的策略 +3. 其余光源进入 additional list +4. 对 additional list 做稳定排序 +5. 截断到最大上限 + +为了保证输出稳定、便于 GT 固化,建议排序规则写死为: + +1. additional directional lights 优先 +2. point / spot 在后 +3. 同类型内按影响力降序 +4. 影响力相同则按 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 参数 +- `BaseColorTexture` +- `LinearClampSampler` +- `ShadowMapTexture` +- `ShadowMapSampler` + +这一步非常关键,因为它决定后续扩展是否正规: + +1. scene/frame lighting 不再随每个 draw 重复写入 `PerObject` +2. additional light 数组有正式宿主 +3. 三后端可以共享同一份高层资源声明 + +### 7.5 三后端 shader 路线必须保持统一 + +本阶段继续沿用当前已经建立起来的 shader 路线: + +- 高层作者视图仍是统一 `.shader` +- 每个 `Pass` 通过 backend variants 指向: + - OpenGL GLSL + - Vulkan GLSL + - D3D12 HLSL + +也就是说: + +1. 不在材质系统层面分裂成三套 API 专属 shader 入口 +2. forward lit pass 的资源声明只保留一份 canonical contract +3. 三后端只在 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 全链路重构,建议首版这样处理: + +1. `outer cone` 直接使用 `spotAngle` +2. `inner cone` 由 runtime 以固定比例推导 + - 例如 `inner = outer * 0.8` +3. 等 shader/material 与 renderer 多光源闭环稳定后,再决定是否把 `innerSpotAngle` 正式上升为组件字段 + +这能保证当前阶段先把 runtime 多光源打通,而不是被 editor 数据建模拖慢。 + +### 7.8 BuiltinForwardPipeline 的正式改造方向 + +`BuiltinForwardPipeline` 本阶段要完成的,不只是“shader 多写几行光照循环”,而是正式接管以下职责: + +1. 创建/维护 `Lighting` 常量资源 +2. 每帧更新一份 bounded additional light 数据 +3. 在 draw 时稳定绑定 `Lighting` 与 `ShadowReceiver` +4. 保持 `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_scene` +- `tests/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 + +- `RenderSceneExtractor` multi-light 提取 +- `BuiltinForwardPipeline` lighting resource layout / descriptor binding +- light attenuation 数学辅助函数 + +### 9.2 Integration + +- `multi_light_scene` +- `spot_light_scene` +- 回归: + - `directional_shadow_scene` + - `backpack_lit_scene` + - `camera_stack_scene` + - `transparent_material_scene` + - `cull_material_scene` + - `depth_sort_scene` + - `material_state_scene` + - `offscreen_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. 阶段完成判定 + +满足以下条件时,本阶段可以认为收口: + +1. `RenderLightingData` 已正式支持 additional lights +2. `BuiltinForwardPipeline` 已正式消费 bounded additional lights +3. `multi_light_scene` 与 `spot_light_scene` 三后端通过 +4. `directional_shadow_scene` 与 `backpack_lit_scene` 无回退 +5. Scene/Game View 继续通过统一 runtime renderer 显示一致光照结果 +6. 文档与测试矩阵已同步 + +## 12. 本阶段之后的正确下一步 + +多光源阶段收口后,renderer 的下一阶段才应该进入: + +1. skybox / environment seam +2. post-process 正式入口 +3. 更完整的 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 主线的正式下一阶段。