Games104 总结
02 引擎架构分层
引擎架构包含以下几层:
- 工具层
- 功能层
- 资源层
- 核心层
- 平台层
工具层
工具层是面向引擎使用者的。它提供一系列接口,以让引擎使用者可以使用该引擎上手制作游戏。通常包括地图编辑、材质编辑等。
功能层
功能层负责实现游戏的核心玩法。为了模拟游戏场景中的行为,现代游戏引擎一般都使用 “tick“ 这一概念。每经过一个小时刻就执行一次循环。也就是说,游戏世界的时间是不连续的,离散的。
每一个 tick 中我们通常需要做两件事:
- 帧逻辑。一般就是这一帧的模拟。在 3D 引擎中包括物理计算等。也包括玩家的输入输出,数据计量等。
- 帧渲染。逻辑计算完后,该帧所有资源的渲染信息都确定了,于是需要将图像渲染到屏幕上。
资源层
资源层的重要任务之一:将资源导入引擎。
将数据引擎化类似于将 word 变为 txt 的过程——我们只保留可编辑部分,对其他文件格式导致的附加内容进行裁剪。
资源层的重要任务之二:资源的关系组织。
这一点类似于文件系统。一个完整的资产通常包含材质、mesh、贴图、shader 等多个属性。为了让这几个资产组织起来,需要另外一个 composed asset. composed asset 本身也是资产之一,是引擎的 reference 特性的体现。为了为每个资产一个唯一标识,我们还需要引入GUID.
UI 层面上,我们还需要一个资源管理器。这也与 Windows 的文件管理器类似。
而在资源层之外,游戏执行的核心之一即管理资产们的生命周期。
核心层
核心层通常写一些支持其它层调用的底层接口。
包括线性代数库、数据结构等。
为什么需要自己的一套数据结构?以 C++ 的 std 为例,vector 的空间分配为段式,在性能要求非常高的游戏开发中可能会导致许多不必要的内存分配。
一个很好的轮子:electronicarts/EASTL,EA 为解决 C++ 引擎开发中的性能问题而诞生。
还比如一些对象池之类的功能。把内存管理好,把性能提优,都属于核心层的使命。
平台层
这一层主要是为了跨平台而存在。虽然不是完全必要,但一个只能在单平台使用的现代引擎未免太不合格。
而不同的平台,对不同的图形 API 兼容又各不相同。因此我们需要一层 RHI,将这些硬件 SDK 封装起来。
除此以外也有很多其他的兼容问题……
(当然对个人 toy 引擎来说,支持跨平台确实有点过于复杂)
03 构建
ECS 架构
使用 Composed-based Tick 要优于 Object-based Tick. 以 pipeline 的形式更适合数据整合批处理。
interactions 实现
Hardcore:GO 间通信,GO 互相调用、生成。这一方法也可以在 Scripts 中写出,
更优秀的方法包括射线检测,Events系统。
interactions 优化:四/八叉树
BVH 层次包围盒
引擎 demo 功能
04 渲染(1)
光栅化 pipeline
略
纹理采样
在有 mipmap 支持时,一种能达到比较好的 sample 方案是:采取最近的两级 mipmap,分别进行双线性插值采样,结果再线性插值合成。
Mesh
一个 mesh 必须包含:
- vertex data
- index data
- face (triangle/octangle) data
Optional 的:
- normal data
- uv data
- color data
- …
相应地,引擎需要为 mesh 的应用,在内存中提供 buffers,例如 vertex buffers、index buffers……
为了方便 Mesh 的树级管理,各个部件应用不同的 material,引擎一般都有 Submesh 的概念。不同的 submesh 使用 mesh 的不同组顶点。
Materials
决定 shading 效果的组件。
一个 material 必须包含:
- shader
可以包含:
- texture (PBR)
- albedo
- normal
- metallic
- roughness
- AO
Resource Pool
通过索引提高资源重用率。而为了重用并且保证不同组件被识别为不同,引擎通常都有 instance 的概念。通过资源索引创建一个 instance。
视锥裁剪
除了普通渲染器提供的齐次裁剪以外,会渲染更多 object 的 game engine 需要更多样化的裁剪来确保性能,例如 GPU culling
纹理压缩
DXTC
ETC/PVRTC
新技术:Cluster-Based Mesh Pipeline
由显卡支持,可以用一个算法,基于数据生成几何。
一个有名的 further work: Nanite