KlayGE 4.4中渲染的改进(三):高质量无限地形
本系列的上一篇讲了DR中的一些改进。本篇开始将描述这个版本加入的新功能,高质量地形。
原有的地形
以前的地形实现和水面的方法一样,都是从Crytek在2008年的老方法改进而来。虽然比projected grid的好得多,并且速度很快,但有一些很明显的缺点:
- 视点移动的时候会抖动。水面比较平,而且有波浪看不出抖动。如果用来做静态地形抖动就会非常明显。尤其是far plane变大之后,远处更明显,所以限制在3000以下。
- 不支持shadow。因为只有产生了视野内的三角形,视野外的地形无法正确投出shadow。
- 顶点密度较低,无法表达精细的地形。原先的方法三角型分布接近于screen space,不足以很好表达地形。
这个抖动的消除可以靠snapping操作,每次更新height map的时候都保证原来的像素中心仍然落在新的像素中心上。这样每个顶点在视点移动后仍然会去到同样的值。
Clipmap
Clipmap也不是什么新东西了,最早出现于1998年。当时还是用CPU做几何生成和提交。2004年MSR的一篇Geometry Clipmaps: Terrain Rendering Using Nested Regular Grids把clipmap带到了GPU时代,GPU Gems 2的第二章就是这篇paper的缩写版本。通过在GPU上维护一个以视点为中心逐级递减的一系列几何块,依靠GPU的强大处理能力,过度细分的地形也能实时渲染。用这种方法,远处的三角形密度仍然较大,所以可以很容易的把far plane推到5000-8000。
但是,即便是2004年的方法,也已经过去了将近10年。当时的SM3能VTF,却不能改变几何拓扑。在实际使用中,这个方法的开销还是比较大的。而且由于不同层次之间的三角形密度一定是2倍的关系,难免还是会有看得见的层次跳变。
Tessellation
(这里的实现是从NVIDIA Direct3D SDK 11的一个例子改进而来)
DX11的GPU都支持tessellation,而且效率不低。这里对clipmap很自然的改进就是加入硬件tessellation支持,把细分的任务转到GPU里做。这样CPU端直需要提交比较稀疏的几何,在GPU里通过视点距离等因素计算tessellation level就可以了。而且,DX11要求GPU支持基于浮点的细分。三角形不但可以分整数次,还可以分任意的浮点数次。这么一来,就能让细分层次连续变化,层次跳变问题就彻底解决了。
如果检测到GPU不支持tessellation,就会退回到原先的clipmap方法。这时候需要处理不同层次之间的接缝问题。因为在连接处顶点密度不同,如果不处理的话,就会出现许多小的空洞。这个问题由团队成员孙文全解决了,方法是调整较密层次的顶点,在shader里面手工插值,得到和较稀疏层次同样的height。这么做虽然没有在拓扑上达到无缝连接,但GPU的精度足以保证空洞基本都会小于一个pixel的大小。所以视觉上看不到空洞了。
Procedural
在Texturing and Modeling: A Procedural Approach这一巨作中,有详细介绍如何用分型的方式生成地形。这个方法也可以顺利地移植到GPU,在生成height map的时候使用。如果参数合适,生成的结果很像自然的风景,有崇山峻岭也有平原低地。height map以视点为中心,加上snapping的修正,得到视点周围一定面积的所有高度场。这个height map可以进一步用来计算gradient map,在渲染的时候作为normal使用。以视点为中心,所有方向都有几何也保证了可以轻松地使用原有的shadow map系统,包括CSM在内。
加上细节
有了tessellation之后,height map里的信息只负责大体形状。顶点密度远大于height map的情况下,加上个noise就有意义了。normal上也可以用同样的方法加上像素级别的细节。有了这些之后,tessellation的能力就能全部显现出来了。并且可以根据GPU能力连续地调节细分的程度和细节的多少。
在不支持tessellation的平台上,这个细节就只能加到normal上。视觉效果也不差。
综合一下,加入水体、light shaft、SSR等效果之后,可以发现新的地形系统可以很容易兼容于原有deferred框架的其他组件。
本篇专注于新实现的高质量地形。下一篇仍会将一个新的渲染效果,屏幕空间次表面散射。