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和主机),它们的硬件架构可能也不一样,平台层同样也要针对这些不同的硬件架构去做不同的优化。
第三方中间件
在各个层级中,我们也可以直接使用很成熟的第三方中间件来简化构建游戏引擎。
有些中间件需要和游戏引擎一起进行编译,有的只是通过文件和游戏引擎“对话”。
总结
- 引擎是分层架构的。
- 通过抽象化和分层,可以明确每层的职责,以至于在架构时不那么混乱。
- 分层结构的代码,越上层越灵活(可以随时更改),越下层越稳定(写好就不推荐再改了)。
- 尽量只让上层的东西去调用下层的。
- 驱动游戏世界的核心——
tick
参考资料
- GAMES104 (boomingtech.com)
- 游戏引擎架构(3e)