为了将游戏引擎解耦并降低复杂度,每一层都将独立,底层提供基础服务,顶层无需知道底层的具体实现,便于开发与版本迭代。在这一分层架构中,越往下,越稳定;越往上,越开放灵活。主流游戏引擎主要包含5个架构分层(Tool Layer、Function Layer、Resource Layer、Core Layer、Platform Layer)及第三方库(3rd Party Libraries):
- Tool Layer(工具层):一系列的编辑器,动作编辑器、材质编辑器、场景编辑器等。
- Function Layer(功能层):让游戏世界可以看得见(Rendering\Camera\HUD…),动起来(Animation\Physics\FSM\SCRIPT\AI…),玩起来(Input…)
- Resource Layer(资源层):处理数据、模型、音频等需要的资源。
- Core Layer(核心层):工具箱。内存管理、容器分配、数学运算、线程池。
- Platform Layer(平台层):解决平台通用性,多平台(PC、Mac)的多操作输入,输出(VR、AR)。多平台运行环境和发布环境(Epic、Steam)。
- 3rd Party Libraries(第三方插件):第三方的代码集成到引擎生态里面,或者处理引擎用的的资源文件。
- Tool Layer(工具层)
- Function Layer(功能层)
- Resource Layer(资源层)
- Core Layer(核心层)
- Platform Layer(平台层)
- 3rd Party Libraries(第三方插件)
Tool Layer(工具层)
简介
在一个现代游戏引擎中,我们最先看到的可能不是复杂的代码,而是各种各样的编辑器,利用这些编辑器,我们可以制作设计关卡、角色、动画等游戏内容,这一系列编辑器就构成了引擎最上面的一层:工具层。
该层主要提供可视化的接口给使用引擎的人员,该层也处理mesh、动画等资产的第三方格式导入导出(资产管道)。
允许任何人构建游戏
工具层通常以编辑器的形式存在,更加强调对于使用者的便捷性,以释放创造力。并且可用多种编程语言,保证开发效率优先。
该层是真正的生产力的工具,允许相关人员编辑自己想要的内容:比如美术编辑效果,因为在游戏中的实际表现通常和maya这些软件中的表现是不一样的;比如策划编辑各种游戏内容配置。
保证第三方数字资产可用
工具层需要确保编辑完的资源格式与引擎使用的资源格式对应。游戏引擎中使用资产管道(Asset Conditioning Pipeline)确保第三方开发的工具生成的数字资产可加载到游戏引擎中,具体来说是把别的软件(例如maya、3dmax)产生的Resource,序列化成引擎使用的Asset。
Function Layer(功能层)
简介
游戏中物理,渲染,动画相关处理都在这层。
- 物理:逼真的虚拟世界也离不开物理,物理系统将使用刚体、软体、流体等去表达世界,使得人与人、人与物不会发生碰撞。
- 渲染:为了使游戏呈现在屏幕上,需要渲染系统对虚拟世界进行渲染。
- 动画:动画系统将艺术家设计的动作动画在引擎中进行组合、过渡,让游戏人物在游戏动起来。
功能层的使用,使得每过一个tick时间,游戏中的虚拟世界就会前进一步。
Tick又分为tickLogic和tickRender。分别处理逻辑和渲染。
功能层的内容十分庞杂,而且经常难以区分哪些部分属于引擎,哪些属于游戏自身逻辑。
如何让世界动起来
功能层将使得整个虚拟世界变得栩栩如生:每隔tick时间,分别执行逻辑与绘制–tickLogic与tickRender。tickLogic主要用于模拟世界,包括处理输入输出,计算物理并进行碰撞检测等;tickRender将tickLogic计算的结果(人物位置等)进行绘制。考虑到功能层需要实现大量功能并对运行时间存在要求,功能层复杂性高,并通常需要借助多线程计算。
Tick分为逻辑层(Logic)和渲染层(Render)。
动画和渲染Ticks
每一个tick(简化):
- 获取获取角色的动画帧
- 驱动角色的骨骼和皮肤
- 渲染器在每个帧的渲染tick迭代中处理所有渲染工作
复杂性
功能层非常复杂、庞大,提供了游戏引擎中大部分功能模块,但哪些功能属于游戏,哪些功能属于引擎,界限不明确。
多线程
最早的计算机是单核的,现代计算机CPU为多核处理,引擎根据这一特性进行多线程计算。比如Logic和Render会在不同的线程中计算。在未来,引擎可将所有的任务变为原子计算,每当存在空闲核时,就将任务分配到该核上。
Resource Layer(资源层)
简介
资源层负责存储联系不同的游戏资产,管理资产生命周期。例如:材质,纹理和mesh的资产依赖记录;不需要的资产回收和延迟加载(deferred loading,如远处的景等到人物靠近了才进行加载)。
如何获取资源
通过定义元资产文件格式统一文件访问
Photoshop中的psd、3ds Max中的max等数据格式比较复杂, 包含大量与引擎无关的数据,如psd格式将保存Photoshop中所有的图层,包含通道、参考线、注解和颜色模式等信息。为了避免在使用资源时频繁调度并减少不必要的内存消耗,在导入资源时进行转换,将不同资源(纹理、模型几何、动画等)都转换为资产文件,即assest文件(.ast)。
通过导入预处理,可以更快地访问资产
对于引擎中最常使用的贴图数据,可使用png、jpg格式进行存储,上述格式对应相应的压缩算法,但这些压缩算法不是GPU高效的算法,直接在GPU中使用会浪费性能,通常在引擎中被转换成dds格式。dds格式针对纹理设计,支持很多其他图像格式不支持的功能,如Mipmap等。
构建一个复合资产文件以引用所有资源
对于一个游戏人物,可能需要绑定网格、动画、贴图、材质等资源,定义Composite asset文件(如XML)关联不同资源。
GUID唯一识别号作为引用的额外保护
GUID唯一识别号对资产进行管理,这些都是在资源导入引擎后自动分配给他的ID。
实时资源管理
所有的资源都需要可以变换路径,当变化路径之后还是需要知道这个资源的目录。
- 虚拟文件系统(实时资源管理器)通过路径引用加载或释放资源。
- 通过handle系统管理资源生命周期和引用
资源生命周期管理
不同的资源有不同的生命周期
异步加载、延迟加载,不断地加载出来一个资源的各个部件内容。
内存有限,尽可能释放可释放的加载资源
对于运行时的游戏资源来说,不可能将所有资源都读取到内存,因此资源层还需要处理运行时的资源加载与卸载。
垃圾收集和延迟加载是关键特性
如果资源回收时机不合理,就会出现卡顿的情况。异步加载、延迟加载,不断地加载出来一个资源的各个部件内容。当加载一个很大的资源比如人物时,会先显示主干然后脸然后皮肤线条,加载出来资源也是渐渐的变清晰。
Core Layer(核心层)
简介
工具层、功能层、资源层会频繁调用底层代码,使用容器创建、内存分配、数学库、多线程等底层功能,而核心层能够提供上述功能。
核心层需要质量高、少修改。该层是通用功能的集合,如内存管理,垃圾回收,自定义数据结构及算法,矩阵计算等数学库。这层的代码要精心设计,因其对效率要求很高。
- 核心层提供了各种功能模块所需的实用程序
- 超高性能设计和实现
- 高标准的编码
数学库及高效率算法
绘制和游戏逻辑需要的数学运算库。引擎的数学运算需要很高效率的算法,因为需要实时性,也就是可以到达一秒需要执行几十帧的运算。比如说:开方这些运算耗费性能,使用MagicNumber可以快速的得到一个近似的结果。
SIMD-单指令可以多数据进行,比如一次运算可以同时得到4个加法的值。
数据结构、容器实现
编程语言中自带的数据结构可能会出现一些问题,比如C++中的Vector在添加对象时开辟的储存空间会成倍增长,在添加大量对象后,使用的储存空间我们将无法得知,可能会产生内存空洞,而引擎中的数据结构更加方便内存的管理,提高访问效率。
内存管理
游戏引擎的内存管理十分接近操作系统。游戏引擎的内存性能瓶颈:
- 内存池(分配器)
- 减少Cache Miss
- 内存对齐
引擎内存管理准则:
- 数据放到一起,不要存在内存孔洞。如果存在内存空洞下次再插入数据就需要计算是不是哪个空洞可以放,不存在的话依次往后面放就可以了;
- 访问数据尽可能按照顺序的访问。访问一片内存时访问第一个数据要比第100个数据要快,因为读取指针偏移也是需要时间的;
- 读写时尽可能一起读写,比如要回收空间就找个合适的时间一起回收,然后重新排布内存。
Platform Layer(平台层)
简介
平台层使引擎能够兼容各种硬件平台,实现引擎的平台无关性。由于不同游戏平台对同一个文件的处理可能不一样,如Win和Mac路径的写法。更严重的是硬件架构都可能不同。所以需要一个平台独立层运行在各层之下,包装操作系统调用和其它API,保证引擎在不同硬件平台上达到相同的运行效果。
不同的规则
不同的平台有很多不同的规则,引擎需要隐藏掉这些规则,让上层来统一实现。不同规则比如文件系统的路径,win和mac的目录中分别使用的反斜杠和斜杠。
不同的图形API
不同平台使用的图形API不同,例如:图形设备接口在PC上是DirectX11、DirectX12,在Android上是opengl、Vulkan。 游戏引擎中一般使用RHI来解决这个问题。RHI是一套硬件无关,平台无关的图形渲染API,是Render Hardware Interface(渲染硬件层接口)的缩写,游戏引擎通过RHI把各个平台的图形API封装成统一接口,供上层渲染来使用,让业务不用过多的关注API细节。
不同的硬件结构
不同平台硬件结构可能不同,比如:PS3上面的CPU叫做PPU,GPU叫做SPU,很多运算可以放在一些特殊硬件上。游戏引擎的平台层需要解决不同硬件结构的兼容问题,保证引擎在不同硬件平台上达到相同的运行效果。
3rd Party Libraries(第三方插件)
在上述五层的构造中,都由可能使用到现成的第三方中间件。数据结构和算法,碰撞和物理,图形,角色动画,人工智能,生物力学等。这些都有现成的优秀第三方库可以使用,故第三方中间件在整个引擎中属于横跨五层的存在。