03 - 屏幕空间的实时全局光照算法

本文将介绍一些屏幕上的实时全局光照算法,例如 屏幕空间环境光遮蔽SSAO屏幕空间方向性遮挡SSDO屏幕空间反射SSR

屏幕空间算法

如果全局光照算法在生成间接光照效果时,只根据从相机视角能得到的信息,对只有直接光照的渲染结果进行后处理(post processing)以加上间接光照效果,即只用到了屏幕空间(screen space)信息,则这该算法属于屏幕空间算法。

SSAO

简介

SSAO(Screen Space Ambient Occlusion) 是一种在屏幕空间中对全局光照的近似。

在Crytek引擎中首次使用

如下图,SSAO可以让场景看起来更真实,因为它让物体富有立体感。而且SSAO的实现也比较容易,因此是必要的。

SSAO的核心思想如下:

  1. 不知道间接光照的具体内容(屏幕空间),于是假设它是个常数。
  2. 认为各着色点所有方向上的可见性不同,因为着色点间存在“遮挡”关系。
  3. 认为物体材质都是漫反射(diffuse)材质。

这样就可以通过估计着色点的可见性,直接地计算出间接光照效果。

理论推导

需要解RTR渲染方程,使用积分近似将其拆分成可见性V项+其他项:

其中:

  • 可见性V项:即,从着色点看向周围所有方向可见性的加权平均,范围0~1。
  • 间接光和BRDF项:两个常数的乘积,即间接光强与漫反射BRDF。

有关积分近似拆分:

  • 可以理解为将f(x)g(x)拆开,顺便求了f(x)的均值。上面这种拆分是准确的,因为f(x)g(x)都是常数。

  • 为什么拆出来3个cos项?是因为要进行换元,引入“投影立体角”这一概念,即球面立体角在它单位圆上的投影,有。于是变成了在“半球”上的积分,且​。

间接光和漫反射BRDF项均为常数,于是可以将它们从积分中提出来:

也就是

计算Ka

从上面的理论可以得出,要计算SSAO只需计算即可。如何在屏幕空间计算呢?

如图,SSAO算法在以着色点为中心,一定半径的球里进行采样,得到被遮挡(红)和不被遮挡(绿)的点的数量。在屏幕空间如何判断着色点和采样点的遮挡关系,可以利用屏幕空间的深度值来判断,若采样点深度比屏幕空间中该点深度大,说明该采样点被遮挡了。

当超过一半的采样点均被遮挡时,认为该着色点是不可见的,应用SSAO。

计算出的仍有一些不足之处:

  • 在估计可见性时没有考虑法线方向,导致出现“假遮挡”现象,如上图中间红虚线右边的点,应该是绿色的,但被SSAO计算成了红色。不过影响不大,可以忽略。

    假遮挡现象(Halos游戏)
  • 算出来的没有被余弦加权平均,在物理上不准确,但看起来还算正确。

避免“假遮挡”

要想避免假遮挡现象,就得进行更多采样,但实时渲染的性能要求不允许我们这样做,可以用下列技巧来缓解/避免“假遮挡”现象:

  • 可以用较少采样得到有噪声的结果,然后降噪,获得“更多”的采样点。

    施加保边滤波使结果更平滑
  • 现代图形渲染管线通常是 延迟渲染(Deferred Rendering)的,可以通过其中的 G-Buffer 获取当前着色点的法向量,有了法向量就能将采样点的范围缩减至一个半球,让结果更准确。

    这也是 HBAO 的思想:

    HBAO的结果是准确的,因此可以避免假遮挡现象。

SSDO

简介

是SSAO的升级版,比SSAO考虑的更全面准确。SSAO假设间接光来自远处,而SSDO则认为间接光来自附近,因为场景中的间接光照信息还是知道一部分的。

由于是屏幕空间算法,SSAO无法像RSM那样获取间接光照信息,于是SSDO认为 屏幕里能被直接光照射到的物体就是间接光源

SSDO的核心思想和路径追踪很像:

在着色点P上向任意方向射出若干光线,如果

  • 光线没有打到物体,说明射向P的光线是直接光;
  • 光线打到了物体,说明射向P的光线是间接光。

和SSAO对比

如图,SSAO和SSDO最主要的不同点就是 间接光的来源不同

  • SSAO认为着色点一定能够接收到部分间接光(红圈),另一部分则因为遮挡没有间接光(橙圈)。
  • SSDO认为着色点射出光线后,打不到物体的是直接光(红圈),打到物体的则为间接光(橙圈)。

因此,SSAO认为 间接光来自远处,SSDO认为 间接光来自近处,理论上它俩应该结合起来做才科学。

理论推导

还是解渲染方程,将其分为可见和不可见两部分:

重点考虑不可见(间接光贡献)的情况,而这种情况是可以被算出来的。

具体做法

SSDO的做法类似于HBAO,在着色点为球心,一定距离的半球上进行采样,然后将采样点和摄像机视角深度值比较,如果采样点深度比摄像机视角深度大,说明采样点和摄像机连线与物体的交点所在面片是一个次级光源(如左图A,B,D);反之则不是次级光源(如左图C)。

最后利用渲染方程将所有次级光源对着色点的贡献求和即可。

但SSDO也存在误差,如右图A点,本来是直接光源,却被SSDO误认为是次级光源。

优缺点

优点:

  • 效果很好,接近离线渲染
  • 轻量化

缺点:

  • 只能表示小范围的全局光照,这说明它仍会丢失一些来自于远处次级光源的信息。
  • 屏幕空间算法的缺点,有来自屏幕外的误差和信息缺失。

SSR

简介

SSR也是一种屏幕空间实现全局光照的方法,它在屏幕空间上进行模拟光线追踪,不需要场景图元信息。

SSR的核心问题如下:

  • 求交问题:解决任意光线和场景求交的问题。
  • 着色问题:计算光线与场景相交的像素点们对着色点的贡献。

具体做法

基本SSR算法

为了充分利用屏幕空间提供的信息,该算法是基于 镜面反射 的。

对于每个着色片段:

  • 计算反射光方向
  • 让光线和场景求交,获得交点
  • 让交点颜色作为反射的颜色

可以做镜面反射,也能调整地面粗糙度,配合法线造成模糊/凹凸效果。

接下来说说如何具体进行求交和着色操作。

解决求交问题

起初人们使用 Linear Raymarch 算法进行光线和场景求交。反射光线在着色点往反射方向以一定的距离步进,直到它的深度比场景物体深度大停止步进,视为光线和场景物体相交。

在这个算法中,步长为定值,太大太小均不好。于是能 让步长动态调整 的算法 Hierarchical Ray Trace 便出现了。

就像世界空间光线和场景求交可用层级结构加速(如BVH树、KD树)一样,屏幕空间中光线和场景求交可用 深度Mipmap 来加速。该深度Mipmap和平常的Mipmap不一样,平常的Mipmap使用下层4个像素均值作为上层像素,而 深度Mipmap使用下层4个深度最小值作为上层深度

这样就让场景深度值有了类似于树状的层次结构关系,方便光线动态步进:

解决着色问题

对SSR的着色要达到如下要求(在正确考虑物体BRDF前提下):

  • 根据反射面材质做出不同反应(如镜面地板,粗糙地板等);
  • 离物体越近,反射得越清晰;
  • 类似雨天路面效果,反射物体会上下拉长一点(如果有场景是雨天)。

可沿用路径追踪算法,不过要假设:

  • 反射物材质是漫反射材质,这样就不必考虑方向导致贡献的不同;
  • 只有次级光源。

因此可用 BRDF重要性采样 来获取着色点反射光线的方向分布。然后为了复用采样结果,可以在采样前预过滤一次,然后用加权BRDF加速运算。这里的“加权”就是利用该像素旁边一圈像素的结果,用它们深度值以不同贡献求均值。

优缺点

优点:

  • 对镜面/光滑材质地板性能高
  • 效果好

缺点:

除了对漫反射材质地面性能和效果不好外,还是屏幕空间带来的信息不足的问题:

  • 屏幕内物体信息丢失,如下图没有手心的信息:

  • 屏幕外物体信息丢失,如下图没有帘布的上端:

对于第二种情况,我们可以随反射距离衰减着色结果来解决:

参考资料

  • GAMES202: 高质量实时渲染 (ucsb.edu)
  • 《GAMES202:高质量实时渲染》3 实时全局光照:RSM、LPV、VXGI、SSAO、SSDO、SSR - 知乎 (zhihu.com)