原文:D3DTutorial10_Half-Life2_Shading.pdf
m17 转载与编译
关于什么是Engine(引擎)?
在Half-Life 完成之后不久,Valve开始筹备他们的下一个主打游戏--Half-Life 2。在商讨游戏引擎的采用问题上,开发小组明白到原版游戏所采用的改良Quake 1引擎对于Half-Life 2来说显得过于破旧,而且在很多的方面都不符合这一代游戏发展的要求。于是,vlave的开发小组决定从美工设计以及游戏代码开始,设计出一个全新的游戏框架,并在其中加入了一套来自havok的定制物理引擎。
对于一个游戏来说,“引擎”就是一个系统,就像是一辆汽车的发动机一样,他能输入来自加速器的动能,并输出到轮子的转动。软件(在这里为游戏)的引擎实现的东西和汽车的发动机一样,输入来自框架(某些程序或者文件的片段),然后输出程序员们想要的结果。再次拿汽车的发动机为例,一个软件的引擎不能自行运作,他必须依靠另外一个系统,就好像,你只能开着“一台汽车”而非“一台发动机”去上班。在Source中,一个纯粹的引擎只能是一堆代码,完全不具有可玩性。所以不难对引擎下这样的定义:引擎就是一套让游戏元素发生互动关系并将其编译成可玩程序的代码或程式,依靠框架进行操作。
Source引擎总览
Source并不是一套简单的3D引擎,也可以是说,他并非只是一套渲染器。Source引擎包含了很多不同的模组,程序员可以在引擎的程序包中方便地取出以及添加进其他的元素。
在这篇文章里面,我将会为大家展示这些模组是什么回事并且对游戏产生怎样的影响。在下面将要陈述的问题主要讲解在Source引擎中一些令人惊奇的模组是怎样对整个游戏的画面以及游戏效果产生影响,而不是去解释Source引擎的代码怎样去运作。对于此,可能大家会觉得比较枯燥,毕竟,这些在程序实现上的问题针对的是对游戏有一定研究的玩家。我们并没有打算深入到Source的程序代码进行研究,因为这些已经不属于我们一般老百姓可以研究的范畴了。在这里必须要给读者澄清一下,由于目前Source引擎的非公开性,我们并不能准确地将Source引擎中每一个模组的特性都准确地表示出来,如果你一定要深入研究的话,请参考Half-Life 2发布之后的 SDK 参考文档以及Valve以后的白皮书。本文的章节细分以笔者对Source引擎的了解为依据。请根据实际情况印证并参考其他专著以及文献。
- 3D 引擎
- 渲染器
- Pixel 、vertex shaders
- 光影效果
- HDR (High Dynamic Range)
- 动画以及角色面部表情
- 几何构成
- VGUI游戏界面
- 物理引擎,基于Havok 定制的物理引擎
- 刚体的动力学模型以及关节约束机制
- 弹性机构、绳索机构、布纹处理、车辆系统
- 水以及火光
- 粒子系统
- 怪物/NPC/程序 上的物理学系统
- 材质系统
- AI 系统
在这里,我尚且用3D engine来描述造Source引擎中,生成引擎输出图像及其几何体的模组。
渲染器 这部分最能体现显卡的功力,也是玩家最为注重的一个重点。渲染器的作用主要主要功能就是采集画面几何体和材质的数据,通过一系列繁杂的过程,生成一个三维的图像。Valve并没有重新创造Source引擎的渲染器而采用了Microsoft DirectX 9.0 的 API,并借助Half-Life SL高阶编程语言编写引擎,在很大程度上节省了宝贵的时间,这归功于 DirectX9良好的硬件兼容性以及先进的代码设计流程。原有的Half-Life 1引擎被设计成支持 OpenGL and Direct3D的双模式,但正如各位所见,这个引擎在Direct3D模式下的渲染十分糟糕,特别是在目前主流的显卡上工作时,其效率以及画质远不及OpenGL模式下的表现。在设计Source引擎的时候,Valve放弃了ogl的渲染模式进而采用DirectX架构,以增强其硬件兼容性以及对未来特效的支持,比如是Shader2.0b甚至是Shader3.0 Model的支持。 Shader就是一些能够在GPU/VPU上执行的程序句段。目前市面上流行的游戏中,采用实时渲染的画面均大量运用了Shader,你的显卡无时无刻在处理着这些Shader信息。现代显卡主要的改进就是用Shader代码替代沿用自GeForce GTS时代固定的硬件T&L (Transform and Lighting)。Shader允许程序员创建他们喜欢的Shader特效程序片段以取代有限个数的固化在显卡核心中的预设特效。经过Shader编程之后,如果有一个关于bump mapping的技术推出,程序员只需改写或者加入该部分的Shader代码便能使这些特效运行在现今的显卡上,而不需等待下一代的显卡出现。于是,显卡的处理特性便得以最大程度地延伸。在程序接口方面,由Microsoft推出的HLSL、nVIDIA推出的Cg、以及OpenGL小组推出的GLSL都是编写Shader的工具。能和目前个人PC、工业用电脑上的DirectX以及OpenGL很好地对应。 Source对directx中的pixel/vertex shaders version 2.0提供了完整的支持,Valve最近的声明指出Source引擎将在未来硬件成熟的时候提供对Shader3.0的支持。目前的Source引擎中,所有的directX 9 Shader均在 (high level shader language)下完成,对代码的运用上只需简单地插入片段,省却了在底层使用汇编语言重编译的麻烦,增加了Source引擎的弹性。在引擎代码方面,所有的代码均用C/C++ using Visual Studio 6.0进行开发,有很大的开放度以及可扩展性,目前已经有数家公司得到Valve授权采用Source引擎进行下一代游戏的开发,除传统的FPS游戏之外,还有aRPG,SPD等模式,相信在明年开初将会见到很多采用Source引擎制作的佳作。 对于玩家,Shader就能实现依靠驱动程序实现更加多以及更富弹性的特效,在Half-Life 2中最为凸出的Shader2.0特效就是那些吸引眼球的充满反射和折射的水纹效果。在目前推出的基于Source引擎的CS:Source选项设置中单独对水纹效果提供了一个现实效果设置选项。 |
光影效果: 在 Source 引擎中使用了两类的方法处理光影:辐射度光影贴图和环境光立方体贴图。
辐射度光影贴图 整个引擎的光影效果实现占据了Source引擎的绝大比重,这里只略略讲述Half-Life 2画面成功的秘诀--辐射度光影贴图。在 Source 引擎的渲染器中,辐射度光影贴图扮演着一个最为重要的角色。先给大家一个辐射度光影贴图所能实现的大概效果: 方向性光照 辐射度光照 辐射度光照)以及更加细腻的模型细节(法线贴图)通过算法整合到最后的效果图中。
辐射度法线贴图基本方程 在传统的法线贴图中,每次工作只会累积一个光源的效果,多重漫射光将会由NL在多通道中进行合成,在对Light Map进行辐射度处理的时候只能处理一个颜色值。辐射度法线贴图能在一个通道中实现任意多光线的处理,基本处理方程会转化为每个切面的向量计算。在DirectX中,法线是可以转换的,并不局限于形体,可以扩展到光线、颜色……。在辐射度贴图中,使用下面的方程将法线从法线贴图中转换为上述辐射度法线贴图基本方程: lightmapColor[0]*dot( bumpBasis[0], normal )+lightmapColor[1]*dot( bumpBasis[1], normal )+lightmapColor[2]*dot( bumpBasis[2], normal ) |
在Hammar这个Half-Life 2地图编辑器中,设计者在材质表面安设了环境探测用的实体以作为镜面反射的参照物。 接下来将会为大家讲解在Half-Life 2中整个静态环境的生成。首先将会为大家介绍一下我们想得到的效果,并以一个小范围为例说明整个Shader序列的创建过程: |
实现的效果可以用下面的流程图进行说明: 左下脚的Normal法线贴图和三张Lightmap混合后的辐射度贴图再加上漫反射系数的控制就可以创建出以上所说的辐射度法线贴图;再以加法加上传统的表面光滑度以及反射度的贴图结果,就可以生成最终的贴图效果。在Source中创建一个静态的环境时还需要用到三张Lightmap,主要是考虑到为了适应任意光源的作用。在下面的分组图中,大家会看得更加明白: LightMap #1 LightMap #2 LightMap #3 三张直接辐射能贴图整合之后的效果,由于缺乏了法线贴图的支撑,整体没有细节可言。 由于这个过程处于贴图的预处理程序,需要考虑到整体执行的效率,因此只采用了分辨率较低的lightmaps贴图(因为diffuse材质的irradiance十分平滑的,只需很小的分辨率,渲染结果是通过filter还原),在这一步骤中,渲染的贴图可以说丢失了所有的细节。如果盲目增大lightmaps的分辨率,处理时间会成倍增加,显存带宽也会被大量占据。 因此,Source引擎将lightmaps分成三个成分,每个贴图都有其对应的基本方程,最后根据法线贴图储存的法线进行混合得出第一步的处理结果,在很大程度上利用了低分辨率的好处,并且能将法线贴图所最擅长的细节表达发挥出来。 另一方面,程序设计员可以采用不同的法线贴图与之结合,在debug模式下实时检查渲染结果变得比以前方便得多。 |
接下来,Source会将上面由Lightmaps生成的辐射贴图附上法线贴图, 辐射度贴图 法线贴图 被细节化的辐射度贴图 物体的表面有凹凸的细节,形状方面需要依靠法线贴图实现,至于光线的表现方面,则需要依靠漫反射系数来确定。下面的流程就是继续细化并加上法线贴图的辐射度贴图。 |
同时,考虑物体表面反光程度的镜面反射贴图也在进行之中,第一步也是采用立方体反射贴图和法线贴图的混合: 辐射度法线贴图 漫反射系数 被加上漫反射系数的辐射度法线贴图 |
最后的步骤,由加上了漫反射系数的辐射度法线贴图和加上了镜面反射系数的镜面反射贴图进行加法运算,得出最后结果 上一步生成的镜面反射法线贴图 镜面反射系数 镜面反射法线贴图和镜面反射系数的混合 在整个渲染流程中,法线贴图起着引导性作用,ATI目前的顶级产品Radeon X800系列已经完整支持新一代的法线贴图处理方式,并对大材质的贴图采用了全新的3Dc纹理压缩技术。虽然我们目前未收到任何关于Source引擎采用3Dc纹理压缩的消息,但从ATI发布的白皮书来看,X800系列显卡在处理法线贴图的算法技术上会和Valve有更好的沟通,实操效果会占据一定的优势。 |
水面的视觉效果: 首先我们来看反射。Source 引擎首先将水面上要反射的景物上下颠倒地渲染到一张贴图上。然后是折射,将水下的景物渲染到另一张贴图上。然后将这两张贴图贴到水面的多边形上,同时根据凹凸贴图,使用 Pixel Shader 对纹理坐标进行调整,以加入扰动,得到水的最终效果!简单吧。 然后将这两张贴图贴到水面的多边形上,同时根据凹凸贴图,使用 Pixel Shader 分别加入扰动,得到水的最终效果!简单吧。如果没有DirectX 9.0中的Pixel Shader技术,想对反射和折射贴图进行象素级的扰动来实现这样的水面效果是十分困难的。在Source引擎中对水面的视觉模拟范例 只采用了30行左右的代码: 最终的效果 反射贴图 折射贴图
|
色泽贴图(tonemap) 如果你有一间只有一角被照亮的,灰暗的房子,那么在这个角落里的物体旁边的光线会比房间其他地方要亮。这就是一个”泛光”的现象。如果你将整个房间照亮的话,在这个角落上的物体也会在视觉上出现高于正常的亮度。在这个黑暗的房子的顶棚开一个洞,比如是天窗或者是破旧的穿洞什么的,让外面的阳光直射进屋,这时在天窗或者孔洞的周围就会出现泛光的现象,这一圈的范围会出现很多鲜明生动的色彩。在 Half Life 2 中,这些泛光或光晕是由光泽贴图进行处理的。 由于一般 HDR 也在后期处理的时候使用光泽贴图,所以许多游戏中应用的光泽贴图并且往往被误认为是 HDR。
|
动画、几何体以及游戏界面 动画以及角色面部造型 就如目前很多的现代游戏引擎一样,角色的动作效果由一个骨骼系统控制。事实上,Half-Life 1 是这个骨骼系统使用的先行者。通过这骨骼系统,多种的动画以及细腻的动作可以被绑定到同一个角色上,由绑定在不同骨架部位的动画互相作用而生成整个角色的动作。Source引擎还在这个骨架系统中整合进Havok先进的物理引擎。 对于玩家来说,使用附加有物理特性的骨骼系统会让我们看到更加真实的角色动作以及怪物的运动动作。因为在这些骨骼上会混合地播放角色动画,举个例子,一个角色在跑动的时候向对手开枪,然后被对手还击的子弹击中手部,手中的枪脱手飞出……这一系列的动作都能在一个角色上同时上演,加入了物理特性的骨骼系统能对受伤的手部作出反应,比如是承受冲击力时的晃动以及身体的扭转。 面部动画系统 Geometry 几何模型的体现主要来自网格(例如表现一个物体或者角色的整体),静态网格(非生成整个物体),BSP序列以及一些几何建模实体。在Source中,所有的几何体均被储存在BSP序列中,当你查阅该序列的时候,你可以看到几何体均在 Hammer 地图编辑器中的光影关系,正如上面所说的场景合成一样,所有的辐射度、漫反射系数、镜面反射系数等均在编辑器中生成。 BSP序列 (Binary Space Partitioning tree) 用以储存在Source里面大量的固态几何体(或许还有一些非固态的),不过,关于BSP序列的创建以及具体的操作将不在本文的讨论范围,各位有兴趣的玩家可以在google上搜索有关地图制作的知识,特别是关于Hammar地图编辑器的使用帮助。 当我提及“mesh”网格的时候,具体指的是一些将几何体储存在地图文件之外一些独立的文件中,Source采用了.mdl文件来储存mesh网格。mesh多数用在创建能移动的物体或者一些复合的静态物体,主要是因为这种格式的文件能被XSI以及3DMax这些常用作三维建模以及动画设计的软件所导入。此外,.mdl文件还能多次地在场景中出现而避免重复地将几何体插进地图文件,采用了.mdl之后,你就不会再为已经够复杂的BSP序列添加进更多的冗余信息。 |
VGUI 值得欣喜的是,Valve的图形控制界面将在Source中获得全新的定义。大家都知道,GUI (Graphic User Interface,用户图形界面) 就是和命令行(拼命地打字输入命令)相对的概念,意味着你根本不需要输入任何的命令,因为你有形象的图形操作界面能实现交互的人机操作。VGUI更是让开发者使用Source进行GUI的渲染,能在游戏中任何的地方显示并交互执行命令。这时,VGUI已经不再只限于一套菜单系统,他提供了程序接入窗口、按钮、弹出窗口、内核控制命令行等等控件。所有的这一切能按照程序员甚至玩家的意愿显示或者放置。另一方面,由于Source的VGUI采用了兼容的Unicode编码,能很方便地实现游戏语言以及文字的本地化,在CS:Source中任何地方的中文输入甚至全世界的语言文字输入已经让我们见识到了下一代VGUI的威力。 在Source中,VGUI能在游戏中以及游戏外面进行显示,Steam的菜单就是一个很好的例子。在CS:Source出版之前,我们还不清楚,STEAM看似革命性的菜单是否就是采用了全新的VGUI编写。到了今天,CS:Source正式公开测试,可以这样下一个判断,CS:S中的,才是真正的VGUI,因为他采用了游戏的渲染引擎进行菜单的润色渲染,并能通过菜单操作所有的界面命令以及内核命令(半透明以及淡出淡入的效果、Debug Option菜单、附着完整信息的Console控制台),而Steam的窗口菜单只是GUI菜单的一个比较完善的改进罢了。据称,Valve将为Source制定的VGUI命名为VGUI2 物理系统 有一样东西是Valve想在Half-Life 2中需要解决的首要问题,那就是一个能让角色和场景中任何物体都能发生互动关系增加整个游戏可玩性的物理引擎。Valve一直在找这样一个引擎,能让物品能和主角发生互动关系而不再是一个摆设,最后,他们将目光定格到 Havok 的物理引擎上。 当和Havok整合之后,Source的一切得到了重生般的感觉,引擎里面所描述的所有东西都有了他们独到的物理特性,包括了声音、外观、材质、AI以及角色动画。当Valve被问道,是否会将Havok 1 引擎升级到Havok 2 的时候,Valve指出目前并不会作出此等举动,因为二代的引擎并没有比目前他们所拥有的引擎有更多的性能提升。 |
刚体动力学 以及 约束、关节链 正如名称一样,刚性物体不能在游戏中被打碎、弯曲或者其他形式的扭曲。刚体的动力学是目前游戏中最常见的一个物理引擎表现部分--仅仅是非形体变形上的物理模仿,通常会以小盒子、铁桶、临时的木板等形式出现,不过有时候也会以小玩偶的形式出现(通过关节链将刚体组成一个简单的整体) 关节节点就是常说的活动连接,这种连接允许你将两个物体有机地连接在一齐,你可以为这个关节添加约束,使他们只能在你规定的范围之内活动而不会走远。这就是在游戏中NPC被创建出来的关键。在众多角色中数不清的关节里面,有一些是能够被打断的,而有一些不能,在这些能够被打断的关节上,在被折断前就存在着一个受力的极限值。 楼房被怪物击中,整个墙壁以及上面挂着的招牌被怪物强劲的冲击波衔翻,在Half-Life 2中似乎到处都充满这种可以被破坏的墙体。 柔性体: 和刚性体相对的就是柔性以及弹性体,就和Source中的物理特性--作用力与反作用力一致,具体来说就是受力物体对施力物体的一种反作用,起到两者的排斥反应,只不过在弹性力中,这种排斥力是柔和的,加速度相对较小。在和橡胶轮胎的碰撞中,我们就能体验到这种弹性的反作用力。绳索的定义只需在地图编辑器中简单地连接两点并指定其属性即可,最重要的一个属性就是取样点的多少。当然,取样点越多绳结看上去越真实,但会对显示性能造成负面的影响。布料的模拟就类似于绳索,取样点点的多少将直接对布料在物理环境(大风、皱褶等)中的真实程度。当然,布料的模拟将消耗比绳索更加多的CPU资源而且按照目前的3D设计来说,要真实地模拟出一块布料在各种环境中的形态还是未能做到精确。 车辆系统在Source中就是物理系统和建模系统的有机结合,加入了属于专有的脚本系统以便能让玩家操纵车辆。在Source引擎中的车辆系统由另外一群主要的专业设计师担任设计,以在达到最真实效果之余在最大限度上节省创作时间。毕竟Half-Life 2不是一个专业的赛车游戏,玩家只会用方向键对车辆进行操控,因此,在游戏中出现的航船、气垫船等可操控的交通工具均保持了最高的易用度:和读者想像中最简单的操作方法一样,WSAD控制方向,鼠标控制视觉以及枪械的瞄准。当然,车辆拥有属于自己的一套独立的脚本系统。 水、火 Source中另外一个令人迷惑的东西就是水的模拟系统。当Valve说,水的效果会在物理的层面被模拟的时候,各界均推断在Source中将会引入流体动力学并加入物体的浮力特性到其物理指标中。但到了后来,Valve在声明中指出,在Source中并没有内建流体动力学的模型,water区域只是一个加入了特别的物理特性的场地。当其他的物体进入到这个区域后,会作出与之正常行为不同的动作,比如是行动变得缓慢、并且会出现重力上的变化(浮力)。当然,如果是真正的流体动力学模拟的话,将会是完全的自身物体特性引起的行为动作而非单纯的两者之间的互相作用。 火,在Source系统中并非一个独立的系统,但作为一个FPS游戏中不可或缺的部分(特别是Half-Life 2这种充满毁灭性镜头的大作),火的效果是最能吸引玩家的眼球的。在Source中,火混合了粒子系统和材质系统,按照道理来说,在游戏关卡中的火苗如果在旁边出现易燃的物体的话,火将会向这些物体蔓延出去,不过并没有确切的消息肯定这个推断。 |
粒子系统和材质系统
在Source中,粒子可以理解为“点状物”,常在一些单面的几何面上出现,这种粒子没有区域,没有体积,只能依靠坐标系或者某些参照物来描述其存在的位置,在字面上解,他们就是在空间上的点,是Source中比较容易进行模拟的物体。Source中的粒子除了长宽高的几何尺寸和明显的扭转系统之外,拥有和刚体完全一致的物理特性,毕竟,例子系统并不需要和刚体系统那样丰富的互动性。在游戏中,使用粒子系统创建的最常见的物体就是烟雾、沙尘、火、雨、雪、血雾、火花以及飞溅的碎片。
材质系统 在Source引擎中的材质系统被赋予了物理特性以及贴图外观的特性。例如,给一块板赋予木材的材质,这块板便具有了木材的所有物理以及外观特征,重力、韧性、声学特性等均被附加到这块板上。材质特性方面保留了诸如密度、表面材质、耐压度、以及当折断或者敲击时发出的声响,虽然这些在众人眼中看是一些很简单很必然的事情,但在游戏中,这些细节将会是游戏增加其感染力的最佳途径。此外,AI系统还能就材质系统提供的信息,反馈给NPC以使其对战术作出相应的调整。当然,玩家也可以充分利用材质的特性从而得到更多的通关方法。 木板被赋予了物理刚节点之后,破裂之后的断层不再如一般游戏那样刀切般平整。 |
AI系统 AI,Artificial Intelligence,近年来在电脑领域是一个突飞猛进的科研领域,一个优秀的AI系统,能对其周围的环境智能地作出非线性的反应并采取相应的行动。最重要的是具有依据周围环境参数的变更而决定系统行动的能力,否则,就不能称之为真正的AI。一个惯常的AI系统,会使角色根据当前任务的可行性、对主要任务影响的重要性以及目前的周遭环境作出判断以选择达到预定目的的最佳途径,而怎样选择最佳的动作以达到这个目的,就是一个AI系统优秀与否的体现。 聪明的NPC借助矮墙以及队友在对角线火力的掩护下弓身前进。 老实地说句,笔者并不完全明暸Source的AI系统所能够完成的任务,Valve关于Half-Life 2的白皮书中就说过很多的东西表明Source里面的AI系统是多么的强大,大意就是下面的几点(已经足够让目前每一个游戏汗颜的了)。
在游戏中NPC的AI着实让笔者大吃一惊,比如在TrainStation的一幕,主角刚刚到达City17,被NPC带到一个阴暗的长廊上准备接受洗脑,途中听到一间房间内发出人类疼苦的哀嚎,好奇的主角把头凑过去那个房门上打开的小窗户想了解里面发生什么事情,这时,屋内的NPC会判定屋子里面发生的事情不是主角所应该看到的,于是,NPC会走过来,唰地一声将小窗户关上……类似这种行为判定的例子在游戏中往往会是通关的关键。Source引擎做到了主角和NPC之间很好的互动以及沟通。 |