Skip to content

Non interleaved Deferred Shading of Interleaved Sample Patterns

Monica的小甜甜 edited this page Jul 25, 2020 · 2 revisions

交错采样

​​​​

    本文是一篇光照计算加速的文章,是一篇非常经典而且非常常用的一篇文章。本文想解决的问题就是在计算VPL光照影响的时候,随着VPL数量增加会导致计算时间明显的增加。本文是在的基础上进行优化的。 

    本文的核心思想是将Gbuffer中的纹理进行分块重组,然后产生很多低分辨率的小场景(由于Gbuffer中包含了整个场景的位置,法线,颜色和深度,因此可以通过Gbuffer中的内容重建整个场景),这些小场景如(b)所示,每个低分辨率场景之间非常像,因此就把我们需要计算的VPL平均的分给每个小场景,然后每个小场景独自进行一部分光照计算,计算完成之后再将这些小场景合成一个大场景即可。

   实现步骤:(a) 计算Gbuffer->(b) 分块(分成多个低分辨率小场景)->(c) 单独计算光照->(d) 组合(将计算完之后的小场景合并为一个大场景)->(e) 边缘检测(为了后面高斯模糊使用)->(f) 高斯模糊(后面会讲原因)->(g) 融合(讲纹理和光照结果进行相乘,如果在计算光照就把纹理带上,那么高斯模糊会讲纹理也一并模糊了)。

   文章的思路是很清晰的,不过每一步都还是有些问题的。

分块(Block Splitting)

   本文最大的难点就是要想清楚这篇文章是如何进行分块和重组的。比如我们要进行44的分块,也就是把大场景分成44=16个小场景,一行4个,一列也4个。

   分块本质如上图所示,他的意思就是我们从头到尾的按照44像素的进行遍历,对于每一块44像素里面的每个像素,依次利用一个公式讲他们按顺序放入上图右边的块中。如上图所示,对于第一个4*4的小块,将第一个像素,放入第一块,第二个像素放入第二块....第16个像素放入第16块。直接遍历到图片末尾,就可以将图片中的像素全部均匀的分配到16个小块中了,也就组成了16个小场景,这16个小场景本身是完全不同的,他是把大场景中的像素进行了一个重新组合而已,还是以前的像素。并不是16个完全相同的场景。分块公式如下:

其中width,height为小块的宽度和长度,numX,numY是分块的数量,x,y是原始像素的位置。

计算光照

    计算光照就和普通计算一样,不过需要的是将所有的VPL均匀的分给每一块即可(可以通过自己当前处理的像素位置来计算当前是第几块场景,然后计算VPL的起点和终点即可)。但最最重要的一点是,需要将最后计算的结果乘以你分块的数量。大家可以这样想上面的分块的时候对于4*4像素要按顺序分到16块中,对于一个光源而言,原本这16个像素都要进行对这个光源的光照计算的,但是由于分块了,那么这个光源只会在一块中进行光照计算,那么剩下15个像素就不能计算这个光照了,所以亮度就暗了16倍,因此要乘以块数才行。有人可能会问,那么这个结果不就不准确了吗。是的这样处理之后结果会非常不准确,因此这个方法我们多用于间接光照(间接光照对场景的光照贡献不高,就算是不准确也很难发现)。光源开始结束索引如下:

其中width,height为小块的宽度和长度,numX是分块X方向的数量,x,y是像素的位置,num为分块总数量,N为光源总数量。

组合

    组合就是分块的逆过程。只需要把分块的像素再按照原来的样子复原即可。公式如下

边缘检测

    边缘检测是为了在进行高斯模糊的时候如果是遇到了边缘则停止模糊,这样会让边缘更。任意一种边缘检测算法都可以,文中的边缘检测算法太老了,大家可以自己找新的边缘检测算法。我采用的是判读当前像素的向量和深度与周围的像素之间进行比较,设定向量阀和深度阀,然后在动态调节这两个参数以达到好的效果。

高斯模糊

   有人可能会问为什么要进行高斯模糊呢?因为本文的思路是让一个像素去计算代替周围一块来计算光照,如此一来所有的光照影响都集中到一个像素中,但是实际应该是周围的像素都应该去计算光照的,所以我们采用高斯模糊的方法把这个光照的影响分一点到周围像素去,让效果看起来更加逼真。

融合

因为我们进行了高斯模糊,所以,如果在计算光照的时候把纹理带上了,那在高斯模糊的时候纹理也会被模糊了,就会看起来怪怪的,因此我们在计算光照的时候不带上纹理,最后计算完之后再进行融合即可。

代码地址:Non-interleaved Deferred Shading of Interleaved Sample