基于 Probe 的实时全局光照方案(Probe-based Global Illumination) [TODO]
  0fD9fbsrNBEU 2023年11月01日 290 0

探针(Probe) 或者说 光照探针(Light Probe),简单理解就是场景中的一个点然后给予这个点去往四面八方收集光照或者说探测光照的能力,并以某种 cache 形式记录下来。在我们对某个 shading point 渲染的时候,就可以利用它附近 probes 所记录的光照信息粗略估计出它所受到的光照。

Cache 形式 [TODO]

probe 的 cache 存储形式通常有以下:

  • Cubemap:往往需要高分辨率的 6 张 texture 拼成 cubemap。
    • 存储空间开销极大(取决于分辨率)
    • 较好保留高频信息,适合做高质量 specular。

img

img

  • Octahedral Mapping:使用八面体映射技术。
    • 存储空间开稍微大(取决于分辨率)
    • 也能保留一定程度的高频信息,适合做 diffuse 和 glossy(低质量 specular)。
preview
  • SH:往往只需要存储十几个或几个 SH 系数。
    • 存储空间开销极低(取决于阶数)。
    • 由于基本只能表示低频信息,比较适合做 diffuse,不太好做 glossy 和 specular。

Radiance Map

Irradiance Map

Material Map

Visibility

基于烘焙的 Irradiance Probe [TODO]

在场景里预先放置若干个 probe,为每个 probe 预计算出局部(因为只能处理静态物体和静态光照,无法囊括动态物体和动态光照,所以是局部的)光场信息并存储后,在运行时就可以通过物体周围 probes 的光照信息来插值来得到 shading point 此时受到的局部光照。

基于预计算的 Probe 方案往往意味着需要进行预放置,主流有三类放置方式:Tetrahedral Tessellations,ILC,VLM

基于预计算的 Probe 方案在收集光照信息的时候,也采取预计算(烘焙)的方式。这意味着只能对静态光照(静态光源、静态物体组建成的静态场景)进行收集。

优点:

  • 预计算能够节省大量的计算来实现还可以的 GI 效果

缺点:

  • 由于是预计算,因此不支持动态光照
  • 对于大场景需要很多的存储空间,并需要设计一定复杂程度的空间结构来管理查询

在离线阶段,每个 probe 会通过比较高质量但耗时的渲染方式(一般可以使用 path tracing 等方式)来收集静态光照,说白话也就是在 probe 上往四面八方去探测光照。同时,探测到的静态光照信息信息将以 SH 的方式(而不是 irradiance map)的形式记录到该 probe 中。

由于场景中有很多个 probe,要是每个 probe 都存储一张 irradiance map 的存储和带宽开销会非常大,因此往往采用 SH lighting 方式(每个 probe 仅需要存储十几个或者几个 SH 系数)会更加可行。

有了预先放置好的 probes ,又有它们各自预先烘焙的光照信息(SH 系数),那么我们就可以在运行时对 shading point 着色:

  1. 根据 shading point 的世界坐标找到其邻近的 probes
  2. 对这些 probes 的 SH 系数以距离为权重进行混合,得到 shading point 的 SH 系数(比较粗糙的光照信息)
  3. 根据 SH 系数就可以重建 shading point 的光照信息信息

四面体镶嵌(Tetrahedral Tessellations)

在场景中预先放置自定义位置的 probe ,这些 probe 将自动相连成一个个四面体。而为了增加这种 GI 方案的真实感和避免过多的 probe 带来的存储开销,一般应当把 probe 在光照发生明显变化的地方(如明暗交接处)放密集些,而在光照不怎么变化的地方可以稀疏地放置。

ps:将这些 probe 进行三角化(将空间切分成四面体)需要用到 Delaunay Triangulation 完美三角剖分算法。

  • 手动放置的方式比较费人力
  • 运行时,查找 shading point 所处四面体的运算量较高:四面体的分布并不是均匀的,最糟糕没有优化的情况下需要暴力遍历每一个四面体判断 shading point 是否在该四面体里面,无论对 CPU 还是 GPU 运算都不太理想

基于 probe 的方案是需要经常用到这种查询操作:给定一个世界坐标,查询出它周围邻近的 probes

Indirect Light Cache

Indirect Light Cache, 即 ILC(间接光缓存),是 UE4 的方案,它基本上是在静态物体表面法线向上自动地均匀放置 probe ,这是基于假设受光照影响最大的地方都是在靠近静态物体的地方。

实际上,ILC 还包含两种 probe 放置方式:通过手动放置 Lightmass Importance Volume(重要光照范围)来限制烘焙光照采样范围,或 Lightmass Character Indirect Detail Volume,来增加一段均匀放置 probe 的区域。

  • ILC 通过 CPU 寻找物体周围的 probe:所有的 probe 的数据将保存到八叉树中以方便物体找到周围的 probe

Volumetric Light Map

Volumetric Light Map, 即 VLM(体积光照贴图),也是 UE4 的方案,它使用网格(Grid)采样点保存 probe 数据,而在静态物体表面附近,会对网格进一步细分。

  • VLM 通过 GPU 来寻找物体周围的 probe :所有 probe 的数据将烘焙至贴图中,不同细分层度的网格将使用 level 不同的贴图,这样可以方便地在 GPU 中进行逐像素的三线性插值

  • VLM 比 ILC 的 probe 要多更多,从而 VLM 的 GI 效果更佳,但要存储的数据更多

  • VLM 的存储结构决定了可以通过 GPU 算法来寻找 probe,这比传统的 CPU 算法性能更加可观(即便 VLM probe 数量要多得多)

  • VLM 更适合将 probe 应用到体积雾效果中,这是因为 ILC 往往不在几乎没什么物体的空间放置 probe

UE 4.18 以后使用 VLM 代替了 ILC 方法作为 UE4 默认的 probe 方案。

ILC vs. VLM 效果图:

Local PRT [2023]

DDGI [TODO]

DDGI(Dynamic Diffuse Global Illumination) 是一种支持动态光照的 probe 方案。

DDGI 的 probe 采取 ray tracing 的方式去实时探测动态光照信息,并且使用了 八面体映射(octahedral mapping) 技术来缓存收集到的光照信息:将球面方向映射成一张 2D texture,一个 texel 对应一个立体角方向,texel 的值即代表了其对应立体角方向的值。

RTXGI 实现中,ray tracing 就需要使用到硬件光追 API(需要 RTX 系列显卡)

DDGI probe 的数据组成:

  • 6×6 irradiance texture:存储每个 texel 方向的 irradiance \(E(\omega)\)
  • 14×14 moment texture:存储每个 texel 方向的深度 \(r(w)\) 及深度的平方 \(r^2(w)\),以便进行切比雪夫不等式测试。

有关于优化和改进 DDGI 的方案,可以详见于 动态漫反射全局光照Dynamic Diffuse Global Illumination | 知乎 [宇亓],这方面个人觉得宇亓的文章会更加全面。

RTXGI 1.0 [2019]

NVIDIA 的 DDGI 实现版本则一般称之为 RTXGI 技术,由于 RTXGI 往往比原论文的 DDGI 实现要更加成熟,因此重点对 RTXGI 进行分析。

RTXGI Volume

lp_volume_10

DDGI volume:一个立方体积区域,里面均匀放置着 probes(类似于 grid 分布),在 DDGI Volume 内的物体就能被间接光照亮,实现 GI 效果。

  • 虽然 volume 也需要手动放置,但是粒度更大,比起手动放置 probe 工作量要少得多。
  • volume 支持动态位置

不过,与前面预放置的固定 probes 不同:

  • volume 既可以预先固定在某个位置(静态放置),也可以动态改变位置(动态放置)
  • 动态放置 volume:需要实时探测几何信息 + 光照信息
  • 静态放置 volume:需要实时探测光照信息,而对于几何信息则可以选择预计算或者实时探测

在实践中:

  • 对于静态放置:会先放置一个大号的静态 volume 囊括整个场景(常用于表现室外间接光),然后再在场景中各个房间都放置一个静态 volume(更加高清晰度表现室内间接光)

  • 对于动态放置:往往会多个大小不一的 volumes 绑定到 camera 上,这样就可以跟随 camera 移动对视野内的一定范围的物体应用间接光照,并且具有质量上的 LOD 效果(近处采用高精度 volume,远处采用低精度 volume)

  • 在嵌套多层的 volume 之间会做一个线性淡出从而避免明显的边界

image-20231008155448265

ray tracing

计算 radiance:

  1. probe 均匀向球面上射出若干个 rays,并记录每个 hit point 的 position,normal,albedo 并将结果存入分别存入三张 texture

如果采取预计算的 volume ,那么这一步操作就会提前到预计算阶段并保存好,从而运行时让每个 probe 无需射出 ray,直接访问保存好的那三张 texture

接着我们需要计算每个 hit point 的着色结果,这样才能计算出对应 ray 的 radiance

  1. one-bounce lighting:通过 position,normal,albedo, rayDir 进行 hit point 的直接光照着色

\[L_{one} = \sum_{lights} (L_{light} * f * \cos \theta) \]

  1. multi-bounce lighting:通过 position,normal 并利用周围 probes 的上帧 irradiance texture 来重建 hit point 的光照信息,并进行间接光照着色

\[L_{multi} = \frac{E(position, normal)* albedo}{\pi} \]

间接光照着色必须使用 diffuse BRDF,即乘 albedo 除 PI。因为 irradiance 丢失了入射角相关的光照强度信息,无法使用 specular/glossy BRDF。

  1. 将 radiance 结果写入 ray buffer 中

\[L(ray) = L_{one} + L_{multi} \]

probe update

更新 probe 的 irradiance:

  1. 使用 radiance texture 来更新 probe 中的 irradiance texture

\[E(texelDir) = \frac{\sum_{\text {rays}} L(rayDir)\cdot \max (0, \cos \theta )}{\sum_{\text {rays}}\max (0, \cos \theta )} \]

  1. 使用 position texture 来更新 probe 中的 moment texture

\[\begin{aligned} r(texelDir) &=\frac{\sum d(rayDir) \cos ^s \theta_i}{\sum \cos ^s \theta_i} \\ r^2(texelDir) &=\frac{\sum d(rayDir)^2 \cos ^s \theta_i}{\sum \cos ^s \theta_i} \end{aligned} \]

position texture 代表了某个方向的光线交点的世界空间坐标位置,通过变换可以计算成该方向的最近 depth,这将在后面用于 probe 的 depth test,去解决一些漏光问题。

  1. temporal filtering:

\[E_{new}(texelDir)=\operatorname{lerp}(E_{old}(texelDir),E(texelDir), historyWeight ) \]

probe classification

probe 引入状态机,分为 inactive 和 active,减少所需要更新的 probes 数量。

gathering

重建 shading point 光照信息:在最后我们需要对 shading point 进行着色的时候,就可以通过更新好 irradiance 的 probes 来重建 shading point 的光照信息:

image-20221025015858864

  1. 根据 shading point 的世界坐标找到其邻近的 8 个 probes

  2. 对每个相邻的 probe:

    • 计算出 shading point 到 probe 的 \(dir\)

    • 测试 \(dir\) 是否与 \(n\) 面向同一侧:若 \(dot(dir, n)\le 0\),则跳过该 probe

    • 根据 \(dir\) 索引到 texture 中对应的 texel ,得到 \(E(dir)\) , \(r(dir)\)\(r^2(dir)\)

    • 计算 shadow 系数:根据 \(r(dir)\)\(r^2(dir)\) 来对 shading point 进行切比雪夫不等式测试

    • 该 shading point 受到的光照信息 irradiance 即为 \(E(dir)*shadow\)

  3. 对这些通过测试的 probes 算得的 irradiance,以距离为权重进行混合便能得到 shading point 的光照信息

重建光照信息实际上在 DDGI 的流程走了两次,一次在计算 ray radiance 那块需要计算 hit points 的着色,另一次便是在这里需要计算 shading points 的着色。

SDFDDGI

DDGI Resampling

结合预计算

Reflection Probe [TODO]

reflection probe 与 irradiance probe

Parallax Correction

Simple Parallax

simple parallax 使用简单的球形/长方体形代表场景,首先算出 hit point 的 ray 与球形/长方体的相交点,连接 probe 与相交点的方向即为矫正后的查询方向:

image-20230927135324706

Probe Depth Parallax

从 hit point 往 R 方向,每隔一段位置(对应橙色点)就与 probe 连接得到一段连接向量。该连接向量单位化后可以用于采样 probe 并得到对应方向的深度,该深度将与连接向量的长度进行比较:若连接向量长度更长,那么说明 ray 在该橙色点前的某个位置与场景发生了碰撞,那么可以 hack 一下直接取该单位化后的连接向量作为矫正后的查询方向。

image-20231007174852911

结合 SSRT 和 Ray Query [2023]

来源于 GDC2023《战神:诸神黄昏》的 rendering 演讲。

无论是 simple parallax 还是 probe depth parallax,算得的查询方向仍然与 ground truth 查询方向有一定偏差,也因此仍然存在一定程度的图像视角偏差现象。可以利用 ray tracing 技术来得到 hit point,从而连接 probe 和 hit point 得到更准确的查询方向。

在战神诸神黄昏的做法中,结合使用了低廉代价的 SSRT 和硬件支持的 ray query 特性,给定 shading point 的位置 P 和反射方向 R,那么:

  1. 首先尝试进行 SSRT:若 SSRT 命中则采样 screen color 作为本次 ray 的 radiance。
  2. 若 SSRT 未命中,则使用 ray query 得到准确的 hit point,并判断该 hit point 是否在 screen space 中:若在,则采样 screen color 作为本次 ray 的 radiance。
  3. 若 hit point 不在 screen space 中,则连接 probe 和 hit point 得到了 reflection probe 的查询方向,从而在对应的 radiance map 中查询到对应的 radiance 值。
image-20231007175034074

在更具体实践中,我们不必对场景的原生 mesh 建立 BLAS,而是对场景 mesh 创建出更加简化的代理 mesh 后并以此建立 BLAS,可以大大减少 ray query 的开销(因为查询方向确实也不用太过精确)。

虽然现在硬件光追逐渐普及,但很多平台仍然不能支持 ray tracing pipeline 特性,只支持阉割的 ray query 特性。这种混合了 ray query 和烘焙的方式会比较适合从光栅化过渡到硬件光追的项目使用。

Screen Space Probe

Screen Space Probe:往屏幕若干个 pixels 对应的世界位置(即一些几何物体表面)贴上 probes,并让这些 probe 通过 ray tracing 的方式搜集动态光照。其实本质上相当于降分辨率的 pixel shading,并通过插值方式 upsampling 到原分辨率。得益于可以贴在几何物体表面的特性,screen probe 往往比传统 world probe 会更少一些漏光现象。

Screen Probe in Lumen [2021]

screen probe placement

Lumen 的 screen probe 是每帧全部重新生成的。

  • uniform placement:在屏幕上均匀放置 probe(如每隔 16x16 pixels),因此往往用 1 个 tile 对应 1 个 uniform probe;一般使用 2d texture 存放 uniform probes。
  • adaptive placement:在 uniform probes 之间,每隔一小段距离尝试进行插值测试,对插值失败的地方额外放置 probe;一般每个 tile 有对应存放 adaptive probes 的列表(通过 offset+count+global array 的数据结构来表示)。

所谓插值测试,一般是指根据 uniform probes 的世界坐标进行插值得出当前屏幕点的插值世界坐标,如果与当前屏幕点的实际世界坐标相差太大,那就意味着该位置出现几何上的突变,从而导致插值失败。

image-20220822021720949

ray tracing

基于 Importance Samping(重要性采样)生成固定数量的 rays:

  • 每个 texel 方向分配 1 根 ray,并算出每个 texel 方向对应的 lighting pdf(根据 4 个 history probe 的 radiance map 混合而成)× BRDF pdf。
  • 将 pdf 值为 0 的 texel 方向剔除掉,并将原本应该分配给该 texel 方向的 ray 重新分配到 pdf 较高的 texel 方向,从而实现 Importance Samping。

screen probe 的 BRDF 以 SH 形式表示,并来源于附近 screen pixels 的 BRDF SH 混合结果。并且由于 screen pixels 的特性,screen probe 的 brdf 分布经常会出现另一半球的 BRDF 值为 0 的情况(毕竟很少有 normal 朝背面的 pixels)。

image-20230926215942337

  • 对生成的 rays 进行 tracing,并记录下对应的 radiance 结果(这里如何做 ray casting 就不多介绍了)。
  • 根据各个 rays 的 radiance,转化成本帧的 radiance map。

由于 screen probe 往某个 texel 方向分配的射线数量有限(最多细分为 4 根),也因此在包含远距离光照的 texel 方向上比较难收敛。当然,后文会提到增加了一个 screen probe 层级的 filtering 后效果会好很多(主要是 temporal filtering 立功),然而在快速移动镜头时由于丢失历史信息,仍然会很容易出现不稳定的光斑现象,这就需要下面介绍的 world probe 解决光照稳定性问题。

图左的光斑现象便是丢失历史信息(无 temporal filtering)的效果。

image-20230927132841665

利用 world probe

Lumen 中除了 screen probes,还有 world probes(被 Lumen 命名为 radiance cache)。只不过 world probes 不是基于屏幕生成,而是类似于 DDGI 那样在世界空间上均匀分布。world probe 的作用主要是为 screen probe 的 rays 提供一个更稳定的 radiance 结果。

image-20230927134653605

radiance cache 的主要特性:

  • 比 screen probe 更稀疏的分布,但 world probe 的 radiance map 更高分辨率(更精确)。
  • 和 screen probe 一样,也需要发出 rays 来搜集光照信息。
  • 仅保留能影响到 screen probe 的 world probes(相当于剔除掉屏幕空间以外的 world probe)。
image-20230926175948964

因此,引入了 radiance cache 机制后,screen probe 的 ray tracing 流程就变成了判断自己 ray casting 的距离是否达到足够远的阈值:

  • 如果是,则停止 ray casting,转而去查找附近的 8 个 world probes,并根据射线方向来分别在这个 8 个 world probes 中矫正(用上面说的 simple parallax)成对应的查询方向,并以该方向映射到 world probe 中对应的立体角 texel,并由此在 world probe 的 radiance map 采样出对应的 radiance 值。
  • 如果不是,则继续 ray casting,和原 ray tracing 流程一样(即直到 hit 到某个点进行采样,从而算出该 ray 的 radiance)。

screen probe filtering

一般对 probe 的 radiance map 各个 texel 进行 filtering。

  • spatial filtering:由于 screen probe 是贴在屏幕上的,因此可以充分利用屏幕信息(G-Buffer)来作为 probe 层级 spatial filtering 的指导。
  • temporal filtering:投影到上一帧某个位置并根据对应位置附近的 4 个历史 screen probe 来进行复用。

AMD GI-1.0: Two-Level Radiance Caching Scheme [2023]

前面 lumen 的 screen probe 方案曾经提到如果快速移动镜头,那么 probe 层级的 temporal filtering 会失效,从而导致画面不稳定产生光斑现象。而 AMD 的方案则是重点在于改进 screen probe 稳定性问题。

screen probe reprojection

和 Lumen 类似,基本每个 tile 需要对应生成一个 screen probe,然而 AMD 方案会利用 reprojection 避免大部分 screen probe 的重新生成。

具体来说,tile 内每个 pixel 会通过 motion vector 来投影到历史帧,并评估其与最近 history probe 的几何差异度。接着,从 tile 中挑选出一个差异度最低的 pixel 作为 probe 的位置,并直接把 history probe 的内容填充到当前 probe 的内容,就避免了重新生成当前 probe 的计算开销。

会存在 reprojection 失败的情形,即每个 pixel 投影到历史帧位置都找不到比较相似的 probe 或者越出屏幕边界。

当然,不移动屏幕,一直使用 history probe 的信息也是不合理的(不会更新光照),因此 AMD 方案每帧强制重新生成 1/4 的 probes(Lumen 则是重新生成全部 probes)。

image-20231007170554388

为此,使用了三种 tile 队列来决定最终应当为哪些 tiles 重新生成 probe:

  • empty tiles 队列:reprojection 失败的 tiles,可以理解为丢失历史 probe 信息的无效 tile。
  • spawn tiles 队列:将要生成 probe 的 tile id 队列,其元素数量为 1/4 的 probes 数量。初始包含元素:处于 1/4 checkerboard pattern 的 tiles。
  • override tiles 队列:reprojection 成功(即为已经有历史 probe 信息的有效 tile)且同时处于 1/4 checkerboard pattern 的 tiles。
image-20231007170412491

我们倾向于为 reprojection 失败的 tiles 用于重新生成 probe,为此会随机抽一些 override tiles:对每个被抽到的 override tile,需要将自己对应的 spawn tiles 与 empty tiles 交换,从而实现原本给自己 spwan probe 的机会让给 empty tiles。

但是原文并不推荐把所有 override tiles 都将 spawn 的机会让给 empty tiles,因此采用了随机抽一些的方式,但这也意味着在本帧仍然可能会有 empty tiles 不会生成 probe。

empty_tile = empty_tiles[tid];
override_tile = override_tiles[random_index];
InterlockedExchange(spawn_tiles[override_tile], empty_tile);

image-20231007170454625

screen probe caching

在第一帧,tile 在某个 pixel 上生成了 probe1;而在下一帧如果该 tile 将生成新的 probe,那么将在另一个 pixel 上重新生成 probe2。

那么这时候问题来了:可能这两个 pixel 是完全不同的几何,从而导致 probe2 和 probe1 的光照信息相差过大,可能会产生光照闪烁现象(其实就是采样率过低导致的)。

image-20231007171159122

AMD 方案采用了 LRU Cache 方案,为每个 tile 存储固定若干份 probe 信息,并根据 LRU 规则来换入换出 probe 信息。当然缺点就是若干倍的 probe 存储空间开销。

ray tracing

基于 Importance Samping(重要性采样)生成固定数量的 rays。不过,在计算 lighting pdf 的时候并不是像 Lumen 那样简单的基于距离去混合 2x2 个 history probe 的 radiance map 信息,而是采用了基于 parallax correction 的混合方式(并且混合的是 3x3 个 history probes 而非 2x2 个)。

具体怎么 parallax correction 呢?history probe 包含了每个 texel 的深度信息,因此可以重建出大致的 hit point position,然后连接 new probe 和 hit point 便是视差矫正后的方向。

image-20231008164630500

这种 parallax correction 方式也决定了必须得从 history probe scatter 到多个 new probes,而不能用 new probe 访问多个 history probes:

  • Lumen:对于每个 radiance map texel,访问 2x2 个 history probe texels 来进行混合后得到本 texel 的 lighting pdf。
  • AMD:对于每个 history radiance map texel,根据自身的 radiance 值来对周围 3x3 的 new probes 对应的 texel 进行 4 次 InterloackedAdd(4 个 float 对应 radiance rgb 和权重 w)。在之后每个 texel 将自己得到的 rgb sum 除于 w sum 便可以得到本 texel 的 lighting pdf。

scatter 后,可能有些 new probe texels 一直都没被 InterloackedAdd 过,从而 lighting pdf 为 0,会造成能量丢失。为此,AMD 方案很 hack 直接使用了当前 probe 所有 texels 的平均 radiance 作为空洞 texel 的 lighting pdf。

当然也可以强制让每个 texel 至少 1 根 ray,但是会导致 ray 数量过多,开销过多。

在上面的操作做完后,终于有完整的 lighting pdf 了,就可以用离散逆变换采样方式生成 rays,并且 ray tracing 后得到新的 radiance 后,可以和原有的 lighting pdf(其实相当于 history radiance)进行混合(实际上就是 screen probe 的时序滤波)。

screen probe filtering

虽然前面的 screen probe reprojection 通过三队列机制大大减少无效 probes,但是仍可能存在一定数量的无效 probes(尤其是镜头快速移动时)。为此,在进行 screen probe filtering 的时候需要跳过这些无效 probes。

为此,引入了 probe mask mipmap:mip n 的每个 texel 代表了对应 \(2^n\) 个 probes 是否有效,若无效则值为0,若有效则存储这些 probes 中第一个有效的 probe 的 index。

image-20231007171403625

这样在进行 filtering 的时候,如果发现采样到了无效 probe,那么就去更高级的 probe mask mip 继续采,直到采到一个有效 probe index 时再访问对应的 probe 信息。

AMD 采用了 7x7 样本数的 screen probe 空间滤波,并且使用了 separable blur 的方式(即横向 blur 和纵向 blur 共两个 pass)。而 screen probe 的时序滤波是内含在 ray tracing 阶段中的计算 lighting pdf 过程中....不过u1s1,AMD 的方案也挺杂的,本文篇幅有限,就不全面介绍了。

Probe 的 Light Leaking 问题 [TODO]

不过 probe 经常会遇到错误的 Light Leaking (漏光)问题:受到几何上不应该存在光照关系的 probe 影响,常见于墙壁遮挡的内外侧。

例如,下面的一个 probe 生成在室内,我们预期室外的墙体是亮黄色的,室内的墙体是暗灰色的:

image-20220821205719640

结果由于 probe 方法没有考虑遮挡,而是直接且错误地进行了对相邻的 probe 插值,从而室外本该明亮的一侧变暗,室内本该黑暗的一侧发生 light leaking:

image-20220821205930337

标记法

这个方法很直观,就是给 probe 额外一个标记属性:是否在室内(例如1为在室内,0为在室外);这样我们要拿 shading point 周围的 probes 来插值时,根据 shading point 在室内外的情况来选择用哪种标记属性的 probes 来进行计算。

image-20220821211737411

虽然粗暴直接,但是开销低廉,实际效果很 work,很多游戏工业界都会采用的方法(例如原神)。在一些方案中,这些标记也可以由自动化生成,而无需人工生成。

切比雪夫不等式测试

一些 probe 方案将半球方向上每个 texel 方向的深度存入到基于八面体映射的 depth texture 上。

那么在重建 shading point 光照信息时,我们就可以使用类似 shadow map 的思想来检测 shading point 到该 probe 的光路会不会被遮挡,从而计算出该 probe 对 shading point 的贡献:

\[d_x = x_{probe} - x \\dir = normalize(x-probe) \]

\(x_{probe}\) 为 probe 的位置,\(x\) 为 shading point 的位置。

\[shadow = d_x > d(dir)?0:1 \]

也可以,可使用类似 variance shadow map 的思想,基于切比雪夫不等式(Chebyshev’s Inequality) 去做光滑的遮挡测试(避免硬边缘) :

\[\mu = r(dir)\\ \sigma = r^2({dir})-r(dir)*r(dir) \]

\[shadow = P(X>d_x) \approx \frac{\sigma^{2}}{\sigma^{2}+(d_x-\mu)^{2}} \]

Probe Offset

Bias Vector

总结 [TODO]

Reflection Probe 方案:

基于烘焙的 Probe 方案:

DDGI(RTXGI) 方案:

Screen Space Probe 方案:

基于预计算的 Probe 方案往往意味着需要进行预放置,主流有三类放置方式:Tetrahedral Tessellations,ILC,VLM

基于预计算的 Probe 方案在收集光照信息的时候,也采取预计算(烘焙)的方式。这意味着只能对静态光照(静态光源、静态物体组建成的静态场景)进行收集。

优点:

  • 预计算能够节省大量的计算来实现还可以的 GI 效果

缺点:

  • 由于是预计算,因此不支持动态光照
  • 对于大场景需要很多的存储空间,并需要设计一定复杂程度的空间结构来管理查询

优点:

  • 支持动态光照信息
  • 在预计算模式下,还能避免运行时 ray tracing 的开销
  • 若将 volume 绑定在 camera 上,则存储空间的开销增长与场景大小无关

缺点:

  • 硬件 ray tracing 的开销可能仍然很大
  • 在预计算模式下,对于大量动态物体的场景可能会很容易穿帮,因为几何信息只包含静态物体
  • 不能放置太多 probe,因为每个 probe 需要更多存储空间了(textures 相比于 SH 系数)

相比于空间中均匀放置 probe 的方案,screen space probe 具有

优点:

  • 对性能友好:基于屏幕的方案所需要的 probes 数量明显要少很多
  • probe 的利用率更高:贴合在物体表面上的 probes 离物体表面的距离更近,因此上 irradiance 的表示更加贴切和准确;而在空间中均匀放置的 probes 可能会有一些压根没怎么用到,利用率更低

缺点:

  • 能量损失更严重:ray 命中的地方很可能不存在 screen space probe,即丢失了屏幕可见几何表面以外的光照信息。因此,一般来说 screen space probe 会搭配别的 GI 方法补上这块的空缺。
  • 很难支持体积渲染:丢失了空间中非物体表面的 irradiance 信息,几乎不能支持体积渲染

参考

【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月08日 0

暂无评论

推荐阅读
  90oyMi1VXuqm   2024年08月20日   36   0   0 计算机图形学
0fD9fbsrNBEU