实时渲染-06:三维全局光照
一次反弹
全局光照 Global Illumination,GI 包含光在场景中的直接传播和表面间反射。窗户照亮地板,地板又照亮没有直接看到窗户的墙面;彩色墙面反射的光还会改变附近物体的颜色,这种现象称为 Color Bleeding。给所有物体统一加一个环境常量,无法表达这些位置、方向和颜色的差异。
从路径追踪的观察顺序看,相机先看到点 ,再从 向某方向找到表面 ,最后计算主光源如何照亮 。反过来看光的传播,是“主光源 相机”。直接受光的 可以当成次级光源 Secondary Light Source,将其反射光作为接收点的入射光。
课程首先关注一次间接反弹。需要回答两个问题:哪些表面被主光源直接照亮?每个受光表面对当前点贡献多少?如果从主光源看场景,最先看到的表面正是它能直接照到的表面,Shadow Map 已经能记录这一层几何。
反射阴影图
反射阴影贴图 Reflective Shadow Map,RSM 在普通 Shadow Map 的深度之外,保存受光表面的位置、法线和反射光量。每个有效纹素对应一个小面片 Patch,之后将这些面片当成一组次级光源查询。

从左至右依次是深度、世界位置、法线与反射光量。中间两幅中的 RGB 是数值编码:世界坐标映射为颜色,单位法线也映射到颜色范围,并不是表面的实际材质色。最右侧才包含不同表面反射光的颜色。
RSM 只从一个光源视角观察,却希望知道面片朝接收点的出射辐亮度。为了让这一方向变化可处理,将次级反射面片近似为 Lambertian:
对于固定的入射照明,Lambertian 出射辐亮度不随观察方向变化,因此向光源方向记录的结果可用于面片的其他正面方向。这一假设针对次级源 ;接收点 仍可以使用 Glossy BRDF。
辐射通量 Radiant Flux 是总功率,辐射强度 Radiant Intensity 是单位立体角功率,辐照度 Irradiance 是单位接收面积上的入射功率,辐亮度 Radiance 还同时按投影面积和立体角归一化。它们的方向、面积因子不同,不能都用“亮度”代替后直接套同一个距离衰减。
面片贡献
令 ,,。从接收点看面片,只有其朝向接收点的投影面积起作用:

图中上方的 面片面积为 ,向 投影时缩小为 。距离越远,同一投影面积占据的方向范围越小,按 缩小。下方接收面的 则来自渲染方程中接收侧的投影。这两个余弦分别属于不同表面。
将立体角积分改写为面片面积积分:
其中 ,。将小面片用中心点近似,定义 ,则离散贡献是
面积已含在 中,求和时不用重复乘面积。若存储真正的 Lambertian 总反射通量 ,有 ,计算前应除以 。不同 RSM 表达把“flux”归一化因子吸收到不同位置,实现时必须按存储定义一致处理。
距离项
单位方向的余弦形式使用 分母;若分子直接对位置差向量点积,则每个点积多出一个 :
所以原论文中的 与归一化余弦写法的 完全等价。只改分母、不同时核对分子向量是否归一化,会造成错误的距离变化。
无参与介质的自由空间中,辐亮度沿射线传播不随距离衰减。这里的平方反比来自面积与立体角的几何换算,不是在传播过程中再削弱一次辐亮度。
RSM 纹素的光源投影面积相同,代表的实际表面面积未必相同。表面倾斜或采用透视光源时,应在反射量生成中处理对应面积或采样权重,否则接收求和的能量会随投影方式变化。
遮挡与采样
主光源到 的遮挡通过光源视角渲染处理了, 到 的遮挡仍然未知。若为每个次级源再建阴影图,成本会很高。基础 RSM 因而常省略 ,结果可能穿过本应挡光的物体。

黄色线描出直接受光表面,红点 是接收点。某些面片与 之间被桌体挡住,某些面片朝向不对,即使光源能看见它们,也不一定对 有贡献;同一地面上的源还可能因为接收余弦为零而没有贡献。距离很远的面片通常贡献较弱,但不能仅凭“远”严格认定为零。
一张 RSM 有 个纹素,每像素遍历全部纹素不适合实时处理。将 投到光源图中,在其投影附近选择少量面片,利用“图像附近往往在空间上也较近”的近似减少开销。这一关系在深度断层处容易失效。

中心附近采得更密,外围稀疏;圆的半径表示估计权重增大,不是面片自身变大。以离散纹素集合为例,若按概率 选取 个样本,无偏求和估计需要
只覆盖局部邻域会额外遗漏邻域之外的贡献。约 个样本是课程的示例预算;扩大邻域、调整密度或更换场景后,样本数与权重也要重评估。将面片当成点源还会使极近距离项过大,可通过有限面片处理或距离正则化抑制,但后者引入偏差。
1 | // 第一趟:从主光源视角生成直接受光面片。 |
实际代码还应跳过自面片、无效纹素与退化距离,避免将背景深度当成有效次级源。
局部反弹

下排开启反弹照明后,植被附近的绿色传到了顶棚和周围暗区;直接光照覆盖范围基本不变,变化来自受光表面再次反射。少量局部色彩贡献已经能够表现光源与环境的关系,不必把每处暗区都用统一环境项加亮。
RSM 易与 Shadow Map 管线结合,也与 Virtual Point Light,VPL 的思路相关:将受光面片离散为一组虚拟光源。Instant Radiosity 同样利用虚拟光源近似间接照明,但产生样本的过程不同。
每个主光源通常需要一份 RSM,成本随主光源数量增长。忽略次级可见性、次级源漫反射假设、投影邻域采样和有限面片近似,都会影响质量。虽然数据存在二维图像中,它来自光源视角并保存世界位置,不只局限于最终相机的当前画面;这是课程将它归入三维 GI 的原因。
光传播体积
RSM 让每个接收点反复查询许多面片。光传播体积 Light Propagation Volumes,LPV 尝试先将光照送到整个空间,再让接收点查询附近的光照记录。
将场景划为三维网格,单个格子称为体素 Voxel。每个体素保存随方向变化的辐射信息,课程用前两带 SH 共四项来近似,记录较粗的方向分布,而不保存精确的每条光线。
LPV 的处理顺序为 Generation、Injection、Propagation、Rendering:先找受光面片,再注入网格,之后传播若干轮,最后查询着色。这些数据可随光源变化重算,因此区别于固定场景下的离线 PRT。
注入与传播
Generation 可以复用 RSM 面片;Injection 将面片放进对应体素,对其出射方向分布投影并累加四个 SH 系数。课程的低阶实现以漫反射次级源近似为主,低阶 SH 会抹去很窄的方向瓣。

粉色箭头表示受光蓝色表面发出的反射光,红框内的 SH 图形表示这一格保存的方向分布。黄色是主光源直接照到的区域,不能把注入格子的反射光与直接照明混为一份量后重复相加。
传播时,从邻格共享面的方向范围收集辐射,转换成当前格的 SH 表示。三维网格有六个面邻居;二维示意只画四个。对角格可以经过多次轴向传播到达。

图中 到 逐步显示不同邻面贡献如何叠加到中央格的方向分布;这是一次收集邻格的示意,不能将四幅图直接解释为四次物理反弹。整个网格完成一轮后,再基于上一轮的数据传播下一轮。课堂举约四到五轮的例子,实际轮数影响覆盖距离、误差和成本。
将方向积分和 SH 投影组合成邻面传输算子 ,可以概括为
必须用上一轮网格读取、新网格写入,避免更新顺序改变传播结果;各轮贡献是否累积、是否重复计数则依具体传播设计处理。这里的迭代是离散空间中的传递,不是物理时间积分。没有额外表面相互作用时,增加传播轮数主要使光走得更远,不能自动等价为增加真实反射次数。
体积误差
着色点找到所在格或周围格,插值得到方向光照,再结合接收 BRDF 积分。接收侧可以是 Glossy,但只有四项的入射表示无法保留尖锐反射细节。

左图屋檐内侧比参考图亮,反映了粗体素与不完整遮挡造成的漏光。若一个格子同时跨过墙的前后两侧,格内近似均匀的光照记录无法区分两侧;传播再省略格间可见性,光便可能穿过墙体。
提高分辨率能减小部分误差,但每个维度加倍,三维体素数就增为八倍,多轮传播的读写成本也增加。级联 Cascade 网格可以在近处保留细格、远处用粗格,平衡局部细节与空间范围;不同网格交界仍需处理插值和更新。
光源变化后重新注入与传播,可以得到动态 Color Bleeding。但光照的平滑程度、薄几何和遮挡精度仍受体积表示约束。带介质吸收或散射的传播还需要其他项,不能沿用“真空辐亮度不衰减”来忽略介质效应。
体素光照
体素全局光照 Voxel Global Illumination,VXGI 同样使用三维网格,但处理方式不同。它先将场景几何体素化并保存局部光照,接收点再按所需方向查询这些体素;不先像 LPV 那样把光照反复传播到整个空间。

左图红色网格表示场景被离散成体素;右图表现不同大小格子的层级。细层记录局部结构,粗层汇总较大空间范围,可用八叉树或类似三维 mip 层级组织。层级需要保存占据、透明度或覆盖信息,以及辐射和法线的方向信息;只存一个平均颜色不足以描述任意方向反射。
第一阶段生成直接光照,将其与体素化几何及方向信息关联,再构造粗层;第二阶段由相机接收点发出查询。动态物体变化需要更新体素化与层级,不能只修改相机颜色图。
锥体查询
锥体追踪 Cone Tracing 用一个逐渐变宽的方向范围代替许多相近射线。Glossy 表面可沿反射方向查询一个锥体;粗糙度越高,锥体张角越大。漫反射需要覆盖半球,课程用八个锥体作示例,各锥贡献应按方向覆盖与余弦权重组合,不能随意相加导致能量增加。

图中的椭圆是各锥截面,多个方向共同覆盖较宽的接收范围;橙色箭头是观察方向。图标为 AO cones,强调相同半球划分也可以用于遮蔽查询;计算漫反射 GI 时还要读取辐射并乘反射权重,不能只读取占据量。

左图紫色截面沿锥体变大,查询从细层转向粗层;右图彩色方块表示相应的体素采样尺度。图中的 Quadrilinear 指三维空间插值,再在相邻层级之间插值,不是普通二维纹理的四个邻纹素。
若锥体半角为 ,距起点 的截面直径近似为 。基础体素宽度为 ,可据此选择
并夹到有效层级。粗层将较大足迹内的几何和光照过滤汇总,使一次查询代表一束方向。
沿锥体前进时,前面的占据应削弱后面贡献。用预乘透明度辐射 和不透明度 ,一种示意累积为
表示尚能穿过前方体素的比例。距离步长与采样尺度一致、避免过度重复采样,也是累积需要处理的条件。
1 | // 查询一个反射锥;体素数据已在前一阶段生成。 |
这是层级查询与合成的示意,实际 VXGI 的方向存储、遮挡表示和锥体权重需保持一致。粗体素会混合薄墙两侧的信息,宽锥可能把不相邻的表面合在同一足迹中,所以它仍不是对完整三角场景的精确射线求交。较细体素、更多锥和更完整的方向数据可以改善质量,也增加构建、内存和每像素查询成本。


