01 - 引擎架构分层与整体Pipeline

这篇文章说明了游戏引擎的分层架构,初探游戏引擎。

在《游戏引擎架构》这本书中,有一幅著名的架构图:

看起来十分复杂,让人劝退。因此得进行分层,先进行一个快速入门。

工具层

工具层(Tool Layer),提供了一系列工具链,例如引擎UI,编辑器等,让任何人都可以自由的去创作游戏。

除了自己制作的编辑器(Qt,WPF,HTML等方式)外,还能利用其他著名软件的编辑器。用它们创作的数字资产可以通过 Asset Conditoning Pipeline(各种各样的导入器和导出器)进入我们的游戏引擎中。

功能层

功能层(Function Layer),为游戏提供基本的物理、动画、渲染、相机、HUD、人机交互(输入)、脚本、音频、AI等等功能。

让游戏世界动起来

像现实世界的时间由“秒”驱动那样,游戏也有一个计时单位——tick ,每次进行1tick,游戏就会进行某个操作(如上图)。1tick通常是1/30秒。

先模拟再渲染

在GAMES101里也说过,我们应该先模拟再渲染,将tick操作拆分成模拟/逻辑(Logic)渲染(Render)两部分。

对于模拟部分,它通常包含对玩家输入、物体移动、物体碰撞等等的处理;对于渲染部分,会对场景着色、光照等等方面进行处理。

使用多线程

现在已经进入到多核时代,对于功能的计算和处理应该并行的进行。主流是多线程加速,但仍吃不满每核的性能,更先进的是JOB System,将每种功能的计算和处理视为原子操作,吃满每核的性能。

对于这方面的难点是 依赖处理 ,例如角色的攻击动画可能需要好几个功能先后参加,如何高效并行让它们执行,使得流程更高效是个问题。

资源层

资源层(Resource Layer),各种各样的游戏文件都需要资源层来加载和管理,为游戏引擎提供资产服务。

将资源变成资产

各种各样的资源文件让一起读取是很麻烦是费事的,不妨将它们 转换为我们引擎独有的资源文件(.assets)并进行导入操作,可以高效使用和管理它们。

操作完成后,我们得到了离散的资源文件。很显然,有的资源文件是有关联的(例如某物体的模型文件和贴图文件),我们可以 用XML格式等定义一个混合资产文件(Composite Asset) ,让游戏引擎知道哪些资产是有关联的。

在现代游戏引擎中,我们希望 给每个资产设立一个唯一识别号(GUID),就像公民身份证号一样,独一无二。

实时资源管理器

在使用游戏引擎的过程中,我们需要一个实时的资源管理器来让我们更好的进行工作。该管理器是一个虚拟的文件系统,可以加载/卸载路径引用上的资产文件;该管理器通常是一个 handle system,管理资产的生命周期。

管理资产的生命周期

不同的资产有着不同的生命周期。例如过关游戏,每当玩家通关时,它就会卸载上一关的资源,并加载下一关的资源。在这一过程中,难免会造成卡顿,因此如何更好的进行 垃圾回收(GC)延迟加载(Deferred Loading)等资产管理的解决方案仍是需要解决的问题。

核心层

核心层(Core Layer),是游戏引擎的瑞士军刀,提供各种各样的工具(线程库、内存分配管理、数学库等),为上层的各种操作提供服务。

数学库

游戏引擎的数学库涉及到的知识一般不深(除了一些物理),大学线性代数基础就行。

数学库为什么要单独写,因为涉及到了优化问题。游戏中任何操作都是实时的,这就要求我们写的数学库效率得高。SIMD技术是最常使用的。

数据结构和容器

游戏引擎的数据结构和常用容器也需要自己写。以C++STL容器为例,它在进行高频数据插入/删除时会在内存中产生大量空洞,而且内存使用是不受控制的。因此,我们自己写的数据结构就得规避以上问题。

内存管理

游戏引擎就像操作系统,其内存管理也是很重要的一环。我们可以使用内存池等方法进行内存管理。

综上,Core层代码都是很牛逼的人写的,它应该由高性能代码和牛逼架构组成,平常最好不要碰它。

平台层

平台层(Platform Layer),用户的设备千千万万,输入方式各不相同,游戏引擎都需要对这些平台进行适配,将它们不同的输入和软件等“翻译”成同种语言,给游戏使用。

本层的目的就是尽量消除各平台差异,制定一个统一的标准。方便开发人员进行工作。

RHI(Render Hardware Interface)

对于图形API,在安卓上用到OpenGLES,在mac上用到Metal,在Windows上用到DirectX/Vulkan,在Linux上用到Vulkan…… 可以发现如果我们不制定一套统一的标准,写这些代码就会很煎熬。

于是就有了RHI,RHI对内编写了针对各平台的多种GPU和图形API的相关代码,并封装成统一的接口方便供上层使用。

不同的硬件架构

对于不同的平台(例如PC和主机),它们的硬件架构可能也不一样,平台层同样也要针对这些不同的硬件架构去做不同的优化。

第三方中间件

在各个层级中,我们也可以直接使用很成熟的第三方中间件来简化构建游戏引擎。

有些中间件需要和游戏引擎一起进行编译,有的只是通过文件和游戏引擎“对话”。

总结

  1. 引擎是分层架构的。
    1. 通过抽象化和分层,可以明确每层的职责,以至于在架构时不那么混乱。
    2. 分层结构的代码,越上层越灵活(可以随时更改),越下层越稳定(写好就不推荐再改了)。
    3. 尽量只让上层的东西去调用下层的。
  2. 驱动游戏世界的核心——tick

参考资料

  • GAMES104 (boomingtech.com)
  • 游戏引擎架构(3e)