全局光照

From KlayGE
Revision as of 09:11, 6 May 2012 by Gongminmin (Talk | contribs)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

目前direct lighting在游戏中日趋成熟,比较前卫的游戏引擎已经不满足于direct lighting的效果了,逐渐开始尝试indirect lighting。早期的方法有通过离线渲染light map来实现静态场景、静态光源的GI。接着出现了PRT,可以处理静态场景、动态光源。CE3用了Light Propagation Volumes的方法,不需要预计算,可以产生动态场景、动态光源的diffuse GI。不过其速度和质量确实不敢恭维。难道就不能有全动态场景、全动态光源、diffuse和specular通吃的实时GI方法吗?有!Multiresolution splatting for indirect illumination(MRSII)前来救驾。

KlayGE 3.12中,团队成员atyuwen就已经实现了MRSII。经过半年多的改进,这种GI方法已经融入了新的Deferred Rendering框架中,并且性能也得到了很大的提升。下面就让我们来看看这种神奇的GI。

MRSII的渲染流程如下(感谢vanish整理了此流程图):

GI pipeline

首先,G-Buffer需要做mipmap,接着在每一层检测深度和法线的间断点,把那些间断点在stencil buffer中标记出来,得到了这样的stencil buffer:

Stencil Mip 0
Stencil Mip 1
Stencil Mip 2

和之前的stencil规则一样,最高位是1表示忽略。所以灰色的pixel是可以忽略掉的,黑色的是需要计算光照的。可以看出黑色所占的面积并不大,绝大部分pixel都被略过了。

另外,还需要生成一个Reflective shadow map。和shadow map类似,RSM也是从光源视角渲染一遍场景。除了深度以外,RSM还需要保存normal和flux信息。把RSM采样出一些点,比如256个,作为虚拟点光源(VPL)。目前KlayGE里面用的是均匀采样的方式,以后将改成importance sampling的方式提高VPL分布效率。

最后,每个VPL都可以根据BRDF生成一个light volume。用这些light volume去照亮G-Buffer的每一层。初始的light volume是个半球,在它的vertex阶段会根据各方向反射的亮度拉出某些顶点,生成一个奇怪形状的light volume。这个阶段因为涉及到大量的填充和计算,非常耗时,但因为stencil test是打开的,绝大部分pixel都会被挡掉,真正参与计算的pixel数远远少于G-Buffer的总pixel数,GI因此得到明显的加速。经过测试,在目前的场景下,如果只用一层G-Buffer(也就是不用multiresolution),速度只有用三层的一半。如果大于三层,速度已经没有提高了。所以默认就选了三层G-Buffer。

在生成每一层的indirect lighting结果之后,还需要做一个特殊的插值upsampling,才能得到光滑的结果。这个插值在MRSII的原paper中有描述,这里就不累赘了。

Indirect lighting: smooth sampling

如果只是用一般的最近点插值或者双线插值,结果会有很多悲催的锯齿:

Indirect lighting: point sampling

最后,把indirect lighting加到direct lighting中,继续做下一步的shading pass。最终结果如下:

Final GI

比较只有direct lighting的结果,可以看到右边和地面被照亮了:

Final no GI

用了MRSII后,对于512×512的RSM、256个VPL、三层G-Buffer的情况下,GI在GTX480上只需要1.09ms、在9800GT上需要4.3ms。目前还有不少性能空间可以挖掘,我预计在同质量的情况下,最终能达到在GTX480上0.5ms、9800GT上2.5ms的速度。

这套GI的框架不但可以做这样的反射型indirect lighting,也可以做caustics这样的高频反光,也可以处理sub-surface scattering等材质效果。在KlayGE以后的版本中,MRSII将会得到持续的发展。