GAMES104课程笔记02-Layered Architecture of Game Engine
这个系列是GAMES104-现代游戏引擎:从入门到实践(GAMES 104: Modern Game Engine-Theory and Practice)的同步课程笔记。本课程会介绍现代游戏引擎所涉及的系统架构、技术点以及引擎系统相关的知识。本节课主要介绍现代游戏引擎的分层架构。
现代游戏引擎是一个非常复杂的系统并包含了海量的代码,但幸运的是游戏引擎一般会通过分层的方式将这些代码组织起来。因此了解游戏引擎的分层架构有助于对整个系统形成全面的认识。

A Glance of Game Engine Layers
打开一个游戏引擎会直接看到各种类型的编辑器。这个直接和开发者进行交互的层称为工具层(tool layer)。

在工具层下面包含功能层(function layer),用来实现游戏的渲染、动画、交互等不同类型的功能。

在此基础上还需要资源层(resource layer)来管理各种各样的场景美术资源。

再下一层是核心层(core layer),它包括支持游戏渲染、动画、物理系统、内存管理等不同系统的核心代码。

最底层是平台层(platform layer),一般包括各种图形API、输入设备支持以及不同游戏平台的底层代码。

除此之外各种不同类型的中间件也会贯穿整个游戏引擎的不同层。

Explore Game Engine Layers
加下来我们介绍游戏引擎不同层的逻辑和功能。
Resource Layer
首先来看资源层。游戏中的每一个对象都包含不同类型的资产(asset),比如说几何模型、纹理、声音、动画等,同时每种资产都可能包括不同的数据格式。通过资源层我们将游戏对象的资产组织起来并通过全局唯一标识符(Globally Unique Identifier, GUID)进行识别和管理。

资源层和通常意义下的资源管理器的一大区别在于资源层需要对各种资产进行动态实时的管理,不同资产之间的通信和交互往往需要通过handle系统来进行实现。handle系统的细节我们留到后面的章节再详细介绍。

因此资源层的核心在于管理不同资产的生命周期(life cycle)。大型游戏需要实时地加载并回收系统资源,如何设计出高效的垃圾回收(garbage collection, GC)和动态加载机制对于提升系统的运行效率有着重要的价值。

Function Layer
功能层用来实现游戏的核心玩法。某种意义上讲功能层的作用类似于一个时钟(tick)用来控制整个游戏世界的运行,在每个时钟周期内功能层需要完成整个游戏系统的全部运算。

一般来说tick在运行时会依次调用两个函数:tickLogic()
以及tickRender()
来分别更新系统的状态和并把图像绘制到屏幕上。这里需要注意逻辑的计算是严格早于渲染的,编程时也要注意不要把它们混到一起。

在每一个时钟周期内一般会把视野范围外的对象裁减掉只对视野中的物体进行渲染。如果仔细观察还可以发现场景中的物体都是按照一帧一帧的方式发生运动,这样通过人眼的视觉残留效应就形成了我们看到的动画。

当然功能层的作用不仅限于逻辑以及渲染,实际上功能层会占据整个游戏引擎很大比例的内容并且和游戏自身的玩法密切相关。

为了提升游戏引擎的计算效率现代游戏引擎往往会通过多核的方式来充分利用CPU计算的资源。未来的游戏引擎架构一定会向多核并行的方向上发展,因此在设计引擎时最好从多核的角度进行思考。当然如何管理计算任务之间的依赖仍然是一个难点。

Core Layer
功能层的各种数学计算需要核心层的代码进行支持。一般来说核心层不会涉及到过于复杂的数学知识,基础的线性代数就能满足绝大多数游戏引擎的需求。

核心层的数学库和通用数学库的一大区别在于游戏引擎对于计算的实时性要求更高,有时我们甚至可以牺牲一些计算精度来换取计算效率的提升。同时核心层数学库还大量使用了CPU的SIMD指令,这样可以极大地加速矩阵和向量的计算速度。

数学库之外核心层还需要包含各种常用数据结构的实现。需要说明的是即使是C++标准库stl,有些数据结构的实现仍然不是效率最高的,因此在核心层中需要根据需求重新实现一些常用的数据结构。

核心层最重要的功能是实现内存管理(memory management),从这个角度看游戏引擎的功能非常类似于操作系统。在游戏运行时往往会直接申请一大片内存空间然后通过引擎而不是操作系统进行管理,这样可以提升系统的运行效率。

总结一下,核心层是整个游戏引擎的基础,它要求非常高的代码质量而且在大多数情况下不要随意修改它。

Platform Layer
为了克服不同平台对于代码的限制,我们需要平台层来提供对不同操作系统和硬件平台的支持。这样我们就只需要一套代码就可以在不同的平台上运行程序。

不同的平台往往使用了不同的图形接口,为了统一代码游戏引擎的平台层提供了RHI(render hardware interface)作为通用的图形编程API。RHI包含了统一套程序在不同图形API上的实现,这样上层的图形应用中就可以使用统一的一套API进行编程。

不同的平台甚至可能有着完全不同的硬件架构,为了高效地利用平台的计算资源需要平台层将计算逻辑合理地分配到不同平台的计算硬件上。

Tool Layer
工具层是为游戏开发者提供支持的一层。工具层允许游戏开发者直观地预览不同美术资源在游戏环境中的表现,对于游戏开发者和设计师有着重要的意义。

除了游戏引擎自己的开发工具外一般还需要导入其它软件和开发工具的资产,这就需要asset conditioning pipeline来提供不同资源导入游戏引擎的统一管线。可以说编辑器和asset conditioning pipeline共同构成了游戏引擎的工具层。

Why Layered Architecture?
对游戏引擎进行分层的意义在于对不同类型的代码进行解耦,这样可以更好地管理这个系统的复杂度。

Mini Engine: Pilot
本课程使用课程组自行开发的Pilot引擎来介绍现代游戏引擎的基本架构和实现。



