揭开游戏引擎的秘密
硬件周刊
究竟是3D游戏的发展带动显卡的进步,还是显卡的发展带动3D游戏的革新,这个问题恐怕谁也说不清楚。就像显卡需要一款强劲的GPU引擎来带动显示性能一样,游戏同样需要一款“游戏引擎”来演绎逼真的场景。可以说,今天几乎每一款3D游戏,其视觉特效都是建立在3D引擎的基础之上,但你了解游戏中所有这一切的幕后技术吗?
游戏引擎系统内部分为图形、输入、声音、配置等几个子系统。今天我们主要介绍游戏引擎的图形部分,让大家从游戏中了解一下与显卡相关的技术。
一、骨骼蒙皮动画
目前游戏所采用的动画系统可以分为两种:一种是骨骼蒙皮动画系统,另一种是模型动画系统。前者用内置的骨骼带动物体产生运动,比较常见,后者则是在模型的基础上直接进行变形。下面我们主要谈谈骨骼蒙皮动画系统。
1.骨骼蒙皮原理
游戏中的骨骼蒙皮动画可以看作是关节动画和单一网格模型动画的结合。在骨骼蒙皮动画中,一个角色由作为皮肤的单一网格模型和按照一定层次组织起来的骨骼组成。相邻的骨骼通过关节相连,并且可以做相对的运动,同时通过改变相邻骨骼间的夹角、位移,组成角色的骨骼就可以做出不同的动作,实现不同的动画效果。皮肤则作为一个网格蒙在骨骼之上,确定角色的外观。这里的皮肤不是固定不变的刚性网格,而是可以在骨骼影响下变化的一个可变形网格,组成皮肤的每一个顶点都会受到一个或者多个骨骼的影响。影响一个顶点的最大骨骼数一般取决于模型的设计和目标硬件平台的限制。比如,对于一个典型的人体骨架,一般只有在关节附近的顶点才会受到相邻几块骨骼的影响,而同时影响某一顶点的骨骼数,也不会超过4块。随着3D硬件性能的提高,越来越多的相关计算可以通过硬件来完成,骨骼蒙皮动画已经成为各类实时动画应用中使用最广泛的动画技术。
骨骼蒙皮动画的计算过程中,一个顶点受到许多骨骼影响的时候,求一个顶点的新位置会牵涉到大量的矩阵与乘法运算。比如一个顶点受到16根骨骼的影响,那么就要进行16次矩阵与向量相乘的运算,然后乘以影响位移需要的16次浮点数,最后还需要与15次浮点数相加来求得最终的顶点位置。对于一个复杂的角色模型,比如精细的人体模型,上万的顶点数同时受几十根骨骼影响并不少见。骨骼蒙皮动画过大的计算量一度限制了它的广泛应用。幸运的是,随着3D硬件技术加速发展,特别是硬件支持的 Vertex Shader(顶点着色器)的出现,这一情况得到了很大的改观。
2.顶点着色器
要使用Vertex Shader 来实现骨骼蒙皮动画的计算,首先要把每一根骨骼的变换矩阵写入3D显卡的常量寄存器中。由于每一根骨骼对应的变换矩阵有4×4 共16个浮点数,因此每一骨骼需要4个常量寄存器,事实上可以只存储前3行元素,这样就只需要3个常量寄存器。比如,在一款支持DX8.1的游戏引擎中,一个Shader中可以访问的最大骨骼数不会超过 96/3 = 32块(注:DX8.1的常量寄存器为96个,而最新的DX9.0的常量寄存器增加到了256个,一个Shader中可以访问的最大骨骼数将达到85块,而虚幻竞技场2004中每个标准角色都有100~200块骨头)。
因此对于一个使用了大量骨骼的角色,就需要分别渲染使用了不超过32块的同一骨骼集的不同部分。然后交给Vertex Shader程序处理的每一个顶点还需要包括使用哪几根骨骼的信息(也就是指出使用哪一个常量寄存器中保存的变换矩阵),同时影响一个顶点的骨骼数同样受到硬件的限制。Vertex Shader程序在收到一个顶点后,会按照该顶点骨骼索引利用相应的寄存器一一定位相应的骨骼变换矩阵,然后对顶点位置进行变换,再乘以相应骨骼的影响权重,最后把求得的变换结果累加,这样就得到了最终顶点的新位置。
最新的游戏中人物的骨骼蒙皮越来越复杂,比如最新3DMark05的“Vertex Shader Test”项目中,每条海怪就需要超过一百万个的顶点来建模,因此对显卡的顶点着色器及三角形生成能力的要求较高。在这方面, ATi的产品比同级别的NVIDIA显卡略有优势。ATi最新一代图形显示芯片R420的几何引擎具备6条平行的顶点处理管线,在顶点产生率的数据(单位是vertices/s)上,X800 XT为7.8亿,X800 Pro为7.12亿。虽然NV40的顶点着色单元符合微软DirectX 9.0c的规格,NV40可以在MIMD的设计上拥有6个顶点单元,但NV40由于采用3×2设计,每秒只能达到6亿个多边形的三角形转换率的水准,理论上比ATi同级别的产品稍逊色一些。
二、光影效果
光影效果,即场景中的光源对处于其中的人和物的影响方式。游戏的光影效果完全是由引擎控制的,折射、反射等基本的光学原理以及动态光源、彩色光源等高级效果都是通过引擎的不同编程技术实现。随着游戏场景的效果复杂性,目前光影效果实现往往成为了游戏引擎的一个重点,但不同游戏引擎的侧重面不一样。目前最新游戏引擎中对光照的处理都是顶点光照,而顶点光照又分静态光照和动态光照。
1.静态光照
其中静态光照又称没有即时性的光影效果。引擎在顶点处理阶段采用一种叫做“光照贴图”(light map)的特殊纹理贴图,它实现编码表面是如何被光照的(注:意思是“它定义表面是如何被光照的”)。光照是预先在聚光灯的光照贴图里计算好的,因此光照不需要在运行时被计算,这节省了处理时间。当然,只有静态对象和静态灯光的光照可以被预先计算。因为光照贴图是预先计算好的,游戏开发者能够使用更多更加精确的和复杂的光照模型。光照贴图的最大优点是对GPU资源占用率并不是很高,但缺点是渲染效果不够逼真。为此游戏开发者在光照贴图的基础上推出了一种Normal Map(又称“法线贴图”,法线的概念大家最先接触于初中物理的光反射部分,大意就是从一个面上的一点射出并垂直于这个面的一条射线)。
Normal Map就是记录了一个需要进行光影变换的贴图上的各个点的凹凸情况的贴图,显示芯片根据这个贴图的内容,来实时生成新的光影变化贴图,从而实现立体效果。Normal Map可以在少量多边形的模型下,增加该对象的精细度。它最大的优点是,光源无论在哪一个角度上看起来都正确无误。但它仍无法摆脱传统光照贴图的局限性,而且Normal Map每次工作只会累积一个光源的效果,对于多重漫反射光需要在多通道中进行合成,在对Light Map进行处理的时候也只能处理一个颜色值。幸好一些游戏开发者在其游戏引擎中引入了更先进的动态光照。
2.动态光照
动态光照又称实时光照渲染,它主要由引擎根据场景实时情况来渲染。现实中,当光线从一个光源发出,它在到达观察者的眼睛之前,要经过成千上万的对象的反射,光的方向和光源往往具有不确定性。因此如果要在游戏中达到逼真的渲染效果,光照效果就往往需要随着环境的改变而改变,而正是动态光照技术的出现将游戏引入了真正的光照渲染。以DOOM3引擎为例,这个引擎为了加强游戏当中的光照效果,引入了Ray-tracing(光线追踪)、Radiosity(混合光源)两项动态光照渲染技术。其中光线追踪法可以看成是物体和物体之间光线的交互作用,利用反射光和折射光的特性来追踪光线的来源,同时把光源照明所传递的能量及物体间接传来的能量纳入亮度的考虑之中,因此光线追踪法可以完美地表现出透明材质与反射情形良好的物体特性。而混合光源技术也类似光线跟踪的特效,它通过制定在场景中光线的来源并且根据物体的位置和反射情况来计算从观察者到光源的整个路径上的光影效果。在这条线路上,光线受到不同物体的相互影响,如:反射、吸收、折射等情况都被计算在内。不过这两种光照渲染技术,对GPU资源占用率较高。
3.阴影技术
光(Light)与影(Shadow)从来是如同一对相辅相成的搭档,但是我们往往忽略了阴影的作用。其实阴影是游戏引擎的渲染器的一个重要功能。游戏的阴影实现方法有很多种,目前比较流行的主要是Shadow Mapping(阴影映射),这种效果实现起来相对简单,可以发挥现在GPU可编程流水线的能力。但是由于先天不足,Shadow Mapping在处理动态光源、物体时资源消耗过大,经常用于静态阴影场景中,所以如果要运算动态场景的话就显得力不从心了。
因此游戏开发者引入了Shadow Volume(阴影体积)的动态阴影技术,它允许程序员约束光源使物体的阴影在一个特定的范围内,计算此区域内光源对物体产生的效果,预先排除不需要进行计算的区域,通过将注意力集中到那些光源效果最为显著的区域,使阴影生成的全过程将大大加快。而DOOM3之所以能提供如此逼真的阴影效果正是依靠此技术。比如在以往的游戏中,虽然可以实现阴影效果,但是那种阴影效果基本都是随着单独物体的移动而随之变化,而在DOOM3中,我们可以领略到多个物体以及光源同时移动而产生的不同阴影效果,这种效果基本上接近于现实世界中的表现。值得一提的是,NVIDIA的NV35、NV40所支持的UltraShadow技术可以看成Shadow Volume技术的GPU版本。正是凭借UltraShadow技术,NV35、NV40一次就可以完成通常需要两次渲染才能实现的阴影效果,而NV40的UltraShadow Ⅱ可以让游戏开发人员定义场景中预期的阴影覆盖边界,从而大幅度提高模板Shadow Volume的渲染效能。
三、渲染器
游戏引擎中的渲染器是一个很重要的元素,可以将它看成是整个游戏引擎的灵魂部分,往往也是厂商、玩家最为注重的。渲染器的主要功能就是采集画面几何体和材质的数据,通过一系列繁杂的过程,生成一个三维的图像。当3D模型制作完毕之后,美工会按照不同面把材质贴图赋予模型,这相当于为骨骼蒙上皮肤,最后再通过渲染器把模型、动画、光影、特效等所有效果实时计算出来并展示在屏幕上。渲染器在引擎的所有部件当中是最复杂的,它的强大与否直接决定着最终的输出质量。
目前大多数游戏引擎的渲染器采用Microsoft DirectX的 API,主流游戏一般支持DirectX8.1,而最新的游戏中,已经对DirectX9的Shader Model 2.0b甚至是Shader Model 3.0提供了支持来增强其硬件兼容性以及对未来特效的支持。目前在支持DX9的游戏引擎中,所有的DX 9 Shader均在HLSI (high level shader language,高级渲染语言,对HLSI的解释可参看《电脑报》第42期的“技术空间”)下完成,对代码的运用上只需简单地插入片段,省却了在底层使用汇编语言重新编译的麻烦,增加了游戏引擎的弹性。而对于玩家,Shader能达到依靠驱动程序实现更丰富弹性的特效。
渲染器设计得好坏,主要是将渲染器组件制作得基化(Based)与干净(Clean)。其中每一个部分都需要一个接口来方便地实现改变各种设置以及其他可能与系统相关的属性配置。一个不成功的渲染器的最大缺陷便是“特性臃肿”──如果将新特色置入引擎中,而又不进行相应的代码优化的话,那么在渲染过程中往往会导致大量的冗余代码,大大降低渲染效率。你也许最终便能发现,实现所有这些所需要的特殊效果,可能只占了15%左右的代码量甚至更少。
结语
自从真正的3D显卡出现后,3D显卡与3D游戏的关系就变得微妙起来,它们互相推动,每当有新的3D游戏出现,必将带动一轮更换显卡的热潮;每当有新的显卡规格出台,也将推动发挥显卡新功能的3D游戏的出现。可以说,游戏已经成为了游戏爱好者衡量系统性能的标杆,而这种趋势仍将继续持续下去。


