Files
XCEngine/docs/plan/MainLight方向光阴影修复计划_2026-04-13.md

228 lines
7.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# MainLight 方向光阴影修复计划
日期: `2026-04-13`
## 1. 文档定位
这份文档是基于当前仓库代码状态重新整理的版本,用来承接 MainLight 单张方向光阴影的后续修复工作。
需要明确:
- 这不是对之前已删除计划文件的逐字恢复。
- 这是一份按当前实现状态、最近两次提交和现有阴影链路重新整理的执行计划。
- 当前目标不是上级联阴影,而是先把单张 MainLight 阴影做到可用。
## 2. 当前问题定义
当前 MainLight 阴影已经具备从规划、投射到接收采样的完整闭环,但实际效果仍然不可用,核心问题有两个:
1. 自阴影过重,表面出现明显 acne。
2. 阴影边缘呈现大块锯齿,采样质量不足。
当前阶段暂不解决:
- 级联阴影
- 点光 / 聚光阴影
- 阴影时域稳定与降噪的完整方案
- 多光源阴影编排
## 3. 当前阴影链路梳理
当前单张 MainLight 阴影主链如下:
`SceneRenderRequestPlanner`
-> `DirectionalShadowRenderPlan`
-> `CameraRenderer`
-> `ShadowCaster Pass`
-> `RenderSceneData::lighting.mainDirectionalShadow`
-> `BuiltinForwardPipeline`
-> `forward-lit.shader / Toon.shader`
关键代码位置:
- 规划层
- `engine/include/XCEngine/Rendering/Planning/SceneRenderRequestPlanner.h`
- `engine/src/Rendering/Planning/Internal/DirectionalShadowPlanning.cpp`
- 请求与运行时数据
- `engine/include/XCEngine/Rendering/Planning/CameraRenderRequest.h`
- `engine/include/XCEngine/Rendering/FrameData/RenderSceneData.h`
- `engine/src/Rendering/Execution/CameraRenderer.cpp`
- ShadowCaster 消费 bias
- `engine/include/XCEngine/Rendering/Passes/BuiltinDepthStylePassBase.h`
- `engine/src/Rendering/Passes/BuiltinDepthStylePassBaseResources.cpp`
- `engine/assets/builtin/shaders/shadow-caster.shader`
- 接收端采样
- `engine/src/Rendering/Pipelines/BuiltinForwardPipeline.cpp`
- `engine/assets/builtin/shaders/forward-lit.shader`
- `project/Assets/Shaders/Toon.shader`
## 4. 已完成阶段
### Phase 0阴影参数契约正式化
已完成,目标是先把原来散落在不同位置的 shadow 参数收成正式数据契约。
对应提交:
- `2ee74e7` `rendering: formalize main light shadow params`
完成结果:
- MainLight shadow 的 map metrics / sampling 数据有了明确结构。
- 规划层到运行时数据链路不再依赖匿名 float 参数拼装。
### Phase 1bias 设置正式化并接入 ShadowCaster
已完成,目标是把 caster bias 和 receiver bias 的职责拆清楚,并让 ShadowCaster 真正消费运行时设置。
对应提交:
- `1d6f2e2` `rendering: formalize main light shadow bias settings`
完成结果:
- 新增 `DirectionalShadowSamplingSettings`
- 新增 `DirectionalShadowCasterBiasSettings`
- planner 能输出 sampling / caster bias 默认值
- `ShadowCaster` pass 不再依赖 shader 内部写死的 `Offset`
- forward / toon 接收端继续消费统一的 shadow sampling contract
## 5. 根因判断
### 5.1 自阴影严重的根因
当前 acne 的根因不是单一问题,而是以下几项叠加:
1. caster bias 与 receiver bias 原先没有清晰契约,调参入口混乱。
2. receiver 端 normal bias 和 depth bias 默认值没有经过系统标定。
3. caster 端深度偏移之前由 shader 写死无法和场景尺度、shadow map texel 尺度统一调整。
### 5.2 阴影锯齿严重的根因
当前接收端虽然已经做了一个固定 3x3 手写采样,但效果仍然偏糙,原因主要是:
1. 当前仍然是单张 shadow map分辨率预算有限。
2. 阴影采样核是最基础的固定 3x3 box没有更平滑的权重设计。
3. `BuiltinForwardPipeline` 里的 shadow sampler 目前仍是 point sampler。
4. 当前还没有专门面向“单张 MainLight 阴影可用性”的 filter 参数设计。
### 5.3 当前不应优先处理的方向
以下方向现在都不是第一优先级:
- 直接上级联阴影
- 直接引入更复杂的多光源阴影系统
- 先大改 planner 架构
原因很简单:如果当前单张阴影的 bias 和 filter 基线都没有站稳,上级方案只会把问题放大。
## 6. 下一阶段执行顺序
## Phase 2建立可用的 bias 基线
这是下一步最高优先级。
目标:
- 明显压住自阴影 acne
- 不引入明显 peter-panning
- 让不同材质和几何体至少达到“能看”的单张阴影结果
本阶段只调这四个核心参数:
- `DirectionalShadowCasterBiasSettings.depthBiasFactor`
- `DirectionalShadowCasterBiasSettings.depthBiasUnits`
- `DirectionalShadowSamplingSettings.receiverDepthBias`
- `DirectionalShadowSamplingSettings.normalBiasScale`
执行要点:
1. 先以默认值为基线做小步调参,不再混用 shader 内固定 offset。
2. 先看 caster bias 是否足以压掉大面积 acne再看 receiver bias 是否还需要补偿。
3. `normalBiasScale` 只用于削减掠射角表面 acne不能把它当成主修复手段。
4. 调参顺序优先保证“角色和常见静态模型表面不脏”,再控制阴影悬浮。
验收标准:
- 球、立方体、角色模型等常见几何体上没有大片自阴影脏斑。
- 接触阴影没有整体漂浮一截。
- forward-lit 与 toon 两条接收路径结果一致性不回退。
## Phase 3升级单张阴影采样质量
这个阶段才开始处理“大块锯齿”。
目标:
- 让当前单张 MainLight shadow 的边缘从“块状锯齿”变成“有限预算下可接受的软化边缘”
优先处理项:
1. 升级当前固定 3x3 box 采样,不再停留在最基础平均核。
2. 明确是否继续走跨后端一致的手写 PCF还是为 comparison sampler 单独补后端支持。
3. 如果继续保持跨后端一致性优先,则先做更好的手写 PCF 核,再评估 comparison sampler。
本阶段建议的最小落地方案:
- 先保留单张 shadow map
- 先保留当前主链结构
- 把 receiver 端阴影采样从固定 3x3 平均核升级为更稳定的 PCF 核
- 如有必要,再补 `filterRadiusInTexels` 一类的正式参数
验收标准:
- 阴影边缘不再呈现明显的 1-bit 台阶块状感。
- 角色和场景静态物体阴影边缘的可读性明显提升。
- 不因为滤波升级导致阴影整体发灰或漏光严重。
## Phase 4单张方向光阴影稳定性收口
在 bias 和 filter 达到可用以后,再收口稳定性问题。
目标:
- 降低相机轻微移动时的 shadow crawl / shimmering
重点项:
1. 审查当前 shadow camera 拟合结果是否需要 texel snapping。
2. 审查 ortho bounds 与 focus point 的稳定性。
3. 重新评估 `boundsPadding` / `minDepthPadding` / `minDepthRange` 的默认值是否过保守或过激进。
说明:
这一阶段仍然是“单张 MainLight 阴影修好”,不是进入级联阴影。
## Phase 5为后续级联阴影预留演进点
只有前面几个阶段都稳定后,才进入这一阶段。
目标:
- 让当前单张 MainLight 阴影实现不阻塞未来 CSM 演进
需要预留但暂不展开的点:
- split 数据结构
- 每级 shadow map / sampler / matrix contract
- 接收端 cascade 选择逻辑
- 级联间过渡和稳定化
## 7. 推荐的提交切分
后续建议按下面的提交粒度推进:
1. `rendering: tune main light shadow bias defaults`
2. `rendering: improve main light shadow receiver filtering`
3. `rendering: stabilize single-map directional shadow fitting`
## 8. 当前结论
当前正确的下一步不是“直接做级联阴影”,而是:
1. 先把 bias 默认值标定到可用区间。
2. 再把当前接收端采样升级成真正可用的单张 shadow filter。
3. 最后再处理单张阴影稳定性。
只有这三步完成,当前 MainLight 阴影才算真正脱离“占位实现”。