目录
现代游戏引擎
什么是游戏引擎
引擎开发的难点
游戏引擎分层
资源层
Importing
关联资产Composite asset
Runtime Asset Manager
功能层
Tick
多核
核心层
高性能计算
数据结构与容器
内存管理
平台层
文件路径
硬件渲染接口
硬件CPU架构
工具层
目前市面上的游戏引擎可分为三种:
工具层只能实现一些资源的编辑,场景渲染,物体是可移动的,绑定animation,NPC互动,物理方面
而游戏不仅仅需要代码,我们需要大量的数据和文件,主要是美术,音频和动画。因此游戏引擎中有一层用来加载和管理这些数据和文件,使得工作流与游戏高效运行
容器的创建,内存分配,或者是多线程的管理等
核心层像是一个工具箱,遇到什么问题就给一套对应的工具让你去处理,需要处理内存管理时核心层给你提供内存管理的工具,需要处理容器分配时核心层给你提供容器分配的工具,需要进行数学运算时核心层提供数学模块的工具。
游戏相关的逻辑管理是建立在核心层的基础上的,因此coer layer是最核心的一层。
不同硬件对应的平台也不同(PS\PC\Switch\IOS\Android\VR……),不同硬件的输入方式、渲染接口、功能特性各不相同,引擎有一层需要对不同平台进行处理。
- 至此我们有了平台层,解决了不同平台特性的问题
- 然后我们建立所有功能处理的内核,核心层
- 再建立资源层对资源进行加载和管理
- 接着我们建立功能层来进行与游戏相关的操作
- 最后我们建立工具层将功能层进行的与游戏相关的操作可视化为编辑器出来供使用者们使用
为什么要进行分层
Resource的文件格式是不同的,以类似maya,max这些格式的文件来说,它们是适合在自己的软件Maya,3DMax打开,如果用引擎来加载这些数据的话是很低效的。贴图可以是 png,或者 jpg 等,他们有自己的压缩算法,如果直接在 GPU 中使用会很费性能,可以将其统一转成 dds 格式进行使用。
因此我们需要将这些resource转换成引擎的高效数据,这一步叫做importing,而转换后的高效数据我们称其为asset。
现代引擎最核心的观念是数据之间的关联(reference)。
现代游戏引擎中我们希望对每一个资产都设置GUID(唯一识别号),从而避免资产位置改变而导致路径找不到的问题(路径无关性)。
现在我们已经加载了角色的resource并import成了引擎的asset,接下来我们需要对这些asset进行实时管理,不能让他一直加载到内存里呀,因此资源层还需要处理运行时的资源加载与卸载。
在Runtime Manager中这些asset各自拥有各自的指向关联在一起。
对于资源的管理需要对以下几个方面进行平衡
执行一次tick,就是将游戏里的所有模块逐步执行一遍。在现代计算机强大的计算能力基础之上,每隔1/30秒执行一次tick,将游戏的逻辑和绘制跑一遍。
通常Tick分为两个功能:逻辑Tick与渲染Tick。
在游戏中,我们先将游戏场景模拟出来(ticklogic),再进行渲染(tickrender)。
TickLogic一般做的是:
- 读取输入输出
- 计算世界物理信息
- 移动camera,角色和物体
- 碰撞检测等
- 以及各种游戏玩法的事都属于逻辑,比如角色A打到了角色B,因为不管看没看见,A都打到了B并造成了伤害
现代计算机CPU为多核处理,因此引擎根据这一特性进行多线程计算。比如Logic和Render我们分配到不同的线程中执行,甚至再多开一个线程来执行加载。
在普通的ticklogic和tickrendering里只需要简单的线性代数计算,但是我们仍需要重新写数学库,这是因为游戏引擎是一个实时的东西,因此我们需要高效的计算。
原生语言通常会有自带的数据结构,但其中的实现通常不够高效,并且难以拓展。因此游戏引擎经常会自己实现一些底层数据结构,使得几乎没有内存碎片,而且访问效率高。
游戏引擎的内存管理十分接近操作系统。游戏引擎的内存性能瓶颈:
内存管理的目的是为了让计算机更快速的处理:
- 把数据放在一起
- 尽可能按顺序访问数据
- 尽量一起读写数据
平台层存在的意义是为了让你可以无视平台的区别,把平台的差异度掩盖掉。
不同平台的文件路径格式不一样。
对于图形API来说,有OpenGL,DirectX,Vulkan等,需要一个RHI(Render Hardware Interface)封装各个平台的SDK的区别
工具层的意义是为了让别人使用以地图编辑器为主从而形成的一系列编辑器来帮游戏添加或修改内容。
编辑器能及时的实时在我们的游戏引擎中调整效果,保证我们在引擎编辑中看到的效果和实际游戏运行起来的效果一致,提升开发效率;
工具层的代码量占的比例很多。