图形学渲染基础(8) 实时全局光照(Real-time Global illumination)

2,761 阅读12分钟

实时全局光照简介

全局光照能很好地提高渲染的真实度,是非常重要的环节, 但是非常复杂。光线在环境会进行弹射产生间接光照,使场景中不会有全黑的地方。在实时渲染想要实现的全局光照其实是在直接光照的情况多一个bounce的间接光照。(更多的bounce就不适合实时渲染了) image.png

实时全局光照基于3D空间

Reflective Shadow Maps(RSM)

如果需要计算出间接光照,需要考虑的两个问题:

  • 问题1: 哪些东西是次级光源,即哪些物体会被光源照亮?

  • 问题2: 每一个次级光源对Shading point的贡献是多少?

  • 问题3: 次级光源与shading point的可见性关系如何判断?

  • 问题4: 一张RSM记录的patch太多,应该记录哪些patch对P的贡献? RSM利用了Shadow Ma的思想针对这两点提出了对应的解决办法:

  • 问题1解决:在光源摄像机渲染 shadow map (往往只记录了深度)的时候,顺便额外记录 世界坐标 xp 、法线 np、 接受的直接光源 radiant flux Φp。那么就可以认为 shadow map 的一个 texel 对应一块patch ,从而这张 shadow map 就包含了所有次级光照 patch 的信息了 。 image.png

  • 问题2解决:由于每一个shading point相对于每一块patch的位置不同,所以出射方向未知,因此可以假设所有的patch都是diffuse的材质,然后根据公式推导出每一个次级光源q对任意一点p的贡献值Ep(需要注意从q到p之间的radiance不需要考虑衰减,因此4次方需要改成2次方image.png

  • 问题3解决:任意次级光源小片q能不能看到点p,这就没法用shadowmap来解决,不可能给所有q都预计算一张shadowmap,就干脆不计算Visbility.

  • 问题4解决:理论上,为了实现最好的RSM效果,应当取整张 shadow map 的所有 texel 作为次级光源点,因为整张shadow map 意味着包含了整个光源照到的信息。但这样所需的采样数就相当于 shadow map 的分辨率,代价太高。因此我们应当使用少量的采样数来保证性能,同时也要保证RSM的间接光源质量能够接受。将点p的坐标映射到对应到光源所记录的RSM上,根据距离关系进行不同权重的采样。 image.png 因此,选取一个随机采样点坐标 (u,v)(u,v) 和对应的权重 importancee:

image.png 其中,s、ts、t 为 shading point x 在 shadow map 的纹理坐标,ξ1、ξ2ξ1、ξ2 为随机数

Light Propagation Volumes(LPV)

LPV顾名思义,就是在三维空间传播光线,就可以用来做间接光照。LPV的基本思路是把场景分成格子,把格子中的点受到的直接光照注入到格子中,把格子作为次级光源传播到其它格子,实现全局光照。

LPV的基本步骤如下:

  • 第一步:找到次级光源。先用RSM找到哪些点会被直接光照照亮,这样就得到一系列次级光源; image.png
  • 第二步 注入。把场景分成一定大小格子,任意一个格子就包含一些次级光源,把这些的光源往四周的radiance加起来,用球谐函数SH把randiance压缩起来(注意这里格子大小的确定是一个问题) image.png
  • 第三步:传播。一个格子是有六个面的,radiance通过每个面往周围六个格子传播,只要不断传播格子就能稳定下来,最后得到次级光源的radiance传播过的格子; image.png
  • 第四步:渲染。每个shading point 都有一个的格子,已经得到了每个格子的incident radiance,就能直接进行渲染。

Voxel Global Illumination (VXGI)

VXGI和RSM一样也是两个PASS的算法,其区别在于,RSM是把接受直接光照的点作为次级光源,而VXGI是把整个场景离散成体素变成网格,RSM和LPV计算radiance都是从次级光源出发传播一次,从而得到全局光照的结果,而VXGI是从camera出发,根据打到的像素的材质反射出一个圆锥,相交到之前计算好的纹素的(即cones shading),这样每个shading point 都要进行 cones shading 的计算。

image.png VXGI质量很高,但也存在着一些问题,场景体素化的计算量太大,而且可能需要预处理,如果场景里的物体移动,就得重新体素化,开销太大,实时渲染通常不采用该方法,因此不做过多介绍。

实时全局光照基于屏幕空间

屏幕空间方法下的全局光照故名思意,就是从屏幕空间的获得获取的信息来做全局光照(于开局一张图,后面全靠编

Screen Space Ambient Occlusion(SSAO)

所谓环境光遮蔽(AO),就是某个 shading point 因为被其它几何表面所遮挡,从而降低了接受外界环境光的比例(这种遮蔽常常发生在凹处表面):AO就是通过相对位置来制作阴影,让物体相对位置感和立体感更强,是对全局光照的近似。而SSAO就是在屏幕空间下对全局光照的近似。 image.png SSAO把物体接受到的间接光照作为一个常数,就和blin-phone的原理近似,不同的是SSAO考虑到遮蔽,得到一个相对正确的结果。 image.png brdf项和环境光都是常数,那么要求的就只有kA项。KA项记录的是shading point被周围物体遮挡的情况,在只有屏幕空间的信息下,想要记录visibility只有靠一些大胆的假设了:在shading point周围一个圆,随机分布一些点,看哪些在物体内部,哪些在物体外部,再投影到camera里,通过深度图来得出哪些点会被挡住。

image.png SSAO 将要用到的屏幕信息是:color、depth

SSAO 不需要预计算过程,只需要通过屏幕空间信息就能做到还算不错的AO效果:

  1. 在第一个 pass 只渲染整个场景的直接光照,得到包含直接光照结果的 color buffer 和 depth buffer。
  2. 在第二个 pass 对整个屏幕渲染,对于某个 shading point ,在该点周围随机采样一些点,然后这些点与 depth buffer 对应的深度作比较:若采样点的深度小于 depth buffer 对应位置的深度,则说明该采样点被遮蔽了。而这些采样点的遮蔽率便是该 shading point 的遮蔽率。遮蔽率将乘于 color 得到该 shading point 最终的渲染结果。

image.png 虽然SSAO增加了更多的暗部细节,但是通过深度图就会出现一个问题,如图中的地板因为深度,误认为被石凳遮蔽,出现错误的AO。

Screen Space Directional Occlusion(SSDO)

SSDO 也是一类与 SSAO 极其相似的屏幕空间GI方法,区别在于它们看待光线遮蔽的角度是相反的:

  • AO 认为 shading point 朝外的光线打到物体几何表面时,相当于外部的直接环境光被这个表面遮挡了,因此(对于下面这幅图) AO 将红色部分视为间接光照来源,黄色部分视为损失的间接光照
  • 而 DO 认为 shading point 朝外的光线打到物体几何表面时,相当于受到了间接光照(光照来源于打到的表面),因此(对于下面这幅图) DO 会将黄色部分视为间接光照来源,红色部分视为损失的间接光照 image.png

因此 SSAO 往往增加的是明暗细节,而 SSDO 往往增加的是周围物体表面的颜色影响(或者说增加color bleeding效果)!!!!!!!!

SSDO 将要用到的屏幕信息是:color、depth

SSDO 算法流程:

  1. 在第一个 pass 只渲染整个场景的直接光照,得到包含直接光照结果的 color buffer 和 depth buffer。
  2. 在第二个 pass 对整个屏幕渲染,对于某个 shading point ,在该点周围随机采样一些点,然后这些点与 depth buffer 对应的深度作比较:若采样点的深度大于 depth buffer 对应位置的深度,则说明该采样点将提供间接光照。而这些采样点的间接光照按权重加起来便是该 shading point 的间接光照结果。间接光照结果将直接叠加 color 得到该 shading point 最终的渲染结果。

SSDO 效果图: image.png

Screen Space Reflection(SSR)/Screen SPace Raytracing(SSRT)

Screen Space Reflection(SSR) ,一类与 ray tracing 思路非常相似的屏幕空间GI方法,因此也有被叫为 Screen Space Ray Tracing(SSRT) 。它的想法是,将屏幕所看到的表面几何信息当成一个场景,然后计算间接光照时,往半球范围若干个方向投射射线,看看能和这个场景的哪个屏幕像素点相交,这些便可以相交的像素点便是提供间接光照的来源。

image.png SSR 需要用到的屏幕信息:color、normal、depth

SSR 的算法流程:

  1. 在第一个 pass 只渲染整个场景的直接光照,得到包含直接光照结果的 color buffer 、normal buffer、 depth buffer。

  2. 在第二个 pass 对整个屏幕渲染,对于某个 shading point ,在该点往半球随机方向投射若干条射线(使用 ray marching算法),然后将与射线相交的点 p′将对 shading point 的间接光照做出贡献(这与渲染方程是一致的):其中当射线命中时, V=1 ;否则,V=0 image.png 为了减少计算,这里的L(p',wi)项为间接光源提供的能量,仍然默认间接光照是diffuse的,因此式子可以简化成 image.png SSR流程示意图如下:黄点是shading point,绿点是p'. image.png 因为SSR是基于ray tracing的算法,因此可以根据不同的brdf反射不同的效果 image.png

SSR的重要性采样

SSR的步骤2需要向半球的随机方向投射若干条射线,这里就涉及到了采样问题,为了让 SSR 的采样更容易收敛,我们可以根据不同的 BRDF lobe 在进行 importance sampling: image.png

SSR的ray marching

得益于带 depth buffer,SSR 可以实现比较廉价的 Ray Marching 效果。Ray Marching 的精度和性能之间的平衡将取决于 march 的步长。

普通的ray marching 思路如下:

  1. 从shading point每次往射线方向走一个步长得到一个测试点,将该测试点变换成屏幕坐标 (u,v,z)(u,v,z)
  2. 根据uv坐标取 depth buffer 对应的深度 d 与 z 比较:若 z>d,则说明射线碰到该uv位置上像素点的“柱条”,返还该测试点;否则,重复上述步骤。

image.png

在 SSR 的 ray marching 中,步长短了会导致要走很多步,消耗很多性能;而步长长了则可能会导致越过原本应该相交的地方后面,导致错误的相交。

为了优化这一过程,我们可以对 depth buffer 做成特殊的 mipmap,低层级的将取高层级若干个 texel 的depth最小值(离屏幕最近的),而不是传统 mimap 所取的平均值image.png 这样我们可以先在底层级的 mipmap 进行大步的 march:若没碰到,则说明不在当前这块 texel 的任何子像素,可以继续下一大步;若碰到了,则说明可能与在这块 texel 里的某个子像素相交,因此需要降低层级,进行更小步的 march。 image.png 算法的思想:就像使用试探步在行走 image.png

SSR的射线结果重用

当 pixel 的 ray marching 得出一个相交点时,不仅计算出对该 pixel 的间接光照贡献,还可以将计算该点与原 pixel 附近的 pixel 的间接光照贡献并赋给相应的 pixel :

image.png

各种GI技术的优缺点与应用

Reflective Shadow Maps(RSM)

  • 优点:容易实现
  • 缺点:效率与光源数量有关 || 未考虑Visibility || 许多的假设:diffuse depth or distance..
  • 应用:手电筒的全局光照 image.png

Light Propagation Volumes(LPV)

  • 优点:性能优越,效果也还可以,可以适用任意场景。
  • 缺点:格子的大小需要有讲解:格子小,存储空间和效率低;格子大,Light leaking漏光 || 未考虑Visibility || 在云、烟雾等场景光纤不是直线传播。
  • 应用:大多数场景的全局光照。

image.png

Screen Space Ambient Occlusion(SSAO)

  • 优点:快,代价低
  • 缺点:仅包含屏幕表面的几何信息不能表示完全正确的 visibility,因此 AO 效果不那么准确(相对于预计算AO贴图)
  • 应用:廉价的GI效果,提升画面的暗部细节,大部分游戏都会将其纳入一种画面增强选项。

image.png


Screen Space Directional Occlusion(SSDO)

  • 优点:快,代价较低
  • 缺点:仅包含屏幕表面的几何信息仍然不能表示完全正确的 visibility ||仅支持短距离GI效果,而无法展示长距离的GI ||- 会缺失屏幕看不到的平面信息(对于有颜色的GI效果很容易看出artifact)
  • 应用:廉价的GI效果,比起SSAO效果会好点 image.png

Screen Space Reflection(SSR)

  • 优点:渲染效果非常的好(前面的方案看起来总像是增强部分的图像效果) || 通过不同的 brdf 函数,可以自由调成各种反射效果(specular/glossy/diffuse)
  • 缺点:- screen space 方法仍然缺失了屏幕所看不到的几何信息(反射的效果只是壳子而不是完整的物体信息) || diffuse 情况下,由于要往半球范围均匀采样(不能像specular/glossy那样用importance sampling极大优化采样),容易造成nosiy结果,这时候可能需要牺牲更多的性能来采样更多。
  • 应用:廉价的GI效果,比起SSAO效果会好点 image.png

参考