1.6.5 平台无关层(Platform Independence Layer)
大多数游戏引擎需要有能运行在超过一个硬件平台上的能力。像EA及动视暴雪(Activision/Blizzard)这些公司,一直把它们的游戏定位在一个非常广泛的平台,因为这能使他们的游戏拓展到尽可能大的市场。典型的,对每个游戏,唯一不把目标定在至少两个不同的硬件平台上的公司是第一方工作室(first-party studio),如Sony的Naughty Dog还有Insomniac Studio.因此,绝大多数游戏引擎架构上都有一个平台无关层,如图1.16所示。这一层建立在硬件层、驱动层、操作系统,还有其它第三方软件上之,把引擎的剩余部分和大部分的底层平台细节隔离开来。
图1.16 Platform Independence Layer
通过封装或者取代最常用的C标准库中的方法,操作系统调用,以及其它的基础的API,这个平台无关层保证引擎在所有不同的硬件平台上的行为一致性。这个是必要的,因为不同的平台之间有很多差别,即使是C“标准”库。
1.6.6 核心模块(Core System)
每个游戏引擎,还有每个真正的大的,繁杂的C++软件程序,都需要一个有用的软件功能集。我们将会把它们归类在核心模块下面。一个典型的核心模块层如图1.17所示。这里还有几个核心层一般都提供的模块的例子.
图1.17 core system
* 断言(Assertions). 断言是进行错误检查而插入的用来捕获逻辑错误以及违反程序员本意的代码。断言一般在最终产品生成时被移走。
* 内存管理(Memory management). 目前所看到的所有游戏引擎都实现了它自己一套内存的分配机制,来确保高速的内存分配及释放以及减小内存碎片带来的负面影响(见5.2.1.4节)。
* 数学库(Math library). 游戏是天生的对数学要求很高的。正因为如此,每个游戏引擎至少都有一个数学库,如果没有多个的话。这些数学库为向量及矩阵运算、四元数旋转、三角运算、对线、射线、圆、截头锥体(frusta)的几何操作等提供工具。插值(spline manipulation)、数值积分(numerical intergration)、系统方程式求解,以及所有程序员要求的其它功能。
* 自定义数据结构及算法(Custom data structions and algorithms). 除非引擎设计人员决定完全的依赖第三方库如STL,那么一堆用来管理基本的数据结构(链表(linked lists)、动态数组(dynamic arrays), 二叉树(binary trees), hash maps, etc)及算法(搜索、排序等)的工作一般来说是需要的。它们一般是手动编码以求最小化或者消除掉动态分配,以及确保在目标平台上最佳的运行性能。
关于最常见核心模块的详细的讨论请看第二部分。
1.6.7 资源管理器(Resource Manager)
在每个引擎中以某种形式存在着,资源管理器提供一个统一的接口(或者几个接口)来存取任何及所有的游戏资源及其它引擎输入数据。有的引擎采用一个高度集中并且稳固的管理(如Unreal的packages,OGRE 3D的Resourcemanager类).其它的引擎则采用一些特别的方式,一般让游戏程序员直接存取磁盘上的原始文件或者从一个压缩结构中读取像Quake的PAK文件一样。一个典型的资源管理器如图1.18描述。
图1.18 Resource Manager
1.6.8 渲染引擎(Rendering Engine)
渲染引擎是任何一个游戏引擎中最大和最复杂的组件之一。它可以有不同方式的架构,没有一个绝对的标准去做。不过就如同我们看到的一样,大多数现代的渲染引擎都采取了一些基本的设计哲学,并受到它们所依赖的3D显卡的设计很大的影响。
其中一种比较常见和有效的设计一个渲染引擎的方法是采取如下的层次架构:
1.6.8.1 低级渲染器(Low-Level Renderer)
低级渲染器,如图1.19所示,包括了所有的原始渲染引擎特性。在这个水平上,设计目标主要集中在如何快速且大量的渲染一堆几何图元,不考虑场景的哪个部分是可见的。这个组件可拆分为几个子组件,将在下面进行讨论。
图1.19 Low-Level rendering engine
* 图形设备接口(Graphics Device Interface)
图形SDK,例如DirectX和OpenGL,需要一大堆合理的代码去查询可用的图形设备,初始化它们,设立渲染面(Render surface)(后台缓层(back-buffer),模板缓存(stencil buffer))等等。这些东西一般由我们称之为图形设备接口的组件管理(尽管每个引擎有它自己的术语)。
对一个PC游戏引擎,你还需要代码把你的渲染器跟Windows的消息循环结合起来。你可能会写一个"消息泵"(message pump),当Windows消息没有被处理的时候进行处理,否则就尽可能快的执行渲染循环。这个把游戏的按键输入与渲染器的屏幕输出循环连接在一起了。这个连接是不大好的,不过好处是可以把对硬件的依赖性最小化。后面我们会对这一问题作更深入的探讨。
* 其它渲染组件
低级渲染器中的其它组件通力协作,目标在于收集提交的几何图元(geometric primitives)(有时候也叫做渲染包(render packets)),如网格(meshes), 线段系列(line lists), 点系列(point lists),粒子(particles), 地形块(terrain patches),文本字符串(text string),以及其它所有你想画的,然后尽可能的绘制它们。
低级渲染器一般提供一个视口(viewport),它由camera-to-world矩阵及3D透视的参数如FOV(field of view)及近剪裁面及远剪裁面得出。低级渲染器也根据它的材质系统(material system)以及动态光系统(dynamic lighting system)来管理图形硬件的状态及游戏的着色程序(shaders). 每个提交的图元都伴随着一个材质,并且被n盏动态光影响。材质(material)描述了当这个图元被渲染的时候,图元(primitive)所用到的贴图(texture),硬件需要事先被设定的状态,以及哪个顶点着色程序(vertex shader)/象素着色程序(pixel shader)被采用。光照和着色程序是一个非常繁杂的话题,在许多卓越的计算机图形学书籍中都有深入的探讨,包括[14]、[42]、[1]。
1.6.8.2 Scene Graph/Culling ptimizations
低级渲染器渲染所有的提交给它的几何图元,不管它是否可见(除了背面剔除(back-face culling)以及视锥剔除)。一般需要一个更高级的组件来闯荡江湖提交的图元数,根据某种方式的可见检测。这一层如图1.20所示。
对每个小的游戏世界,一个简单的视锥剔除(frustum cull)(去掉摄像机不可见的部分)是必要的。对于大的游戏世界来说,一个更高级的空间划分(spatial subdivision)数据结构可能用来提高渲染效果,它能对物体的潜在可见集(potentially visible set, PVS)进行快速的检测。PVS有多种形式,包括二叉空间分割树(binary space partitioning),四叉树(Quadtree),八叉树(octree), 多维检索树(kd-tree),或者sphere hierarchy. 空间划分有时候被称作scene graph, 尽管技术上来说后者只是一种数据结构且并不包括前者。Portals/occlusion culling可能也会应用到渲染引擎的这个层级中。
理想的,低级渲染器应该完全不知道上面所使用的空间划分或者scene graph。这个能让游戏团队重用它们的图元绘制系统,不过PSV系统则跟他们的游戏的特定的需求有关。OGRE 3D开源渲染引擎的设计是体现这一原理的极好的例子。OGRE提供了一个即插即用(plug and play)的scene graph架构工。游戏开发者可以从预定义实现的几个scene graph设计中挑选一个,或者提供一个自定义的实现。
1.6.8.3 视觉特效(Visual Effects)
现在的游戏引擎支持大量视觉特效,如图1.21所示,包括:
* 粒子系统(particle system),用于烟,火、溅起来的水花等
* 贴花(decal system),用于弹孔,脚印等
* 光照贴图light mapping and 环境贴图environment mapping
* 动态阴影dynamic shadows
* 全屏后期特效full-screen post effect,作用在3D场景被渲染到离屏缓存上之后。
图1.21 visual effects
一些full-screen post effects的例子:
* 高动态光照渲染(high dynamic range(HDR) lighting and bloom.)
* 全屏抗锯齿(full-screen anti-aliasing(FSAA))
* 颜色纠正(color correction)以及各种滤镜(color-shift)特效,包括跳跃漂白(bleach bypass),过饱和(saturation),去饱和(de-saturation).
对一个游戏引擎来说,拥有一个特效系统来按理所有的粒子,贴花,还有其它特效的特殊渲染是常见的。粒子和贴花系统常常作为渲染引擎中一个比较独特的部件,并且作为低级渲染器的输入。另一个方面,光照贴图、环境贴图、阴影一般由渲染引擎内建管理。全屏后期特效则既可以作为渲染引擎内建的模块实现,也可以作为一个独立的模块来操作渲染器输出缓存。
1.6.8.4 前端(Front end)
大多数游戏都采用了一些2D的图形放在3D场景上面来实现各种目的,如:
* heads-up display(HUD)
* 游戏内建菜单或者控制台,或者其它开发工具,它们可能不会从最终产品中移除。
* 可能有一个游戏内建的图形用户接口(GUI),允许玩家来改变他的角色的道具,配置战役中的战斗单位,或者完成其它复杂的任务。
这部分如图1.22所示。这些2D的图形一般是在一个正交投影下用绘制四边形(quads)(两个三角形)来实现的。或者是完全的3D制作的,采用四边形的公告板(bill-boarded)技术来使它们一直朝向镜头。
在这一层中可能还包含全动视频系统(full-motion video FMV system).这个系统负责播放预行录制的全屏的电影(游戏引擎渲染的或者其它渲染工具渲染的)
图1.22 front end
一个相关的系统是in-game cinematics(IGC).这个组件允许电影跟游戏本身结合起来。例如,当玩家走过一个城市,两个关健角色的对话就可能是一段in-game cinematic. IGCs可以包含或者不包含玩家控制的角色。它们可能被设计成当玩家失去控制权时出现,或者可能是巧妙的整合进游戏而玩家根本没有意识到这儿有一段IGC.