除了LOD外,地表材质也是Cryengine的一个比较出众的特性,Crysis的地表材质细节之丰富,绝对是目前绝无仅有的,但是支持它使用如此多材质的地表细节技术,却是Cryengine的一个特殊做法带来的。Cryengine并没有使用什么四层混合,而是按单层来划分的。当一层材质被刷到地形上的时候,Cryengine会生成一个材质的覆盖范围,也就是说每一个材质绘制时都有独立的IB区段,这样最大的好处是每个层都可以使用独立的渲染技术,而不会影响其它层,比如有parallax的地形层只有很少的一两个,但是混在其它层中却让地形细节有了整体的提升。还有就是因为地形距离有八公里,所以不可能都使用Blend的Tiling细节,在细节的几百米范围之外,就切换成只有一张的预生成大纹理,VirtualTexture技术在这里得到了应用。在同时使用了Tiling和VirtualTexture的情况下,Cryengine的地形远近都有很好的细节表现,同时性能上也能够支撑起八公里的视距。
当然Cryengine的地形技术中还有个神奇的Voxel技术。Voxel其实是个很古老的概念,应用到地形中应该是三角洲的时候。不过那时的Voxel技术不是很适应现在的图形管线,Cryengine只是使用了那Voxel作为一部分特殊地形的数据存储,最后用了某种算法,生成了与高度图Terrain无缝连接的Mesh,使得悬崖,山洞可以在引擎中用Terrain实现。通常要做这些往往都使用模型,而不同的系统使用起来很容易产生接缝。这就是Crysis地貌如此丰富的原因。
不过Voxel的生成算法,我还没有想到,或者看到,很想知道有什么好办法来实现这个。不知道龚敏敏大大是否有这方面的办法,或者有见过关于这个的文献。如果KlayGE能整合一个类似的算法,那就最好了。 很希望看到KlayGE的VirtualTexture和GI。目前我也正在整理一些解决方案,有这样的参考真的很不错哈。我可能考虑把LightMass和一种实时GI解决方案整合到无缝场景中。
接下来继续更新
Cryengine的阴影是我最喜欢的一个Cryengine的解决方案,它的科学性,实用性,让我很震撼。在目前的硬件条件下,Cryengine的阴影系统是一个比较完美的实时阴影解决方案。首先要说明的一点是,Cryengine2虽然不是DeferredShading,但是仍然有深度图可用,所以可以在屏幕空间计算阴影,这样能为PCF节省非常多的采样,与VSM相比,采样次数会更少。这样就有了下面的结论:PCF适用于实时性较高的阴影采样,因为一次采样的次数较少,而VSM更适用于低频更新的阴影,因为VSM可以预采样,采样完之后就能很快地生成阴影,这样的话,只要阴影不更新,VSM就不需要再采样。有了以上的思想,就有了Cryengine的阴影解决方案。首先用四张1024大的D24S8作为PSSM的四层,据我目测,PSSM的距离大概在200-300之间,由于远处的物件通常是在较浓的雾里,所以,其实远处阴影对画面的增益会较弱,近的阴影距离让Cryengine的四层1024图都获得了相当高的阴影清晰度。这四层阴影也并非实时更新,Cryengine对这阴影进行了控频,不过游戏中并未感觉到,只是Cryengine3在GDC2009的那段视频中,很明显看到了控频的痕迹。VSM则被用来渲染地形的阴影,众所周知,WOW的地形没有阴影,一开始我还以为这是对的,后来才发现原来WOW的光不会动,所以在阴影不被拉长的情况下,这样的阴影还是可以接受的,但是如果需要阳光动态变化,甚至拉到很长,没有阴影的地形会让物件的阴影腾空,相当难看,所以渲染地形的阴影还是有必要的。但是地形的阴影一般比较模糊,因为距离比较远,所以PCF对于地形来说,阴影边缘太过生硬,所以Cryengine选择了用VSM,在一张1024的R16G16F上渲染地形,然后进行一次Blur,由于地形的阴影渲染范围很大,再加上地形静止不动,和光线变化较慢的特点,地形的阴影更新频率非常低,这样,地形阴影渲染的开销就会比较小。在渲染地形阴影的同时,Cryengine还加上了云阴影,使得阴影非常完整,逼真。VSM使用半精度其实是非常冒险的,VSM不像PCF,利用统计学算法的VSM如果有完美的实数,将会是无比完美的,可惜,浮点的精度有限,想要VSM的阴影有一个模糊的边缘,高精度很必要。通常都使用32位的浮点,半精度会引起近处非常明显的条状失真。不过Cryengine的这个失真仍然存在,只不过并不是很明显,主要原因有以下两点,第一,地形本身是个低频细节的模型,所以阴影距离通常都比较远,第二,Cryengine使用的阴影距离近,所以,本身深度范围都小,所以精度自然就会比较高,浮点数嘛。所以Cryengine很有效地利用PCF和VSM模拟出了非常高效完美的阴影。这个解决方案目前也被我一直在使用。
关于采样,一般,PCF的采样是不如VSM的,原因是PCF是一个比较出来的二值结果,无法利用MipMap,线性采样和AA之类的预采样,这也正是VSM的优势,但是在DX9中,有个HWShadowMap的解决方案,利用透视校正的采样,可以利用线性过滤,一次采样即可得到4次差值的PCF,而在这个基础上进行多次采样,就可以得到非常柔和的效果。一般的,在动画或光发生改变时,阴影很容易发生抖动,这种抖动是非常刺眼的,这是由于被采样的纹理本身的锯齿抖动造成的。想要解决这个问题,一般就两种,VSM可以利用AA来解决,而PCF则利用随机采样。随机采样之所以不容易感觉抖动是因为高频的抖动不容易被人眼察觉的关系。GPU2上就有一篇文章描述一种随机采样方法,不过GPU上的采样方法比较原始,所以实用性并不强,Cryengine使随机采样到了一个新的境界。首先,GPU上说的方法是连续采样一张随机纹理,来得到随机的信息,但是这显然是种浪费,因为一次采样就可以得到随机了。Cryengine所用的方法是预生成一个圆形分布的采样点集,然后采样一次随机纹理,随机纹理上记录的是这个点集的旋转角度,这样的话,一次随机采样,就能使所有点都随之改变。而且也正是这些图形分布的点的旋转,使得阴影边缘更柔和了。GPU上的方法,随机采样的UV是屏幕空间的,这样的随机采样点抖动很快很频繁,而且容易被察觉到屏幕空间相关。Cryengine则是使用了一个光空间透视较正的办法,得到一个只与远近及角度相关的随机纹理UV,这可以把抖动降低。经过了上面的改进,Cryengine的阴影采样效果非常不错,虽然比不上SAVSM,但是比起以往的PCF阴影效果强了太多,把随机采样推到了一个新的高度。
关于ShadowPass,PSSM需要把阴影存在四个SM中,那么采样就会遇到用几个PASS的问题,像WOW,直接采样四张图,肯定会造成无效采样,性能会比较低,而GB则使用一张大图来存,通过变换来定位,再采样,而Cryengine用了另一种方法,使用模板,模板可以分别提取每层需要的像素,然后进行采样,四个Pass得到最终的阴影,理论上来说,全屏的阴影,应该是这个性能最优,因为采样的图更小,又没有重复采样的浪费。
以下是我使用这个解决方案得到的结果,因为引擎和时间的关系,我没有做阴影距离,所以是全距离阴影,我的视距为400米,我用了2048X4的PSSM,和2048G32R32F的地形阴影。因为我这个距离,地形阴影用半精度会出现严重的精度不足的VSM失真,所以没有办法,Cryengine在这个距离上是掐得相当准的,稍有偏差,就会导致无法接受的失真。