转载请注明出处为KlayGE游戏引擎,本文的永久链接为http://www.klayge.org/?p=819

KlayGE中的延迟渲染(四)集中在Anti-alias的方法,本篇是这个系列的完结篇,我们一起来探讨未来将对延迟渲染所做的改进。

展望未来

shading pass再次渲染物体的改进

Deferred Lighting最受争议的一点应属在shading pass需要再次渲染几何体了。如果物体很多,尤其是有tessellation和GS的,多渲一遍有可能抵消了lighting pass带来的性能提升。改进的方法之一就是在建立G-Buffer阶段,用类似Deferred Shading的fat G-Buffer。除了原先的一张纹理,还需要一张纹理用来存放diffuse信息。但是lighting pass和原来一样,不涉及diffuse。shading pass就变成画一个全屏四边形,从G-Buffer的第二章纹理读取diffuse,进行着色。甚至emit也这么处理。这种方法介于Deferred Shading和Deferred Lighting之间。

彩色的specular

在本系列的第一篇文章里, 为了把lighting pass中的diffuse和specular都塞到4个通道里,就只能舍弃specular的颜色,只保存亮度。如果要RGB三个通道的 specular,近似的方法是通过diffuse积累结果的颜色来计算specular的颜色。这是个很粗糙的近似,虽然不是正确的,不过能骗骗眼睛:

其中lumspec是累积出来的specular亮度,lumdiff是用累积出来的diffuse颜色计算出的亮度。epsilon是为了避免lumdiff为零。
另一种方法是lighting pass用6个通道。但是如果每个通道都是float 16的,也就是96bpp,带宽开销非常大,就不合适了。我的一个想法是把diffuse和specular都转换到YUV空间。这个空间的一个好处是Y 是float 16的,U和V都只要8 bit就可以了。所以可以这么安排MRT:第一张texture格式为G16R16F,保存diffuse和specular的Y;第二张texture 格式为ABGR8,分别保存两者的U和V。这样只有64bpp,但能保存正确的彩色diffuse和specular。由于YUV格式也是可以相加的,这 个地方仍可以用原先的lighting pass积累方法。

inferred lighting

Lighting pass可以借用inferred lighting的核心思想来加速。也就是说,lighting pass不需要全尺寸,只需要在一个比较小的render target上执行即可(比如3/4大小)。G-Buffer仍是全尺寸的,并在G-Buffer生成后作一次边缘检测。Shading pass也是全尺寸的,在采样lighting pass texture的时候,利用边缘检测的结果进行保边缘的插值(一般称为Discontinuity Sensitive Filtering,DSF),得到全尺寸lighting的近似。

DSF
上图是使用了800×450的lighting直接拉伸到1280×720做shading的结果,关闭DSF,锯齿严重。下图打开了DSF,基本解决了锯齿问题。

Anti-alias

上一篇文章讲了很多AA的方法,但那些都是在空间上做AA,比较适合近处物体。对于远处物体来说,空间上AA得到的收益有限,必须在时间上进行AA。结合上MLAA的威力,应该能有很小的代价实现很接近16xMSAA的结果。

各向异性BRDF

Crytek的“CryENGINE 3: Reaching the speed of light”里提到了在Deferred Lighting框架下加入各向异性BRDF的方法。它用了Spherical Gaussian(SG)来近似出NDF(来自于SIGGRAPH Asia 2009的All-Frequency Rendering of Dynamic, Spatially-Varying Reflectance),但这个SG只是per-object的。在G-Buffer阶段,不保存normal,而保存SG展开成lobe的系数。而 BRDF的其他几个项,Fresnel term、Geometry term,都留到shading pass才计算。这种方法的好处是,对lighting pass来说一切都是透明的,它照样可以按原来的方法累积光照,因为Microfacet BRDF中除了NDF,其他都作为公因数提取出去了(Microfacet BRDF的详细讲解可以参见“游戏中基于物理的渲染(三)”)。实际上,Fresnel term的系数是lh,必须在lighting pass做。这里相信Crytek是用了nv来代替,这样不是物理正确的,只有在高光的中心点,dot(l, h)才等于dot(n, v),其他地方dot (n, v)会更迅速地衰减,到边缘地方就非常明显了。如果不在乎这个,是可以把NDF都用SG来表示,并用统一的方法进行渲染。

保存lobe的G-Buffer是这个样子的:

lobe in G-Buffer

各向异性BRDF渲染出来的结果:

Anisotropic BRDF

KlayGE中的延迟渲染就介绍到这里了。在这里先给大家拜个早年,谢谢!