首页 > 代码库 > 探寻次时代渲染 - CryEngine2

探寻次时代渲染 - CryEngine2

Advanced Real-Time Rendering in 3D Graphics and Games Course – SIGGRAPH 2007

探寻次时代渲染 - CryEngine2

作者:Martin Mittring

   Crytek 游戏公司

翻译:潘曦

(译文里的pancy:XXX)为译者注)

              (本系列文章由pancy12138编写,转载请注明出处:http://blog.csdn.net/pancy12138)

1:来自于获奖游戏”孤岛危机”的一张截图,它的发布为渲染界开辟了下一个时代。

 技术分享

 

2:来自于即将到来的最新的孤岛危机的截图。

 

 技术分享

摘要

在这篇文章中,我们并不具体探讨某一种特定的算法。而是尝试去寻找德国公司Crytek使用的一些能在一起发挥出更好的效果的渲染算法。(pancy:这篇论文所提到的大部分算法都是以往就提出的,Crytek所做的工作是从众多的图形算法中找到最适合使用的算法,将他们经过一些改变,让他们能够更易实现,互相融合并应用于真正的图形工业当中。这对于现代实时渲染技术的发展意义很大

我们认为这些信息对于所有希望能够实现与Crytek公司相似的渲染效果的人员来说都是有用的,因为往往我们在算法实现的时候所遭遇到的瓶颈正是在某一渲染效果的基础上实现一个渲染效果的时候(pancy:也就是我们在同时用多种渲染算法渲染场景的时候,出现的问题和bug也最多),我们同时简明的介绍了一些你可能会考虑使用的可以用于替代那些方法的途径。我们并没有把图形方面所做的所有工作完整的进行讲解,因为在这篇文章中我们挑选了读者们所感兴趣并且我们能够拿得出手的领域的拓展技术进行讲解。Crytek的开发选取了图形学社区近年来最具先进意义的理论研究,并且结合了一些新的思想以使得这些先进的理论能够有效的映射到当今的图形硬件当中。

介绍

Crytek studios所开发的一个技术出色的第一人称射击游戏”孤岛危机”在其一经发布便广受好评,“孤岛危机”的出现提高了所有同类型游戏的制作门槛,当我们公司成功开发了“孤岛危机I”之后,一个很自然的想法是使用这目前的的引擎来经过很少的改变制作一个它的续作。因此续作会几乎使用在第一作中用到的相同的引擎。当然,这是一个最简单且获利最高的决定,但是我们相信这种想法必然会限制我们最初的目标-为游戏赋予更好的技术和艺术。因此我们决定去设计一个全新的次时代渲染引擎并且设法提高新引擎的设计和架构,除了新添加的一些特性,新的游戏“孤岛危机II”将会继承一代的游戏风格,不过新的游戏获得各个方面的极大范围的效果提升。游戏的一切将会变得更为庞大和优秀。而我们所设计的新的游戏引擎 CryEngine2则会让我们的梦想成真。(pancy:这篇文章的讲解重点,众所周知的著名次时代引擎CryEngine,introduction写的简直豪气冲天)

在我们阅读了设计文档以及开过了一个紧张的审议会议之后,我们所有的设计师,程序员,以及艺术家达讨论出了一组新引擎需要达成的如下目标:

游戏需要包含三种不同的环境:

 技术分享

3:丛林中的天堂

拥有大量的模型对象,三维高度图,海洋,广阔的视野,来自于一个方向光源的环境光。

 技术分享

4:外星人的室内场景。

拥有许多点光源,整体偏暗,区域划分,几何体相互遮挡,体积雾效果

 技术分享

5:冰雪环境

冰材料层,地面的次表面散射

完成所有的三个场景是一项极具挑战性的工作,主要的优化难点在于他们拥有完全不同的特征。

1.避免触发恐怖谷效应的电影级渲染pancy:恐怖谷效应,当虚拟人物的真实程度将要达到真实人类水平而未达到时会出现一个“恐怖谷”此时人类会对这种虚拟人物感到最大的恐惧和厌烦,当真实程度真正达到真实人类水平的时候才会让人类对其的好感回升):渲染质量越接近视频质量,则观众就需要对游戏投入越少的忍耐。

 

 

2.动态光线与阴影:提前算好的光照数据是许多算法提高渲染质量和性能的一个关键因素,而由于这些算法往往具有静态依赖的特性,所以我们不使用这些算法而是使用动态的光影算法。

 

 

3.支持多个GPU与CPU协同工作:多线程加多个图形卡协作开发是一项很复杂的任务,因为我们大多时候必须要为了更好地协同而牺牲其他的配置。

 

 

4.场景大小需要21km*21km的游戏范围:我们希望做到这一点,但是最终的生产,流水线,以及世界的持久性收益并不值得我们做这些努力,最终我们实现了多个4km*4km的游戏范围。

 

 

5.显卡指令从shader model2.0升级至shader model4.0(Directx10):虽然看上去使用shader model2.0作为开发指令是一个最方便的选择,但是这种做法会使得我们在directx10下使用最新的图形卡和图形驱动进行开发受到阻碍。

 

 

6.高动态曝光(HDR):我们在“孤岛危机I”中使用HDR获得了非常好的效果。为了更真实的视觉效果,我们希望设计的游戏不受低动态的亮度差所限制。

 

 

7.动态环境(可能会被break):这是一项很酷炫的技术,不过非常难以实现。

 

 

8.在开发渲染引擎的时候同时开发游戏:这将迫使我们总是在一些正在使用的状态中进行编码,这对于一个小型的工程是比较简单的,但是当工程变得巨大的时候这项工作将变得极具挑战性。

 

我们的概念艺术家创作了许多概念图来确定了游戏最初的雏形。但是为了让大家感受到最终的渲染效果,我们通过外包公司 Blur3 studio制作了一份宣传我们设计理念的视频。这有助于让我们达到我们希望达到的外观和感受。

 技术分享

6:Blur3制造的用于为Crysis公司的引擎设计的概念视频的一帧截图

概括:

在这篇文章的余下部分,我们会先讨论CryEngine2所使用的新的着色框架,这个领域对于我们的大范围场景来说是一个极大的挑战。之后,我们会介绍我们在实现直接照明与非直接照明效果时所使用的解决方法(包括一些设计思路),我们使用专门的算法将不同的光照从总问题中隔离出来讨论,并且用更为先进的方法来解决它。在做完这些处理后,我们先从阴影的角度来处理直接光照(因为阴影在不同复杂度的shader中都可以很轻易的完成)。间接光照我们可以用环境光遮蔽技术来进行模拟,通过简单的令光线变暗来代表环境光遮蔽的贡献。最后,我们涵盖了各种算法去解决各个层次的细节问题。当然,本篇文章只会包含我们引擎在渲染方面所做的工作,但是这依然会给予读者读我们整个系统的一个不错的”品尝”,并且运行我们在这些选定的领域做足够深入的挖掘。

着色器与着色技术:

1.cryengine1的历史回顾

“孤岛危机I”中,我们支持的最低等级的显卡设备是NVIDIA GeForce 2系列。这也意味着我们不仅可以使用顶点着色器和像素着色器,还能共同支持固定管线T&L函数与寄存器管线(通过提前运行pixel shader解决方案来进行纹理混合)。为了达到这个目标以及支持更复杂的材质,我们的Directx和Opengl的shader脚本有了更复杂的规则。在“孤岛危机I”之后,我们希望提高前作的质量并且重构之前的系统。首先我们移除了所有固定管线的支持,并让语法更贴近于[Microsoft07]中所描述的FX语法格式。在项目的晚期,我们为项目加入了一个基于接über-shader的一些新的渲染路径。这基本上是由一个使用CG或者HLSL语言书写的包含了很多#ifdef的一个pixel shader和一个vertexshader组成的渲染路径,这使得开发变得简单而快捷,因为我们完全的避免了手动优化的步骤。早期的shader编译器还不能够总是创建出达到人类手工优化的汇编指令,但是在shadermodel2.0的显卡上已经修缮了很多。über-shader渲染路径的内置变化非常的多,所以将他们一次全部编译时不可能的,我们在开发过程中发现在编译的时候有明显的延迟(当我们不得不编译shader的时候),但是我们希望能够在建立游戏的时候拥有一个已经预编译好的shader存储器。我们会在一开始暂停我们的游戏在Nvida或者Ati硬件设备上的运行直到我们的缓存器读完所有的信息。更多细节可以参考我们的第一款引擎的[Wenzel05]章节。

2.cryengine2

我们决定减少需求的数量以使得新的引擎更加简洁,因此我们移除了opengl的支持以及固定管线的支持,这使得我们可以将shder的格式更接近于FX格式,shder的开发和学习也变得更加方便和简洁(pancy:FX格式是微软为directx实现的一种shder管理格式,cryengine要想在opengl以及固定管线中也是用这种格式是比较困难的,移除这两个支持极大的统一了shader格式)。我们面临的另一个待解决的问题是shder的组合太过庞大,我们重建了整个shader系统,围棋添加了一个shader需求列表缓冲器。这一列表的数据通过网络从公司的所有机器上获得,并且我们在夜间对缓存中的shader进行编译工作。然而编译时间仍然显得过长了,因此我们决定通过以下操作来减少shader的组合个数。

1.动态分支。

2.减少组合并且接受更少的功能。

3.减少组合并减少一定的性能。

4.多通道分离。

我们通过使用分布式的shader编译器的多次迭代,在一个小时内完成了所有shader的编译。

3.格式法线贴图

ATI[ARI04]提出的3DcTM纹理格式允许将法线贴图的每个像素点通过一个高质量且只有一点点额外shader(重建z缓冲区)的代价压缩至一个字节,未压缩的法线贴图一般使用4个字节来存储一个像素(法线的xyz存储在RGB分量中,另一个字节的分量会被填充并浪费),在我们的新引擎中,我们决定在纹理的加载过程中不做压缩操作,而是在我们的纹理处理工具中进行处理,在纹理处理工具中为其创建mip levels和压缩。这种方法使得我们通过简单的预处理得到了快捷的加载速度。对于那些不支持3Dctm的硬件,我们会在加载的时候将这种格式转化为DXT5格式,这种格式与之前的格式非常的相似因此转换是很方便的。当视频质量规格较低的时候纹理转换带来的质量上的损失是可以接受的。而且即便是较为古老的NVIDA显卡的驱动也是有3DcTM纹理模拟的,所以我们不需要在这个方面做过多的关心(这种模拟是没有转换损失的,相应的代价是每个像素需要2个字节的存储空间)。

4.逐像素景深

使用提前的深度缓冲测试可以减少像素着色的代价,因为大部分像素都可以在深度测试的时候被剔除掉,这样就这些像素就不需要在pixel shader里面被执行。由于我们希望使用更复杂的pixel shader进行像素着色。我们的渲染管线从一开始就使用提前的深度缓冲区测试。如果这样做的话,我们就需要添加更多的draw call(pancy:我们通常使用的z-test是在 pixel/fragment shader 之后的,如果希望在此之前进行测试则需要先把场景写入到深度缓冲区一遍,这样就至少多了一次draw call)。而在很多效果器(pancy: effect是FX格式所定义的单位,包含一整套渲染路径,此处翻译为效果器)当中,我们还希望能够使用到场景的深度信息。这样我们就需要将深度缓冲区的输出绑定到纹理资源上以备使用。一开始我们使用R16G16的纹理格式,原因是这种格式能够被所有的硬件所支持并且16位的大小也足以实现我们想要的质量。最初我们是使用双通道的纹理资源但是最终我们优化了这个方法。在ATI的显卡上,我们使用R16纹理格式以节省一些内存和带宽的消耗。我们意识到在一些硬件设备上R16G16格式要比R32格式的速度要慢,所以当显卡不支持R16格式的时候,我们采用R32格式去替代它。当然,直接访问深度缓冲区是一种更好的选择,因为这样我们不需要额外的内存,提前的深度测试会变得更加快捷(在一些硬件上不写入颜色到纹理可以提升两倍的速度)。因此在最后我们根据机器的支持程度来使用R16,R32甚至是默认的深度缓冲区。深度数据被用于在延迟渲染中的一些渲染技巧当中(pancy: CryEngine在这篇论文里面所使用到的很多算法都是需要深度重建的,比shadowmap和ssao,这些算法的特点就是通过屏幕空间的深度还原原始的点坐标的三维信息来大大减少算法在像素着色器上的复杂度)。通过一个MAD操作以及一个三分量插值机,我们完全有希望根据深度信息重建这个点的原始三维信息。当然,如果需要达到浮点型的精度,还是最好根据摄像机的位置或者临近点的位置进行三维重建,如果我们在pixel shader里面使用了24位或者16位的浮点数据的话,那么这种三维重建的方式就变得很重要了。通过偏移所有的模型对象以及光源,我们很容易让观察者接近坐标原点(0,0,0)。如果不做这个操作的话,贴图和动画效果会出现很多跳动和闪烁。我们将景深效果应用于逐像素的场景效果其当中,最终效果和全局雾效,体积雾,以及软深度缓存粒子的效果很相像。

阴影模板的创建也借助场景的深度来减少draw call个数,对于水面的模拟,我们也可以使用深度数据去柔化水面效果,并沿着海岸逐渐增强。一些后处理效果例如运动模糊,景深模拟以及边缘模糊也同样会用到各个像素的深度信息。这些算法的细节记录在[Wenzel07]。

5.世界空间着色

“孤岛危机I”当中,我们将视点和光源转换到了切线空间(根据物体的表面方向),由于所有传入pixel shader的数据都是定义于切线空间的,所以很自然的着色算法也是在切线空间进行的。而这也使得我们在程序中能够运行的光照数量受制于shder内部插值器数量的限制。为了解决这一问题,我们决定将着色模型从且切线空间着色转换成世界空间着色(事实上,我们在运行世界空间着色的时候做了一些偏移以减少浮点类型顶点的精度丢失)。这种着色方法在实现cube map反射算法的时候同样需要用到。因此着色代码会变得更加统一和高质量,并且世界空间也不会像切线空间一样容易扭曲。一些影响因素例如光源的位置可以在pixel shader中设置为常量,这样就不必在所有的模型对象中都进行更新。当然如果我们只是用一个光源或者单一的shader进行着色的话,这种做法在额外的像素计算上付出的代价就会显得比较高。(pancy:这里提到的方法相当于我们现在所说的延迟渲染框架,延迟渲染的好处是剔除了所有我们眼睛看不到的顶点使得多个光源的性能大大提升,如果场景只有一个光源的话那就完全丧失了其优势。)

阴影与环境光遮蔽

1.CryEngine1的阴影模拟

在我们的第一作“孤岛危机I”中,我们使用了shadow map技术根据一个全局太阳光为每个模型结构构建了一个阳光下的阴影。在当时我们就已经遇到了一个典型的shadow map贴图混淆的质量问题,但是在当时这项技术已经是一个最好的选择了。考虑到性能方面的问题,我们将植被的阴影做了预先的计算,但是由于内存的限制我们只能使用极其模糊的贴图来模拟植被。在高端配置的硬件设备上,我们甚至为植被也加上了实时的shadow map算法,但是将这些阴影与与计算阴影相互结合的时候仍然有很多缺陷。对于点光源,我们采取了模板阴影算法来计算阴影,而这对于点光源来说是简洁而先进的阴影算法。CPU上的蒙皮操作(pancy:蒙皮操作是指骨骼动画里根据父子关系存储的骨骼坐标系对人体或动物的表面顶点进行变换的过程。如今所有的蒙皮操作都是在GPU上进行的,如果在CPU上进行的话不仅会拖慢程序的帧率,还会大量消耗CPU)允许我们将阴影轮廓从CPU里抽出,然后在GPU里面渲染模板阴影体。很明显,这种做法要求我们拥有更精致的模型对象,并且需要额外的CPU开销来做蒙皮工作以及将蒙皮结果上传至GPU,同时,我们还得准备更多的内存来存储轮廓数据。这使得我们几乎无法预测最终的性能特征(pancy:CPU过度使用将使得性能预测不可用,因为此时有可能CPU成为渲染瓶颈以至于不能根据GPU运算能力和问题规模预测和优化算法复杂度)。并且,这种做法还会使得我们无法使用alpha混合以及阴影投射技术。这也就意味着这项技术甚至不能用于渲染对于热带岛屿非常重要的棕榈树(图7)。

 技术分享

7:“孤岛危机”截屏:注意与计算的阴影与实时计算的阴影柔和的混合在了一起

在开发的过程中,我们希望对所有的室内阴影使用模板阴影体技术,然而,这种技术产生的多光源下的硬阴影的外观和性能都不能令人满意,这使得我们希望能寻找其它的技术来解决室内阴影问题。一个解决方案是将阴影存储在光照贴图当中,光照贴图能够在无论多少个光源的照射下保证阴影的柔和性。然而不幸的是光照贴图存储的是着色之后的光照结果,这是一个单纯的RGB纹理,因此我们无法在其上面实现法线贴图。我们解决了这项问题并且为我们的解决方案起名叫做Dot3Lightmaps[Mittring04],在我们的解决方案中,我们在光照贴图中存储了一个平均后的切线空间中的光线方向,一个平均后的光照颜色以及一个在纯粹的环境光和纯粹的方向光之间插值之后的混合值。这个操作使得我们能够很快地计算出各个静态光源对于软阴影效果的贡献。然而这种阴影贴图难以和实时阴影混合,在“孤岛危机”发布之后,我们试验了一种简单的修改,并为之命名为遮蔽映射(Occlusion maps),这种做法的主要概念是使用一个0-1的值作为阴影掩码来代表几何体对于纹理元素的遮蔽几率。我们在光照贴图当中存储了来自于多个光源的阴影掩码并且通常所用的四通道纹理允许一个像素点存储四个光源的掩码信息。通过这种方式,我们实现了一种高质量的软阴影并且成功的计算出了每一个漫反射光以及镜面反射光对其的贡献值,同时,光照的颜色和强度还是可以灵活改变的。我们一直保持所有光源的信息是分开的,这样才能保证他们和其余类型的阴影完美的融合。

2.CryEngine2的计划

我们认为是时候统一一下整个阴影系统了。由于上面提到的一些问题,我们决定放弃模板阴影算法(pancy:shadow voluem就这么没了deth)。而shadow map总是可以提供高质量的软阴影并且可以方便的调控性能和质量,因此我们选择这项技术来实现我们的阴影。然而这项技术只能用于直接光照下的阴影模拟,而如果没有考虑到间接光照的话,我们的游戏就很难达到电影级别的渲染效果。因此,我们计划使用这个方法来解决直接光照阴影,而使用另一个方法来解决间接光照阴影。

3.直接光照

对于直接光照,我们决定只使用shadowmap技术(将几何体对象在视线方向的的深度存储在一个2D纹理当中)而取消所有的模板阴影的使用。

<1>:动态遮蔽贴图:

为了能够有效的处理静态光源的位置,我们希望做一些新的探讨。通过对室内几何体进行一些独特的展开,shadowmap的查询结果可以被存储在遮蔽贴图中被动态的进行更新。动态遮蔽贴图的思想史很好的,并且确实起到了一定的作用。但是由于阴影总是会产生混淆错误,所以现在我们不仅仅是阴影,连几何体的展开也出现了混淆。以往用于改善这个问题的纹理拉伸技术有些过于古老了,并且它也不能避免掉所有的纹理拼接缝隙。由于我们依然需要为动态的物体计算shadowmap,所以我们决定最大程度的加大通用的shadowmap并且降低遮蔽贴图的大小(pancy:shadowmap算法虽然非常简洁,但是问题也很多,常见的包括阴影锯齿(也就是这里提到的混淆效果),阴影瑕疵等等,这是由于shadowmap在一定程度上属于光栅类算(shadowmap被存储于纹理并且在使用的时候被反投影来寻找深度),因此其效果取决于视截体的大小以及阴影贴图的分辨率

<2>:shadow map与屏幕空间随机纹理查询:

平面shadow mapping因为混淆现象而变得非常糟糕并且会产生非常严重的锯齿边缘(见第一张印象图)PCF滤波算法(百分比滤波)可以减轻这个问题,但是它需要进行更多的采样,考虑到当初的硬件运算水平,这种滤波算法仅仅能够在NVIDA6代或者7代的图形加速卡上运转,并且仿真速度被大大的拖慢了。而在更先进的ATI的显卡上,我们可以使用Fetch4函数(在[Isidoro06]中定义)。为了代替使用更多的采样实现PCF算法,我们还设计了一种随机像素查找的方法以减少采样数量来达到相似的阴影效果。当然,这会带来一点图像的噪声,噪声(或者躁点)在任何影视图像上都会有,所以我们可以根据采样数量来灵活的控制和调整运算性能和质量。我们的灵感来源于光线追踪的软阴影算法。并且这项算法已经应用于GPU上的shadowmap创建。(具体的提升和优化shadowmap质量的细节请阅读[Uralsky05]与[Isidoro06])

盘状分布的随机偏移可以被应用于2D纹理的查询。当我们使用一个较大的偏移量的时候,平坦的表面的阴影渲染质量将会由于其表面被随机纹理确定的方向而提高,一个3D的图形例如说球体将会消耗更多的渲染资源,但他应归属于偏移的柔化问题。

如果想要得到没有太多噪声的可接受结果,我们就需要更多的对阴影图进行采样。因此,采样次数与随机算法就可以根据需求的质量和效率不同来进行选择。我们尝试使用了两种方法产生圆盘状随机点,一个是对于各粒子进行随机的进行旋转[Isidoro06],另一个是使用一个简单的像素着色器。

 技术分享

8:不同质量的shadowmap样例:从左至右依次是,无PCF,PCF,8次采样,8次采样加blur,PCF加8次采样,PCF加8次采样加blur。

第一种技术需要一个静态的2D随机点以及一个存储着随机二维旋转矩阵的纹理。幸运的是二位旋转矩阵比较小(2*2)可以被存储在4通道的纹理中,由于矩阵是正交的,所以还能够进行进一步的压缩,但这不是必须的。负数的话可以用常用的“放缩偏移”方法进行转化(乘2减一)(pancy:x= x*2-1可以将[0,1]转换到[-1,1],因为通常的纹理只能存储0-255,因此shader中得到的颜色也是0-1)或者使用浮点纹理来存储(浮点纹理格式,不用0-255存储颜色而使用float存储颜色,最新的显卡都加入了这种扩展以方便的实现shadowmap,ssao,hdr等算法)。我们尝试了很多种不同的采样表,并且在图8中你可以看到应用这些采样来模拟软阴影的效果是不错的。对于一个圆形的随机盘状数据也许你希望将其完全填充,但是我们并没有填充其里面部分的数据因为他们对于采样来说很少被用到。这种算法效果的瑕疵已经很难被察觉了,但是为了更正确的结果,我们仍希望在算法上做一些改进。

一个更简单的获取采样点的方法是将一个或者两个2D纹理上的随机正采样点进行简单的变换。第一个点可以放在中间(mx,my)然后其他的四个点将根据随机向量(x,y)放在中心点的周围:

(mx,   my)

(mx + x,my+y)

(mx - y ,my+x)

(mx - x ,my -y)

(mx + y,my -x)

这种做法使得我们可以构造出更多的采样点,当然我们发现这种做法只是能够提升那些低端显卡的材质渲染的速度(因为只有在低端显卡上我们才需要考虑限制采样个数)。

这两种方法都允许我们调整采样点的大小来实现软阴影。为了得到正确的结果,这个点的大小取决于投影距离以及光照半径,当然这通常都是很容易近似计算的,最初我们采用64*64的纹理来1:1的映射屏幕像素(图9)。

                       技术分享              

                          9:一个随机采样点纹理样例。

这个随机纹理是经过精心制作以体现其随机性:在很高维度上都不可辨认出其特征细节。创建一个随机纹理图是最直接的方法,我们还可以手动生成一张特征易于辨认的纹理然后我们就能够通过一个简易的算法来寻找一些可以用于交换的相邻点,一个好的交换方式可以提高纹理的随机性频率(这个计算结果来自于对差异值的总结收集(pancy:大概是用类似于我们计算方差的方法来判断纹理的随机程度如何))。当然,直接创建一张高随机频率的随机纹理是一个更好的选择。我们描述这个方法是因为这项技术更适合我们的目的。

 

影视级的效果并不意味着我们要实现静态的效果,所以我们有可能将噪点进行运动并且希望这么做能够在采样率比较低的时候借助运动来隐藏这些噪点。不幸的是我们最终得到的结果就像是一个新的工艺品一般,帧率变得很低而且不稳定。那些没有动画的静态场景的噪点还能够差强人意,而随着摄像机的运动,一些随机纹理的静态特征所造成的噪声开始出现在屏幕上。

<3>:shadow map与光照空间随机纹理查询:

幸运的是我们找到了一个很好的办法来解决这个问题,我们在世界空间的太阳光照方向上创建了一个mip-map映射的噪声纹理以代替之前的屏幕空间噪声纹理,在中远距离上的渲染结果与之前是相似的,但是由于使用的双线性插值所以近处的阴影边缘变得扭曲而不再有噪声点了。这个视觉效果看上去比以前强了很多,特别是植物和植被,那些很难描述具体阴影形状的模型。

<4>:阴影掩码纹理:

我们将阴影的查找从我们的渲染管线中分离了出来,这样就可以避免受到shader mode2.0的最大指令数的限制,减少shder的组合个数以及允许多个阴影进行混合。我们通过查询平铺空间纹理获得了一个8位的阴影贴图,并称之为“阴影掩码”由于一张普通的纹理有四个通道32位作为渲染目标,所以一张4通道的纹理可以将四个灯光的阴影掩码存储在一个像素点里。

 

 技术分享

10:一个使用随机查找的阴影样例。左上:没有抖动,1次采样。右上:屏幕空间噪声,8次采样。左下:世界空间噪声,8次采样。右下:世界空间噪声,调整后的8次采样

技术分享

11:一个给定场景的阴影掩码纹理样例:左图:通过一个太阳光(视作一个阴影投射)以及两个阴影投射光源。右图:来自于三个光源的阴影模板纹理的RGB显示

 技术分享

12:一个给定场景的阴影掩码纹理的样例,RGB通道代表三个独立光源的阴影掩码。

在渲染管线中,我们将这个纹理进行绑定并且立即根据这个纹理渲染出所有的光照和环境光效果。当然,我们除了RGB通道外,还可以将帧缓冲区的alpha通道一并使用,但是这样我们就需要更多的pass(pancy:每个渲染算法的一趟渲染称为一个pass,一般高级的特效都是经过好几个pass共同渲染的结果)以及draw call(pancy:每次调用图形api的draw操作称为一次draw call,在当年drawcall的数量会极大的影响程序的效率,因此一般都会严格控制到几百个左右,不过最新的硬件和api已经在这个问题上做了很大的修缮,Directx12甚至宣称十万drawcall都不会影响到渲染效率)。对于不透明的物体以及仅仅需要alpha测试的物体(pancy:与alpha混合不同,alpha测试是直接扣除alpha通道不符合要求的像素点,一般来说如果一个点只需要alpha测试意味着这个点不属于需要进行半透明混合的点,多半是全透明或者用于某些算法的预计算)阴影模板可以得到非常好的效果,但是对于那些需要进行alpha混合的几何体来说这种算法起不到任何作用(pancy:当今流行的大部分屏幕空间的算法呢最大的问题就是很难处理半透明物体,像延迟渲染等都有这个问题,一旦物体需要进行alpha混合则这些算法就很难起到作用)。所有的不透明物体都可以被记录在深度缓冲区当中,但是需要进行alpha混合的点是不能够记录在深度缓存区当中的。因此,我们需要在着色器中为半透明的物体建立一张阴影法线贴图索引。

4.直接光照下的阴影贴图

“孤岛危机I”当中,我们仅仅使用了很少的阴影投射对象,并且每个被投射的对象都有一个独立的shadowmap。当阴影投射的对象变得更多的时候,我们认为应当将这些阴影数据统一到一个shadowmap当中。在光照方向使用一个简单的平行投影就可以能够轻易的得到一个shadow

Map,但是这样会使得靠近观察者的阴影贴图分辨率非常的低,出现块状的阴影。如果我们更改参数,例如生成一个透视投影矩阵将靠近观察者的阴影贴图分辨率提升。但这也会出现一些问题。我们还尝试了梯形shadow map(TSM)([MT04])以及透视shadowmap(PSM)([SD02])。

我们在使用级联shadowmap(CSM)的时候取得了较大的成功,这种算法通过对视野所在区域进行多次投影得到了许多张不同范围的相同分辨率的shadowmap。每一个投影的影像像素范围都包含于他前面的那个(pancy:更大的)投影所在的世界范围的像素区域内。这项技术得到了较好的结果,但是同时也浪费了一些纹理存储空间,主要是由于这些投影结果只是粗略的包括到了观察者前面的一些区域。为了找到合适的可划分的视截体(随着阴影区域大小的必须距离的减少而减少),每一个shadowmap都需要包含一个划分,划分越远则视截体就可以包含越大的世界空间,当一个shadowmap视截体恰好完全的包含一个划分的时候,比他更小的shadowmap就应该被舍弃掉。如果使用以往的技术,我们已经知道当摄像机进行旋转和平移的时候会出现阴影混淆。而在使用PSM和TSM的时候我们也没能解决这个问题,但是我们使用CSM加上我们的一些改进则解决了这个问题。我们只是更改了每个shadowmap像素的投影方式就得到了一个非常清晰的阴影结果。

5.延迟阴影模板的建立

初始化阴影模板的创建需要渲染所有的可见几何体,这将会使用到更多的draw call。我们使用延迟技术将阴影模板的额建立从几何体渲染中分离了出来。我们先根据我们用提前z缓冲渲染的深度纹理进行一次全屏渲染pass,这次渲染使用一个简单的像素着色器(根据深度数据获取shadow map查询结果)。并且此次渲染不需要各个点在世界空间的坐标。正如前面所说的,我们使用了多张shadow map,这使得我们用于创建阴影掩码的着色器需要定义所有的像素点,以确定每个像素的阴影映射到了正确的纹理。为每一个纹理添加索引可以使用directx10的纹理数组功能或者在一个大的纹理资源中进行偏移寻址。通过使用模板缓冲区,我们能够单独处理各个划分并且简化了像素着色器。修改后的技术运行速度变得更快了,因为像素着色器不需要再做复杂的操作。并且算法还屏蔽了那些不需要计算阴影的离视点较远的场景。

6.展开点光源的shadow map

通常点光源的shadow map都需要一张cube map贴图来进行深度索引。但是硬件PCF优化并不能应用于cube map类型的纹理上面,因为这种纹理很难控制和管理其所占的存储空间。我们将cube map通过在模板缓存上的6次采样展开成6张阴影纹理贴图,这与我们在CSM中所做的操作很相似。这样我们就将点光源类型的阴影问题转换成了聚光灯类型的阴影问题。这使得代码更加的统一和易于维护并且减少了shader的组合。

7.方差shadow map算法(VSM)

对于地形,我们最初希望先提前算好纹理的起始和结束角度,并且还试图实时的更新一张遮蔽映射纹理的增量。然而地形上的一些几何体总是出现一些问题。对于那些大的物体,在不同的地形中需要适应不同的阴影。我们尝试使用我们的法线阴影贴图技术,这项技术统一了阴影外观,但是却导致了阴影的柔和度不足。我们还尝试使用更大范围的简单随机纹理进行索引,但是这使得噪声变得更加严重。在这里我们尝试使用方差shadowmap技术[DL06],而这项技术的最终效果非常的不错。当多个阴影贴图互相遮盖的时候方差阴影贴图的缺点就很明显了。但是对于地形模型来说这种情况是很少发生的。

 

 技术分享

13:使用VSM渲染场景的一个样例。上图:未使用方差阴影贴图(注意有硬法线阴影)。下图:使用了方差阴影贴图(注意两种阴影的结合)。

间接光照

1.3D Transport Sampler

在第一部分我们已经计划设计一个叫做“3D transport sampler”的工具,这个工具可以将全局的光照数据分配到多个机器上(考虑到性能原因)。

光子映射([jensen01])是一种被大家所认可的计算全局光照的不错的方法。我们决定采用这种方法模拟全局光照,因为它可以简便的统一到系统中,并且快速的得到较好的效果。

 技术分享

14:一个光源的实时环境光。

光子映射最先被应用于创建一个简单的光照映射。这项技术在我们过去的光线映射中实现的很简单,并且仅仅将相邻的三角形连接起来并只使用了一个简单的平面方程。这导致我们填充到多重纹理中的结果出现了很多2D的小块。同时当我们将算法用于更为精细的模型的时候纹理的使用效率开始显得很低,并且在纹理的边界拓展的时候出现了很多细小的间断(pancy:wrap,纹理拓展,一般来说纹理采样UV的范围是[0,1],如果模型的UV超过了这个值就需要进行纹理拓展,具体的拓展方式根据应用而定,常见的有重复寻址和最外边寻址等)。因此我们更改了纹理的拓展方式,使用模型的纹理拓展UV作为基础并且只在我们需要的地方做拓展定义。这样的话负责美工的艺术家就可以对精细的模型的技术细节做更多且更合适的操控和修缮。我们本想将结果存储在Dot3lightmaps(前面已经做过介绍)但是我们希望尝试用更好的方式来提升渲染质量。这个方法的主要思路是存储四个方向的光对表面的贡献。类似的技术曾经被用于“半条命II”(pancy:CS吧??)但是他们只存储了三个方向的光。显然更多的数据将会带来更好的渲染效果。这些数据运行我们进行高质量的逐像素渲染,并且如果不追究细节的话可以和实时阴影较好的结合。但是,由于巨大的存储量和缓慢的运算速度,我们最终还是放弃了这种方式。其实我们最初的想法只是存储每个像素的光照贴图系数以及其余的每个顶点的信息。将这些信息结合存储顶点连接关系的图形数据结构,我们好似有可能实现动态间接光照的。低频的光照分量可以存储在各个顶点结构中,高频的分量例如锋利的角落等可以存储在屏幕空间像素当(pancy:顶点结构数量与几何体有关,屏幕空间像素数量与光栅化有关,看开头还以为cryengine想挑战人类极限加入光子映射......结果竟然是放弃了...弃了.....了)。由于开发时间是很珍贵的,所以我们最终还是放弃了这个想法。

2.实时环境光映射(RAM)

作为替代,我们选择了一个更简单的解决方案,只需要为每个像素存储一个环境光遮挡值标量。

环境光遮蔽值([ZIK98,Landis02])可以根据各个方向的发射光线来进行计算。这些光线有些是光子映射中没有使用到的。我们在着色器中使用这些必要的信息进行重建:存储了遮蔽值的像素,与表面方向相关的光源位置,光照颜色及表面法向量。我们最终得到了一个粗略的近似环境光,但是人眼对环境光并不是很敏感,所以最终效果还是不错的。为了能支持法线贴图技术,我们需要对光照方向进行平均化,因为我们无法获得能较好的和法线贴图表面配合的光照方向。即便使用这种方法,法线贴图依然能够被察觉到,而着色效果也很大的依赖于光照角度。因此我们让环境光的亮度,颜色以及衰减系数都是可以调控的以便设计人员设计出更好的最终外观。当考虑到入口效果的时候,这项技术可以进行扩展以使得太阳光可以混合多个其他光线。对于更大的室外环境,为每个表面计算一个RAM是不可行的,因此我们决定使用其他的技术。

3.屏幕空间环境光遮蔽(SSAO)

我们的一个很有创意的程序员想出了一个不错的方法。这种方法使用我们之前已经计算出来的z缓冲数据来计算出一种环境光遮蔽。(pancy:我就想知道那个有创意的程序员叫啥名字......一个不小心成了SSAO之父啊!一个不小心推动了实时渲染的改革.....)这个方法非常的诱人,因为所有的不透明对象都可以在没有特殊处理的情况下得到环境光遮蔽,并且不需要额外的内存开销。同时,很多渲染部分的的复杂处理也都可以顺手移除了。虽然我们现有的解决方案已经工作的不错了,但是我们还是希望能够计算出所有种类的动态环境光。这种方法基于屏幕像素与采样像素进行简单的深度比较在物体的周围得到一个由遮蔽因子决定的轮廓。而这种环境光遮蔽的效果仅仅决定于这个点对周围光线的的接收程度。经过多次的迭代和优化,我们得到了一种意想不到的效果,我们将其称为“屏幕空间环境光遮蔽”(SSAO)。我们通过一次对全屏幕像素执行的pass来计算环境光遮蔽效果。我们还尝试将这种效果同时应用于环境光,漫反射和镜面反射,但是最终发现他只是对环境光模拟效果最好。最大的原因可能是这种算法使得渲染的真实化受到了影响,这也是我们未来的优化目标。

为了减少采样次数我们将采样点跟改为像素附近点的采样,初始的样本分布于一个以源点为中心的球体表面。然后通过一个随机的3D平面将这些采样点反射到随机的采样位置。

                    n:来自于纹理的归一化的随机像素向量。

                    i:  来自于球面的随机采样点

             Float3 reflect(float3 i,float3 n){return i-2*dot(i,n)*n}

 

反射是很容易计算的,并且将随机平面法向量存储在纹理中是非常足够的。

 技术分享

15:使用屏幕空间环境光遮蔽只计算环境光得到的效果(注意在远距离处,遮蔽使得颜色非常的暗)

 

 

16:场景A使用特殊材质使ssao可视化的一个样例(左:使用ssao,右:未使用ssao)

 

17:场景B使用特殊材质使ssao可视化的一个样例(左:使用ssao,右:未使用ssao)

 

18:场景A使用特殊材质使ssao可视化的一个样例(左:使用ssao,右:未使用ssao)

多细节层次(LOD)

1.现状

当渲染的复杂度不容易控制的时候,层次细节技术(LOD)是非常重要的,很多游戏通常使用雾化效果对视野做了很大的限制,甚至有时候依靠层次设计来强行遮蔽掉远处的信息。这也就是为什么大多数游戏都是以室内环境为主导的,但是在“孤岛危机I”中,我们希望能够展示非常远处的风景以及许多细节,同时不限制玩家的视角和运动位置。因此,我们保持了“孤岛危机”中的视角范围,但是我们为模型增加了不同层次的高质量细节描述。质量的提升意味着我们需要使用更为复杂的着色器,更为高质量的纹理。全新的纹理类型(例如地表纹理)以及更多的网格点。因为我们还希望使用z缓冲前置技术以及实时阴影效果,所以我们需要对每个模型对象付出更多的代价。而过多的drawcall使得CPU负担增加,不过这在Directx10上有所改善。因此在“孤岛危机”中,我们可以很轻易的在美工创作的不同细节程度的模型中进行切换。当然,我们还为植被添加了一些欺骗的技术以改善他们在游戏中的运行效率(pancy:估计是billboard或者cross billboard之类的公告板技术 )但是这不属于本章的讨论范围。

“孤岛危机”中,我们打算使用一个基于移动顶点的平滑的LOD过度。但是这种技术经常对于模型创建带来很多限制。而如果没有这种限制的话模型往往能够快速而高效的建立出来。特别是那些需要alpha测试或者alpha混合的植被模型。这使得有时候我们的模型来不及建立LOD转换而不得不在显示demo的时候直接取消低LOD等级的部分。用于演示demo的机器拥有非常高的硬件配置因此低等级的LOD并不能增强运算速度。而低等级的LOD所引用的范围通常在屏幕上只占很少的一部分,所以总的像素消耗是很少的。使用大量的LOD还有可能适得其反,因为这项技术并不容易让不同层级的对象完美融合,并且我们还得消耗更多的draw call。

2.融合技术

我们的一个程序员最终想到了一个基于在z缓冲前置事前进行模型融合的方式来柔化LOD的转换。而在我们之后的额渲染过程中只需要打开z缓冲前置。当然这并不是一个完全正确的方法因为物体的表面有可能会拥有相同的深度值,这样使用add类型的alpha混合(pancy:add型混合 finalpixel = sourcepixel + destpixel)使得这些点获得了两倍的亮度。然而由于每个物体第一次渲染的目标帧缓冲区不允许混合,所以这种情况只有在之后的pass才有可能发生。不过我们将所有的光照合并到了一个pass当中,因此这种情况发生的概率就非常小了。融合后的纹理属于屏幕空间的一个投影,然后我们随机从纹理中采集一个值与每个物体的变换值进行融合,并在之后使用简单的alpha测试来排除不符合要求的点。我们在最新的图形硬件卡上采用了较为新颖的alpha2coverage(A2C)技术(pancy:alphatocoverage技术,通常alpha测试因为简单地根据alpha排除不透明点使得边界锯齿严重,为了达到类似于alpha混合的效果,DIrectx10使用了一种叫A2C的方法来消除一些alpha测试留下的锯齿)以及全屏抗锯齿技术(FSAA)在亚像素级别上进行优化。即便不使用FSAA技术,如果我们使用到我们的边缘模糊后处理效果,融合的瑕疵也不宜被察觉到。最初我们只是根据模型与视点的距离来进行状态的过度。当时处于过渡期的模型的渲染速度和质量都变得很差,因此我们决定在过渡期隐藏这些模型。这也就是为什么我们为模型过度添加了一小段代码以让其在定义的一段时间内完成。我们不仅仅对变换的3D对象使用融合技术,还将这项技术用于隐藏远处的模型以及隐藏过渡期间的模型已达到欺骗视觉的效果。

3.水面的LOD技术

海面或者大范围的水面通常拥有特殊的属性,因此可以使用特殊的渲染算法进行渲染。最初我们在“孤岛危机”中实现的水面是一个随着玩家运动的简单网格,由像素着色器,反射效果以及透明度决定了水面的视觉效果。然而,我们希望拥有真实的3D波浪,当然不是基于物理模拟,而是一种廉价的解决方案。我们尝试通过使用基于FFT(pancy:快速傅里叶变换)的水波仿真([Jensen01a], [Tessendorf04]).要想获得3D的波浪就必须要进行必要的顶点操作,而我们以往使用的网格模型显然是不能够做这样的操作的。

4.立方水域

前面提到的FFT仅仅适能够输出海面的较小的一部分,因此我们必须将表面渲染很多次才能获得想要的范围。不同的细节层次所使用的索引缓冲区不同,但是他们共享一个由FFT生成的顶点缓冲区(pancy:顶点缓冲区决定组成几何体的多边形的顶点位置,索引缓冲区决定了多边形的组织方式。)我们虽然共享了所有LOD的顶点缓冲区以节省内存,但是为了更好地渲染质量(pancy:也就是LOD中被认为不重要的几何体需要降低渲染质量)我们需要更好的向下采样方式。为了减少随距离而产生的混淆现象以及限制低质量多边形的外观,对于近处的点,我们淡化了其对远处顶点的扰动。并且大大限制了其对周围近处顶点的扰动(pancy:大概是很大程度上简化了液体之间的受力方式)。这种方法确实起到了作用但是很多美工建议我们还是再找一些更好的方法。

5.屏幕空间曲面细分

我们决定使用一些暴力的方法,这种方法很简单,但是很好的解决了问题。我们使用一个提前计算好的屏幕空间曲面细分四边形并且将所有的水面顶点投影到这张四边形上。这项操作必须严格保证z缓冲区的正确性,甚至我们还要裁剪掉所有地平面上面的顶点所产生的像素。为了能够使用FFT波浪模拟数据来修改顶点的位置,我们需要建立一张顶点纹理索引,因为这项技术并不能在硬件上实现(pancy:硬件曲面细分始于directx11,当时虽然有使用曲面细分模拟水面的算法但是只能通过一些别的手段实现这项功能)

                       技术分享

                        2:屏幕空间曲面细分产生的波浪

线框中可以注意到的垂直线条是由于我们为了更好的日升顶点缓冲区性能所做的顶点分层。这个结果看上去让我们觉得最终成功的希望很大,但是屏幕边界上的顶点总是在远离边界的位置,这是一个很严重的问题。当然,为缓冲区扩容,以包括哪些超出边界的顶点可以解决这个问题。不过衰减顶点的扰动的方法更适合,因为不仅对屏幕边界影响并不是很明显,并且还能最小化的增加额外成本。

 技术分享

3:左:不做衰减顶点扰动的屏幕空间曲面细分(注意左边界的部分没有被包括到水面)。右:衰减顶点扰动的屏幕空间曲面细分。

为了更好的提高性能,我们减少了顶点的细分程度,而即便我们使用比之前少很多的顶点,工程的质量仍然是可接受的。取景角度的倾斜将使得渲染效果大大降低,这不是我们期望的结果。主要原因是边缘衰减主要依赖于水面方向的摄像机,而不是真实的物理模拟。因此我们不得不减少波动的幅度以解决这个问题。

6.摄像机对齐

剩余的一些历史遗留的锯齿混淆问题以及物理运动学的问题困扰着我们的shader程序员。然后他花了一些时间找到了一个如下的解决方案:这种新的方法更之前一样使用了一个静态的网格。但是这个网格的投影从之前的单一角度转换成了简单的上下投影。整个网格由摄像机来进行移动,我们通过调整摄像机的偏移量以使得摄像机面对方向所获的顶点数量最大化。要渲染地平线以上的顶点,我们就需要对网格的边缘进行显著的扩展。而这些顶点的曲面细分不再很关键因为对于这种远距离定点,其受扰动的系数几乎可以视为0。

      技术分享

204:摄像机对齐后的水面网格的线框:左:上下投影的摄像机对齐空间,右:从观察者角度观看的相机空间。

这种做法得到的效果要优于屏幕空间的做法,特别是在相机做微小的运动的时候更加的明显。除了随距离的衰减,水波现在是与观察者位置无关的。因此现在使用CPU模拟FFT物理运动是可行的。

 技术分享

21:左:摄像机对齐的结果。右:用于比较的屏幕空间曲面细分

总结

通过这次曲折的探究,我们不仅找到了我们的下一代引擎的发展方向,还从中学到了很多的东西。为了找到,验证以及比较不同的解决方案,学习的过程是必不可少的。在过去的说法中,这项工作可以被归类于研究工作。我们认为我们选取他人的研究成果最大的根据是质量,生产时间,性能以及可扩展性。“孤岛危机II”,我们的新一代的游戏,是一个巨大的工程,为了掌控这项工程,时间是非常重要的。一个解决方案的性能与硬件息息相关(如CPU,GPU,内存),因此对于不同的平台我们都可能要重新考虑我们所使用的算法。目前的引擎对于拥有多个核心的CPU以及较为快速的支持Directx9和Directx10的显卡来说优化是不错的。在早期使用z测试前置得到的深度信息也是很有用的,很多功能现在都依赖于这个数据。如今,更为规范的延迟渲染像素数据也包含了更多的像素信息,比如漫反射颜色,法线,以及一些特殊的材质。对于渲染外星人的室内场景,延迟渲染可能是最好的解决方案,但是其他的环境则不能从中受益,因为只有一个光源的情况下延迟渲染并不能很好的发挥其优势。

致谢

此次演示文稿是很多程序员,美工和设计师们共同努力的结果。在这里我们要特别感谢Vladimir Kajalin, Andrey Khonich,Tiago Sousa, Carsten Wenzel 以及Nick Kasyan. 我们已经成为了NVIDA的合作伙伴,我们获得了他们的现场帮助而包括而不仅限于G80 Directx9以及Directx10方面的问题。因此特别感谢NVIDA的工程师Miguel Sainz, Yury Uralsky 以及 Philip Gerasimov。同时为业界的领袖企业Microsoft,AMD,Intel,NVIDA以及其余的支持过我们工作的公司致以感谢。同时为帮助我完成这篇论文的Natalya Tatarchuk 以及Tim Parlett致以感谢。

引用

[ATI04] ATI 2004, Radeon X800 3DcTM Whitepaper http://ati.de/products/radeonx800/3DcWhitePaper.pdf  

[DL06] DONNELLY W. AND LAURITZEN A. 2006. Variance shadow maps. In Proceedings of the 2006 ACM SIGGRAPH Symposium on Interactive 3D graphics and games, pp. 161-165. Redwood City, CA  

[ISIDORO06] ISIDORO J. 2006. Shadow Mapping: GPU-based Tips and Techniques. GDC presentation. http://ati.amd.com/developer/gdc/2006/Isidoro-ShadowMapping.pdf   

[JENSEN01]  JENSEN, H. W. 2001. Realistic image synthesis using photon mapping, A. K. Peters, Ltd., Natick, MA.   

[JENSEN01a] JENSEN, L. 2001, Deep-Water Animation and Rendering, Gamasutra article http://www.gamasutra.com/gdce/2001/jensen/jensen_pfv.htm  

[LANDIS02] LANDIS, H., 2002. RenderMan in Production, ACM SIGGRAPH 2002 Course 16.  

[MICROSOFT07] MICROSOFT DIRECTX SDK. April 2007.   http://www.microsoft.com/downloads/details.aspx?FamilyID=86cf7fa2-e953-475cabde-f016e4f7b61a&DisplayLang=en   

[MT04] MARTIN, T. AND TAN, T.-S. 2004. Anti-aliasing and continuity with trapezoidal shadow maps. In proceedings of Eurographics Symposium on Rendering 2004, pp. 153–160, 2004.  

[MCTAGGART04] MCTAGGART, G. 2004. Half-Life 2 Shading, GDC Direct3D Tutorial  http://www2.ati.com/developer/gdc/D3DTutorial10_Half-Life2_Shading.pdf   

[MITTRING04] MITTRING, M. 2004. Method and Computer Program Product for Lighting a Computer Graphics Image and a Computer. US Patent 2004/0155879 A1, August 12, 2004.   

[SD02] STAMMINGER, M. AND DRETTAKIS, G. 2002. Perspective shadow maps. In SIGGRAPH 2002 Conference Proceedings, volume 21, 3, pages 557–562, July 2002  

[TESSENDORF04] TESSENDORF, J. 2004. Simulating Ocean Surfaces. Part of ACM SIGGRAPH 2004 Course 32, The Elements of Nature: Interactive and Realistic Techniques, Los Angeles, CA   

[URALSKY05] URALSKY, Y. 2005. Efficient Soft-Edged Shadows Using Pixel Shader Branching. In GPU Gems 2, M. Pharr, Ed., Addison-Wesley, pp. 269 – 282.  

[WENZEL05] WENZEL C. 2005. Far Cry and DirectX. GDC presentation, San Francisco, CA  http://ati.amd.com/developer/gdc/D3DTutorial08_FarCryAndDX9.pdf  

Advanced Real-Time Rendering in 3D Graphics and Games Course – SIGGRAPH 2007

121

[WENZEL06] WENZEL, C. 2006. Real-time Atmospheric Effects in Games. Course 26: Advanced Real-Time Rendering in 3D Graphics and Games. Siggraph, Boston, MA. August 2006  http://ati.amd.com/developer/techreports/2006/SIGGRAPH2006/Course_26_SIGGR APH_2006.pdf  

[WENZEL07] WENZEL C. 2007. Real-time Atmospheric Effects in Games Revisited. Conference Session. GDC 2007. March 5-9, 2007, San Francisco, CA. http://ati.amd.com/developer/gdc/2007/D3DTutorial_Crytek.pdf  

[ZIK98] ZHUKOV, S., IONES, A., AND KRONIN, G. 1998. An ambient light illumination model. In Rendering Techniques ’98 (Proceedings of the Eurographics Workshop on Rendering), pp. 45–55.

 

探寻次时代渲染 - CryEngine2