两种尺度下的两项技术。DDGI 把一次反弹的间接光带到整个房间; GTAO 则加深辐照度探针因粒度太粗而无法分辨的褶皱。两者都完全 动态,也都是无需改动场景代码就能关闭的 compute 特效。
基于场景有符号距离场体素化的动态漫反射全局光照。探针对着 SDF 追踪光线,把辐射度累积进辐照度图集,并用切比雪夫遮蔽—— 每个探针命中距离的均值与方差——来拒绝穿透墙壁漏光。 它完全动态:移动一面墙,反弹光就会跟随。
地面实况环境光遮蔽在 AfterScene compute 阶段运行,且只应用于 间接漫反射,因此它与 glTF 遮蔽贴图是叠加关系而不是互相对抗。
// In the app constructor, before
// graphics initialization:
RenderQuality.DefaultGlobalIllumination
= GiMode.Ddgi;
// At runtime, through the live tier:
RenderQuality.Current.GiIntensity = 0.6f;
RenderQuality.Current.AoIntensity = 0.8f;
GlobalIllumination 是初始化时读取的模式——
它烘焙着色器变体并分配探针链——所以之后切换它改变的是强度,
而不是成本。引擎会明确记录哪些旋钮是实时的、哪些是锁定的,
而不是隐藏这种差异。
DDGI · GTAO · TAA
默认值描述了一个覆盖 32 单位立方体的 16×8×16 网格—— 2048 个探针——每个探针投射 128 条光线,每帧刷新一半网格。 选择这些数字是为了让 DDGI 在笔记本 GPU 上负担得起, 而不是让它达到最好的效果。
| 设置 | 默认值 | 含义 |
|---|---|---|
GiProbeGridX/Y/Z | 16 / 8 / 16 | 每个轴的探针数量。Y 刻意更浅——房间的宽度大于高度。 |
GiVolumeSize | 32 | 体积的世界单位边长。探针间距等于它除以网格数。 |
GiSdfResolution | 64 | 探针所追踪的 SDF 的体素分辨率。 |
GiRaysPerProbe | 128 | 每次探针更新投射的光线数。 |
GiProbeUpdateDivisor | 2 | 每帧刷新的探针比例;2 表示一半。 |
GiTraceMaxSteps | 64 | 每条光线的球体追踪步数预算。 |
GiShadowSteps | 24 | 朝太阳方向的阴影光线的步数预算。 |
体积跟随相机,因此 32 单位的立方体是间接光上的移动窗口, 而不是场景大小的界限。大型开放场景仍然会失去远处的反弹光—— 单级联探针就是这里的诚实上限。
可用 DDGI 与不可用 DDGI 之间的差别,大部分在于漏光拒绝和 探针遗忘的速度。下面是这两方面的旋钮。
| 设置 | 默认值 | 含义 |
|---|---|---|
GiChebyshevOcclusion | on | 基于方差的可见性测试。关掉它是理解它为何存在的最快方式。 |
GiProbeValidity | on | 把几何内部的探针标记为无效,使其停止贡献。 |
GiNormalBias | 0.25 | 沿法线把采样点推离表面,是自漏光的常规疗法。 |
GiBackfaceThreshold | 0.5 | 背面命中比例超过该值即视为探针被封闭。 |
GiHysteresis | 0.97 | 探针辐照度的时间混合。越低反应越快、闪烁越多。 |
GiBackfaceHysteresis | 0.99 | 对主要看到背面的探针使用更慢的混合。 |
GiIntensity | 0.4 | 缩放间接光贡献。实时。 |
GiBounceGain | 1.0 | 探针间反弹的反馈增益。 |
GiPunctualShadow | off | 探针光线是否除太阳外也受点光源遮挡。 |
在 0.97 时,一个探针大约需要三十帧才能收敛到新的光照条件。 打开一盏灯,反弹光要半秒多才淡入。降低该值它会更快到达, 但过程中会沸腾。没有能两者兼得的设置。
探针不追踪你的三角形。它们追踪一个有符号距离场,该场由控件在帧期间
贡献的代理体积构建——而
GiProxies.MaxProxies 是 64。
六十四个代理,放在一个 4 KB 缓冲区里。超过之后,
GiProxies.Overflow 变为 true,多余的体积被丢弃——
这些几何体仍然被绘制、仍然被直接光照亮,但对间接光不可见。
如果反弹光穿透了某个实体,请检查 Count 和
Overflow。
控件通过重写
CollectGiProxy 并调用
TryAdd 或
TryAddSphere 来加入该场;两者在预算耗尽时返回 false
而不是抛异常。Control 上两个关键表面属性是:
| 属性 | 含义 |
|---|---|
GiAlbedo | 代理反射的颜色。红墙正是通过它给房间染上红色,而不是通过其纹理。 |
GiEmissive | 代理发射的颜色,发光物体正是这样在不作为光源的情况下贡献反弹光。 |
实际结论:给墙壁、地板和大型遮挡物做代理,把杂物排除在外。 六十四个描述房间的粗略体积,胜过六十四个描述家具的体积。
地面实况环境光遮蔽,在 AfterScene 阶段由场景深度和法线计算,并以
compute://gtao/ao 发布。它处理 DDGI 无法处理的
尺度:椅腿与地板相接处的暗化完全位于单个探针单元之内。
| 设置 | 默认值 | 含义 |
|---|---|---|
AmbientOcclusion | Gtao | 模式选择器;初始化时读取。 |
AoRadius | 0.5 | 世界空间采样半径,以单位计。实时。 |
AoIntensity | 1.0 | 遮蔽项的强度。实时。 |
AO 只应用于间接漫反射。把它应用于直接光是常见的捷径, 会在受光表面上产生暗边,而这里并非如此——这也意味着在 没有环境光或 GI 可遮蔽的场景里,AO 看起来会更弱。
正是为此存在两个调试特效。
Sdf3DViewEffect 渲染一个与探针所追踪类型相同的
距离场切片,DdgiEffect 则在
compute://ddgi/sdfslice 下发布自己的切片,
与辐照度和深度图集并列。两者都是可寻址纹理,因此把它们放上屏幕
只需一个 Sprite2D。如果 GI 看起来不对,答案通常在
SDF 里:没有代理的物体根本不在场里。
后处理与 compute 特效 介绍了这些调试视图 是如何注册的,Apps/Engine 展示了它们接到 屏幕开关上的样子。