【GAMES104学习笔记】简介+引擎架构分层+游戏世界构建

一、笔者前言

笔者大学期间涉猎过Unity的Gameplay游戏逻辑开发、Shader开发、Blender建模,也啃过Vulkan API实时硬件光追、渲染管线和一些图形学知识。近期希望能够系统学习引擎开发的知识,于是有了这个笔记博文系列。欢迎志同道合的大佬前来交流,笔记中如有错误和疏漏,敬请指正!

二、引擎架构分层

游戏引擎自顶向下分为:

  • 工具层(各种编辑器的操作)

  • 功能层(渲染、动画、物理、交互、脚本AI、状态机)——最为庞大复杂

  • 资源层(文件、数据)

  • 核心层(复用的底层代码,包含数学库、数据结构等)

  • 平台层(不同用户平台)

所有层都可以植入第三方库/中间件

工具层

编辑器、DCC数字内容创建(Houdini MAYA 3dsmax blender)

资源层
Asset

资源层导入各种外部资源(模型、贴图等)时,需要转换成统一的形式以降低时空代价(例如通过删除原始资源的一些编辑信息节约空间),称为Asset。

GUID

对每个Asset设置的全体唯一识别号

Runtime Asset Manager

实时运行的Asset管理器,通过handle系统管理Asset的生命周期

Tick

游戏世界动起来的基础,先计算逻辑帧,再计算渲染帧,也有可能多线程并行(逻辑线程和渲染线程)

void tickMain (float delta_time) {
  while (!exit_flag) {
    tickLogic (delta_time) ;
    tickRender (delta_time);
  }
}

void tickLogic (float delta_time) {
  tickCamera (delta_time);
  tickMotor (delta_time);
  tickController (delta_time);
  tickAnimation (delta_time);
  tickPhysics (delta_time);
}

void tickRender (float delta_time)
{
  tickRenderCamera();
  culling();
  rendering();
  postprocess();
  present();
}
核心层
数学库

重点是数学计算速度,精度是其次的。

Quake III引擎采用魔数+牛顿迭代法获得远胜sqrt库的效率;现代处理器采用SIMD(单指令多数据流)提高形如sqrt等专用计算的计算速度。

数据结构与内存管理

需要手动实现相关数据结构以获得优于C++ STL容器的特定优化性能。

平台层
图形API(RDI 渲染硬件接口)
  • 透明化不同的GPU架构和它们的SDK

  • 目标平台自动优化

三、游戏世界的构建

由如下几种GO(Game Object)组成

  • 动态物体(可交互)

  • 静态物体

  • 环境(天空、植被、地形)

  • 其他(空气墙、检测体)

Tick的计数方式根据划分方式,有两种

  • Object-based Tick 以GO为单位(每个流水线生产一个汉堡包),简单且易于调试
  • 推荐——Component-based Tick 每个流水线仅生产汉堡包的某一组件,有利于并行处理、减少缓存不命中,更高效
Events

原始的switch-case实现交互逻辑不利于拓展,称之为hardcode。

使用事件系统,有利于解耦、扩展。

场景管理——空间数据结构

管理一个场景中的所有GO,通常用到独特的GO标识符以及GO位置。场景管理的核心是空间数据结构。

GO之间的检测交互,最简单粗暴得每个GO遍历所有GO O(n^2),显然效率太低,于是有下列空间数据结构:

  • BVH(Bounding Volume Hierachies)——更新代价较小
  • BSP(Binary Space Partitioning) 二叉树——更新代价较大
  • Octree 八叉树(适用于3D场景,每个正方体可以等分为八个小正方体)
  • Quadtree 四叉树(适用于2D场景)
  • Scene Graph 场景图
时序问题

GO绑定、组件依赖

例子:A碰撞B时,B受到A的作用作出响应,A也会受到相应的反作用,可能形成循环依赖。

解决办法:适当采用preTick postTick Lag等控制物体交互响应,防止所有互动在当前tick运算造成的死锁。

例子:FPS精彩回放实际上是模拟玩家输入重新运行一遍游戏。

问题:玩家网络并发输入时,由于输入顺序可能改变,会出现异常。

解决办法:引入邮筒(类似于消息队列)存储并发输入的事件,保证时序的一致性。

Tick时间过长怎么办?
  • 后续tick运算出结果时进行补偿
  • 跳帧(比较危险 )
  • 对于突发的互动剧增场景(爆炸物理),可以采用每帧分批运算一定数量的GO

你可能感兴趣的:(GAMES104,笔记,架构,游戏引擎,图形渲染)