腾讯游戏开局一课——客户端

tiny_star Lv3

记录参加腾讯游戏开局一课——客户端方向学习内容,也算 C++ 一个方向😜

学习

技术栈

  • 核心层:C++ 编程,数据结构与算法,计算机图形学
  • 应用层:Unity / Unreal Engine,渲染管线,物理引擎,网络同步
  • 工具层:Git 版本管理,性能分析工具,热更新系统,自动化构建

学习路线

必备基础

  1. 编程语言
    C++ (核心,必须精通):STL、内存管理、多线程
    C#(Unity项目)
    Lua / Javascript(脚本层)
  2. 数据结构与算法
    数据结构:基础:数组、链表、树、图
    进阶:空间分区(四叉树、八叉树)
    算法:排序、搜索、动态规划
  3. 计算机图形学
    渲染管线基础
    光照模型、纹理映射
    矩阵变换
  4. 网络编程
    TCP / UDP 协议
    C-S 架构
    网络同步基础

进阶技能

  1. 性能优化思维
    CPU:算法复杂度、缓存优化
    GPU:DrawCall、Shader 优化
    内存:对象池、资源管理
    网格:压缩、预测
  2. 引擎源码阅读
    Cocos2d-X 源码分析
    Unreal Engine 源码
    ORGE 架构理解
  3. 跨平台开发
    iOS / Android 原生接入
    GPU 架构适配
    性能差异处理
  4. 工具链开发
    编译器扩展
    自动化构建
    调试工具

比赛

Game Jam

学习资源

书籍

《游戏引擎架构》
《realtime rendering》(图形学圣经)
《C++ Primer》
《Effective C++》

在线课程

Unity 官方教程
Unreal 学习路径
Stanford CS148(图形学)

开源项目

Cocos2d-x
Godot Engine
OGRE

社区论坛

Unity 官方论坛
Unreal 官方论坛
GameDev.net
Emacs-china

游戏团队典型结构

一款游戏有一个总体的制作人,制作人下面会有三个团队(程序,美术,策划),还有PM(项目经理)

downloaded-image

UE入门

游戏引擎简介

常见游戏引擎

UE(Unreal Engine)
Unity
Cry Engine
Open 3D Engine
Source2
Frostbite Engine
Naughty Dog Game Engine
Rockstar Advanced Game Engine

游戏引擎:专门为游戏而设计的工具及科技集合
Game engine are data-driven architectures that are reusable and therefore do not contain game content
特点:通用性与偏向性 可扩展性 完善工具链

书籍《Game Engine Architecture》(Jason Gregory)

游戏引擎典型架构

image-20251205103946598

游戏引擎:渲染

  • Deferred Renderer
    编译器、PC、Console 默认渲染管线
    Feature levels “SM4”,“SM5”
  • Forward + Renderer
    用于桌面 VR 游戏,支持 MSAA
    Feature Level “SM5”
  • Mobile Renderer
    Forward Render,Deferred Render
    Feature levels “ES2”,“ES3_1”,“Vulkan”

书籍《REAL-TIME RENDERING》
课程:GAMES101-现代计算机图形学入门-闫令琪
GAMES202-高质量实时渲染-闫令琪

渲染模式
Immediate Mode Rendering
Tile Based Rendering
Tile Based Deferred Rendering

游戏引擎:物理引擎

Havok

  • Physics、Destruction、Cloth、AI、Behavior、Animation、FX
  • 被 Intel、微软收购,CPU友好
  • https://www.havok.com/

PhysX

Bullet

物理引擎包括的内容
碰撞检测 动态约束 刚体物理 车辆物理 布娃娃系统

Chaos in UE 实时电影效级的大范围破坏

UE(Unreal Engine)引擎

背景介绍

对射击类游戏的支持非常完整,适合开发射击类游戏

学习资料
Youtube UE官方账号学习资料
Bilibili UE官方账号学习资料
知乎 UE官方账号学习资料

Launcher(启动器)

编辑器使用

项目结构

image-20251223201702643

所有代码在 Source 下面,所有资产在 Content 下面,所有配置在 Config 下面

World 世界
世界场景(World)中包含载入的关卡列表。它可处理关卡流送和动态 Actor 的生成(创建)
Level 关卡
level(关卡)是用户定义的游戏区域
主要通过放置、变换及编辑 Actor 的属性来创建、查看及修改关卡
在虚幻编辑器中,每个关卡都被保存为单独的 .umap 关卡,也被称为“地图”
Sub-Levels
A small area of the whole Map
Decouple the work between artist and designer
Actors
可放入关卡中的对象都是 Actor
Actor 是支持三维转换(如平移、旋转和缩放)的泛型类,通常包括一个或者多个 Actor Components
可通过游戏进程代码(C++或蓝图)创建及销毁 Actor
在 C++ 中,AActor 是所有 Actor 的基本类
Don’t have Location, Rotation (stored in root component)
Created with SpawnActor() Method
Must be destroyed explicitly with Destroy() method
Component 组件
Actor 本身是一个空壳,它是没有任何的功能性的,它的功能需要通过 Component 来实现
组件(Component)是可添加到 Actor 的一项功能
组件不可独立存在,但在将其添加到 Actor 后,该 Actor 便可以访问并可以使用该组件所提供的功能
Reusable functionality that can be added to an Actor
Contain the most interesting functionality & events

源码构建

获取:GitHub 账号绑定 EpicGame 账号

image-20251223203852771 image-20251223203916063

UE编程技巧

游戏框架

image-20251226230001853

GameMode 游戏模式
游戏模式(GameMode)类负责设置正在执行的游戏的规则
规则可包括玩家如何加入游戏、是否可暂停游戏、关卡过渡,以及任何特定的游戏行为(例如获胜条件)
GameState 游戏状态
游戏状态(GameState)包含要复制到游戏中的每个客户端的信息,它表示整个游戏的”游戏状态”。它通常包含有关游戏分数、比赛是否已开始和基于世界场景玩家人数要生成的AI数量的信息等等
PlayerState 玩家状态
玩家状态(PlayerState)是游戏玩家的状态,非玩家AI将不会拥有玩家状态
在玩家状态中的数据包括玩家姓名或得分、当前等级或生命值等
Pawn 兵卒
Pawn是Actor的一个子类,充当游戏中的生命体
Character 角色
角色(Character)是Pawn Actor的子类,用作玩家角色
角色子类包括碰撞设置、双足运动的输入绑定,以及由玩家控制的运动附加代码
PlayerController 玩家控制器
玩家控制器(PlayerController)类用于在游戏中获取玩家输入并将其转换为交互
玩家控制器通常拥有一个Pawn或角色作为游戏中玩家的代表

引擎工具

日志

可视化日志
https://www.unrealengine.com/zh-CN/blog/using-the-ue4-visual-logger

内置控制台
Stat FPS(显示帧数)
t.MaxFPS 1000(最高帧率限制到1000)
Stat UNIT(对游戏线程,渲染线程,GPU耗时进行统计,分析瓶颈)
Stat GAME(对游戏各个模块的tick耗时进行统计)
Stat SceneRendering(渲染基本信息统计,可以看DrawCall数)
Stat Engine(渲染信息统计,可以看三角形数量)
Stat lnitViews(可以看到视口剔除的三角形数量)
Stat RHI(可以看到所有的DrawCall)
stat startfile,stat stopfile
Windows平台:工程文件/Saved/Profiling/UnrealStats文件夹下自动保存性能分析文件
Window->Developer Tools->Session FrontEnd->Profiler->Load打开分析文件
调试相机
输入命令freezerendering可以冻结当前帧的渲染
输入命令toggledebugcamera可以自由移动相机
show bounds可以显示没有被culling掉的物体的包围盒

GPU工具
RenderDoc
RenderDoc是一个独立图形调试工具,已经内置于UE4,可以对游戏进行单帧捕获和详细分析

Unreal Insight

UMG界面

UI实现

什么是UI
UI是“用户界面”(User Interface)的缩写,指的是用户与设备、软件或应用程序进行交互的界面。UI设计的目的是让用户能够直观、便捷地使用系统和功能。UI不仅包括按钮、图标、文字、菜单、颜色、布局等视觉元素,还涉及用户与系统之间的交互方式

游戏的UI
游戏UI通常需要更注重沉浸感视觉冲击力,在传递信息的同时还要增强玩家的游戏体验。且游戏UI更侧重于动态性交互性,例如生命值、分数、任务进度等信息经常需要实时更新。此外,游戏UI设计通常与游戏的整体美术风格、主题和情节紧密结合,以确保其与游戏世界的风格一致,创造更沉浸感的体验

UE中的UI界面
Unreal Engine作为一款世界顶级的、实时3D创作工具。它不仅用于制作3A级游戏,还广泛用于影视动画、建筑可视化、汽车设计、模拟训练、元宇宙等领域
作为一款顶尖的成熟游戏引擎,UE也有提供完备的游戏UI制作工具和运行框架


SlateUI 与 UMG
在虚幻引擎中,UI实现一般有两种方式
1)Slate UI
Slate 是虚幻引擎底层的 UI 框架,用于构建和管理用户界面。用以提供高效、灵活的 UI 元素构建和渲染。Slate 是虚幻引擎中所有 UI 的基础,很多 UI 的核心功能都建立在 Slate 之上。Slate 框架非常强大,但它的使用相当较复杂,开发者需要编写大量的 C++ 代码
2)UMG 控件蓝图
UMG(Unreal Motion Graphics)是虚幻引擎的可视化UI工具,基于Slate构建。它通过可视化的蓝图系统让开发者和设计师可以不需要编写C++代码,便捷地构建和管理游戏中的UI界面。同时UMG还提供了较为简单的UI编辑,以方便高效的制作UI界面及动画表现

UMG功能简介

创建UMG控件蓝图
和创建普通蓝图的方式类似,在编辑器中的内容浏览器任意位置右键点击后即可使用下拉菜单进行创建

UMG 编辑器-设计器
UE 引擎提供了完全可视化的编辑方案,以便进行高效的 UI 制作,可以看到设计器(Designer)视图下有如下面板:
面板:整个 UI 的可视化呈现,即所见即所得
控制面板/库:可添加到 UI 中的组件列表
层级视图:用于展示当前正在编辑的 UI 中的组成元素和层级关系
细节面板:用于调整 UI 元素的属性(例如位置信息、材质、颜色等)
绑定控件:显示当前绑定到 C++ 变量的蓝图控件或动画
动画轨道:用于编辑控件动画

UMG 编辑器-图表
这里控件蓝图与普通蓝图类似,可以在图表中使用蓝图可视化编程实现功能

控件蓝图的制作与使用

UMG蓝图制作要点
为了呈现同时具备功能性和美观性的游戏UI,控件蓝图的制作一般会涉及以下几点:
元素展示:通过图片、文字等内容,直观的展示UI需要表述的信息
交互体验:使用按钮、滑动条、输入框等交互元素获取玩家输入以达成交互功能
布局调整及适配:通过合理的布局以美化UI整体效果
动画效果:动画效果的实现对于可以进一步提升UI的美术效果
功能实现:以代码驱动UI的整体运行
通过 C++ 操控 UMG 控件蓝图:绑定控件事件
创建HUD类并在GameMode中设置以用于展示UI

UMG进阶技巧

容器与slot
前面我们粗略地讲解了布局控制相关的控件使用,这里引入一个相关的重要概念,slot

刷新函数绑定
需要频繁变更的内容,可以采用binding的方式控制其变化,需注意性能问题

主动刷新
为了更好的性能,可以通过事件绑定的方式实现主动刷新,需注意生命周期

游戏物理基础

游戏为什么需要物理

游戏引擎架构中的物理

image-20251230100125129 image-20251230100312607

碰撞检测与场景管理

构成虚拟物理世界的主要元素 碰撞几何体

AABB、OBB
Capusle
Triangle
TriangleMesh
HeightFieldMesh

两个碰撞体之间的碰撞
距离和相交测试

N个碰撞体之间的碰撞
BoradPhase(粗略阶段)与 NarrowPhase(精细阶段)
需要能够加速查询场景信息的结构

场景管理

特点 动态性 性能比较 适用场景
BSP 二叉树基于平面划分 静态 早期游戏静态场景
BVH/BVT 二叉树基于包围盒划分 动态 物理引擎场景管理
KDT 静态
八叉树 大范围查询快,小范围查询慢 动态 渲染的场景管理
均匀网格/稀疏网格 小范围查询快,大范围查询慢 动态 超大空间动态场景、物理引擎场景管理

刚体物理学

线性速度(Linear Velocity)
位移运动
力(Force)
F = m * a(Force = Mass * Acceleration)

角速度(Angular Velocity)
旋转运动
力矩(Torque)
τ = F * r(Torque = Force * distance)

引力
全局引力
单个刚体引力

阻尼

物理材质

刚体动力学(kinematic rigid body)

连续式碰撞检测(CCD)

Sweep-based CCD
原理
根据线性运动估算碰撞时间(Time of Impact)
限制
不考虑角运动,旋转的刚体依然出现穿插问题

Speculative CCD
原理
根据线性与角运动计算出移动的包围盒,找出所有的接触点再进行解算
限制
导致幽灵碰撞,因为推测式CCD是基于最近点算法采集所有可能的接触点,所以接触法线的精度较低

关节(Joint)
Fixed Joint
Spring Joint
Hinge Joint

布娃娃(ragdoll)

载具系统

破坏系统

什么是物理破坏
视觉上,场景中的物体发生了拓扑的变化
基于物理规律,一变多,并与场景进行交互
可以与玩法结合
增强场景的视觉效果,提高游戏品质
性能挑战

物理破坏原理
Offline 阶段
资源:箱子模型、模型碎块
程序剖分
美术制作
设置物理参数
箱子受到撞击时,每个碎块所受外力
设置碰撞体
碰撞体:Box(箱子)、ConvexMesh(碎块)
Online 阶段(当球撞击箱子时)
未受到撞击的箱子:作为单个GameObject参与物理计算,与场景进行交互
受到撞击的箱子
计算每个碎块所受到的撞击力
更新碎块的位置
碎块与场景进行交互

引擎中的物理破坏
支持破坏的物理组件
Unity:Fracturing & Destruction 插件等
UE4:Apex、Blast、Chaos
模型资源准备:
提供丰富的模型剖分方法
Online:
更符合物理规律的破碎方式
高效的场景管理
并行计算
物理引擎中模型剖分
剖分方法(Fracturing & Destruction 插件)
Voronoi 空间划分
BSP 方法(二叉空间划分)
Chunk(碎块)
连通信息
碰撞体

优点
易做出酷炫的效果
缺点
性能压力
内存压力(内存随面积增长、模型本身剖分)
不易与玩法结合

柔体仿真

游戏中的布料仿真
基于动画的布料运动
巨大的工作量
布料状态不自然
基于物理解算的布料运动
自然的布料状态
性能挑战
物理引擎中的布料系统除了可以表现布料效果,还可以应用于毛发、坠饰等其他柔性体的仿真
基础知识
几何模型
三角形网格或四边形网格
模型顶点越多,仿真效果越好
每个顶点包含三维的位置x和速度v
在仿真过程中,在约束的条件下,x和v不断发生变化
物理模型
定义布料的属性
不同的参数,表现不同的布料材质
需在仿真计算前,预先设置
基于力的物理模型
顶点受力:外力(重力、风力等)和内力(弯曲力、拉伸力、错切力等)
例:质点-弹簧模型
牛顿第二定律 F = ma
基于约束的物理模型
顶点受力:外力(重力、风力等)
位置约束:距离约束、弯曲约束等(等式或不等式)
求解多个方程组
例:Position-based Dynamics (PBD)
时间步长
物理仿真计算
位置更新计算:力、牛顿第二定律(基于力的模型) 位置约束的求解(基于约束的模型)
碰撞处理计算:碰撞检测 碰撞响应
碰撞类型
布料的自碰撞
布料与其他模型之间的碰撞
在布料仿真中,碰撞检测响应是性能瓶颈,需要优化算法
碰撞响应
调整发生穿插的碰撞体,减少穿插
输入:碰撞点、穿插深度、穿插法向
基于骨骼的布料仿真
代表插件:
Unity 的 Dynamic Bone 插件
Unity 的 Spring Bone 插件
Spring Manager(Spring Manager.cs 脚本)
控制所有Spring Bone的计算
Spring Bone(Spring Bone.cs 脚本)
控制单条骨骼的计算
Spring Collider(Spring Collider.cs 脚本)
碰撞体
资源准备
带骨骼链的布料模型
需要特殊的美术制作
Offline阶段
为参与计算的关节点添加Spring Bone
为角色添加Spring Manger,并将上述关节点加入其中
设置物理模型参数:表现不同的材质效果
设置碰撞体
关节点处的碰撞体
角色身体上的碰撞体
关节点处添加Spring Collider
碰撞关系
Online阶段
仿真流程
image-20251230135403064
时间积分
更新关节点的位置
关节点受力->关节点的加速度->关节点的速度->关节点的位置
主流方法:Verlet积分、显式欧拉积分
碰撞处理
碰撞检测
关节点处的碰撞体与角色碰撞体的碰撞测试
不支持自碰撞检测
碰撞体:球、胶囊体
碰撞响应
根据穿插深度和方向,调整碰撞体位置,继而影响关节点的位置,从而影响柔体的形态
优点
高效,制作流程简单
缺点
模拟效果不够好,容易发生穿插
基于网格的布料仿真方法
直接对网格的顶点进行物理仿真计算
物理引擎:PhysX、Bullet等
游戏引擎:Unity Cloth组件、Unreal4 Cloth组件等
Unity Cloth组件
物理引擎:PhysX
需配合Skinned Mesh Renderer使用
可以实现更细腻的效果
性能差
资源准备
网格模型
通常为FBX文件
三角形网格
Offline阶段
对于网格的每个顶点
设置物理参数
重力
Damping
额外的加速度
设置约束参数
Stretching Stiffness
Bending Stiffness
是否使用Tether约束等
Cook:构建位置约束
Stiffness:表示约束作用强度。数值越大,约束越强;数值越小,约束的作用越小
Online阶段
仿真流程
image-20251230133355457
碰撞检测
自碰撞
Self-intersection radius
Self-intersection stiffness
布料网格与其他模型之间的碰撞
碰撞体:球
约束求解
求解等式和不等式
可配置参数:Solver Frequency(120~300)
迭代次数越多,效果越好,性能越差
优点
效果更好
缺点
运行效率稍差
制作相对比较复杂

游戏中常见物理中间件介绍

2D
Box2D
SG Physics2D
Godot Fixed point

3D
Bullet
Havok
PhysX
Chaos in UE

Fate

References

清华-腾讯 IMDT 课程
游戏引擎架构(第2版)
https://developer.nvidia.com/physx-sdk
https://www.havok.com/havok-physics/
https://github.com/bulletphysics/bullet3
https://box2d.org/
https://github.com/snopek-games/sg-physics-2d

游戏网络同步技术基础

网络基础概念

网络分层模型
OSI七层模型
TCP/IP四层模型

伯克利套接字
在应用层和传输层之间通讯的标准接口(Berkely Sockets API)

传输层协议
UDP/TCP

网络拓扑结构
Peer2Peer
ListenServer
Client-Server

同步内容

网络同步核心目标
达到体验的一致性
根据玩法需求
高及时性
低及时性

游戏程序分层结构
输入模块
手柄、摇杆、鼠标、键盘、触摸屏……
屏幕触摸事件
核心逻辑模块(GAMEPLAY)
游戏规则、逻辑事件、逻辑状态……
输入:玩家移动
逻辑:移动规则
状态:玩家状态、游戏状态
输出控制模块
基于个人视角的:视图状态、渲染指令……
场景和镜头管理、渲染指令组织、音效控制
输出模块
渲染、混音……
画面渲染、混音输出、震动马达驱动

同步内容
不同的同步内容,决定不同的同步方案,以及不同的网络架构
image-20251230140955928
同步控制流
image-20251230141052698
同步状态流/事件流
image-20251230141135947
同步视频流
image-20251230141214758

两种主流同步模型:帧同步-同步控制流 状态同步-同步控制流/事件流

锁帧同步模型

基本原理
给定一个确定的输入,就会对应一个确定的输出
同样的函数->同样的输入->同样的输出
输入模块 = 函数输入
核心控制模块 = 函数
输出控制模块 = 函数输出
输出模块 = 黑板

image-20251230141827407

模块结构

image-20251230145416359

输入的一致性
操作集合在时间轴上一致性
逻辑时间与自然时间

逻辑的确认性
浮点数
降低精度的浮点数
定点数
经过验证的相关开源工具
Fate
物理引擎及数学库
LogTrack
一致性诊断工具
逻辑状态的确定性
仅使用整数或者定点数来表达状态
逻辑过程的确定性
仅使用基于整数和定点数,并且算法
一系列功能库
基于定点数的玩法框架
基于定点数的行为树
基于定点数的“蓝图”
基于定点数的物理引擎,等等
表现与逻辑分离
表现层不可修改逻辑层
逻辑层不可依赖表现层
最容易忽略的地方——
逻辑层没有主角的概念
谨慎使用多线程

古典锁步同步

image-20251230163125554

现代帧同步

image-20251230163203764

优化-断线重连恢复
短单局
直接快速追帧(实)
长单局
结合状态同步
先将整个核心逻辑模块直接恢复到最近的状态
完全状态同步:内存快照技术
再从该状态追帧

优化-安全与反作弊
安全
协议加密:DES、AES、TER/XTEA/XXTEA
自有认证:帧同步独立的权限认证
包防篡改:奇偶校验
安全数据类型:SDT
反作弊
实时校验
战斗中的异常情况进行数值校验
战斗中的实时逻辑校验
结算校验
对单局结果进行数值校验
如有异常,进行逻辑校验
用户画像
识别作弊
逻辑校验服务器

优化-网络抖动
JitterBuffer:通用的解决办法
优点:实现简单,业务无关
缺点:损失实时性
优化:动态调整Buffer大小

优化-移动预表现(示意图优化)
交互性操作/非交互操作

实际案例:FSPLite
FSPLite
一个轻量的帧同步网络模块

优点
服务器逻辑简单,负载低
整体研发周期短
表现一致性高
同步流量小,带宽成本低
快速支持观战、录像、回放等功能
具有通用性

缺点
反外挂问题严峻
网络延时敏感度高
不同步问题较难定位和解决
单局规模受限
技术门槛高

应用场景
单局规模适中
不会中途加入角色
实时性要求较高

状态同步模型

基本原理
通常有3种方式来实现共同状态的同步

image-20251230200352175

实际项目中,方式1和2经常结合起来使用,方式3是2的一种极端特例
另外,1和2与具体玩法强相关,3与具体玩法弱相关

模块结构

image-20251230200710315 image-20251230200810848

状态的一致性
根据是否影响核心博弈结果
核心一致性:异步交互 单点仲裁 实时同步
非核心一致性:多点仲裁 延迟同步
冲突问题
事件冲突
比如2个玩家拾取同一个道具…
状态冲突
比如玩家移动到指定地点失败
解决办法
单点仲裁
关键逻辑
仲裁问题
回溯判定
服务器的玩家状态 [位置]有延迟
射击指令有延迟
服务器回溯射击 [发生当时]的状态,进行判断
时钟同步
Network Time Protocol(NTP)算法

优化-客户端插值
客户端平滑状态之间的变换

优化-客户端预测
预测函数
定义[实现]状态预测函数
一般用于移动预测
航位推测[Dead Reckoning]
基于假设:实体继续在做当前正在做的事情
利用现在物体位置/速度/加速度/角速度等等尽可能多的参数,推定未来位置方向的航海技术
容易受到误差累积的影响,通过以下方式修正:
即时状态更新、
插值、
二阶状态调整

优化-视觉掩饰
前摇
掩饰本地输入到生效期间的网络延迟
提供各接受方等待缓冲时间
后摇
提供“确定性”,提高预测精度

优化-同步范围与相关性
静态区域
将世界划分为一些静态区域
只有和玩家在同一区域的对象才同步
视锥、距离、与可见性

优化-同步频率与优先级
同步频率与相关性正相关
同步频率与优先级正相关
事件同步的优先级高于状态同步
通过休眠状态主动控制频率

优化断线重连
直接从服务器恢复状态
服务器保持关键状态,或者全部状态
怎么恢复:曾经同步过的游戏事件?

优化-安全与反作弊
安全问题:
协议破解/攻击
敏感数据滥用
解决办法:
延迟敏感的状态:则本地维护状态,服务器后校验
延迟不敏感状态:则服务器维护状态
服务器限制不必要的数据同步
设置天花板阈值
用户行为分析,识别作弊

实际案例-UE4Replication
基本流程
For every <Actor> need to replicate
For every <Property> in <Actor>
Compare current data [offset] with previous data [ShadowOffset]
Check [Properties Are ldentical]
Add to [Changelist] if not same
Push changelist to send buffer
Gather<RPC> info
Push to send buffer
Send buffer
ReplicationGraph
利用层级/网格状的静态区域来管理Actors
区分管理不同同步频率的Actor
复用上一次AOI同步之后积累的信息
通过对休眠/唤醒的检测,灵活区别Actors的同步与否
ReplicationGraphNode
按空间划分:
UReplicationGraphNode_GridSpatializeation2D
UReplicationGraphNode_GridCell
按同步频率划分:
UReplicationGraphNode_ActorListFrequencyBuckets
按同步对象划分:
UReplicationGraphNode_ActorList
UReplicationGraphNode_AlwaysRelevant_ForConnection

优势
客户端计算量小
网络敏感度低
技术门槛低

劣势
流量消耗大
达到复杂逻辑一致性的难度很高
后期维护成本高
很难通用化[UE4Replication改善了这一点]

常用品类
射击、赛车、RPG、三消休闲等

通用优化技术

协议优化
选TCP还是UDP?
UDP

优点 缺点 应用案例
ARQ 算法简单、应用场台广泛、有通用的实现方案 最小丢包延时较高=7.7~2*RTT LWIP,KEP
FEC 最小丢包延时较低<=7.5*RTT 算法复杂、通用性受到限制 FSP 〔Lockstep], UE4 [Replication]

进一步优化:ARQ-FEC
去掉非常复杂FEC确认逻辑
实现算法非常简单
用于小型项目的帧同步实践
可以参考开源库:FSPLite
https://github.com/slicol/5GF

UDP分组优化
UDP分组:
将一个UDP大包分成几个UDP小包进行发送·当UDP包大小超过链路层的mTU时:
将会发生lP分片-重组
增加丢包概率

随机丢包优化
丢包规律
相关性丢包
原因
链路拥塞
路由器负载过高
无线信号衰减
基站&场景切换
特点
它是有原因的
随机性丢包
原因
二进制信道噪音
特点
无规律,随机出现
据数据统计:89%的丢包
都是这种〔2016年]
采用Gilbert Model优化

两种模型对比

要素1、公平-确定性
帧同步
具有强一致性
状态同步
非本地仲裁数据有延迟或需要修正

要素2、公平-安全性
帧同步
篡改:输入数据,状态数据
隐私:拥有所有玩家的状态
状态同步
篡改:输入数据,状态数据〔本地]
隐私:无法获取关键状态数据〔远程]

要素3、体验-实时性
帧同步
预表现
协议优化〔RUDP]
丢包优化
状态同步
预表现
协议优化〔RUDP]

要素4、体验-稳定性
帧同步
断线重连逻辑非常复杂,
需要服务器缓存所有帧数据,
发回绐重连的客户端,
从断线帧开始播放到当前帧
状态同步
服务器保存当前状态
重连客户端使用服务器状态

要素5、开销-流量
帧同步
总体同步流量少
空帧优化
状态同步
总体同步流量大
AOI优化

要素6、开销-计算量
帧同步
所有客户端都维护全部的计算量
状态同步
只维护本地计算量

要素7、开销-研发成本
帧同步
技术门槛高
同步模块研发成本高
项目整体研发成本低
状态同步
技术门槛低
同步模块研发成本低
项目整体研发成本高

实践相关知识

协议栈设计
一次协议发送和接收的流程

image-20251231001101240

各层的数据格式可以归纳为

image-20251231001259955

参考TCP的Header,定义我们的会话层数据格式

image-20251231003549975

应用层的数据格式,需要根据具体的同步协议来定义
一般情况下,表现层的数据格式都会采用现成的序列化格式
比如: Json、Xml、Protobuf
当然,也可以采用自定义的序列化格式
比如:KFD,Ustruct
常用的序列化格式对比

优点 缺点
Json 可读性高,跨语言及跨平台容易,调试方便 数据量适中,序列化与反序列化性能一般
Xml 可读性高,跨语言及跨平台容易,调试方便 数据量大,序列化与反序列化性能最低
Protobuf 数据量最小,序列化与反序列化性能最高 可读性低,跨语言及跨平台性差,调试不方便
自定义 可以结合Protobuf与Json的优点 开发成本高

协议加解密
一般都采用对称加密,比如常用的:
DE5
AE5
TEA [XTEA、XXTEA]
参考实现:
https://git.woa.com/slicoltang/SGEncrypt
对于高频小量数据交互加密,使用TEA就足够了

RPC
应用层协议接口的一种实现
比如,RPC[“move”,100,200,300]
对比传统的essage接:
var msg = new movemsg;
msg.x=100;
msg.y=200;
msg.z=300;
……
SendMessage[1, msg];
可以参考:
https://github.com/slicol/SGF/tree/master/SGFCore/Network/Core/RPCLite
也可以参考UE4的复杂实现

FPS游戏开发基础

FPS游戏简介

首先什么是FPS?相较于TPS和其它游戏它有什么特性和核心优势?
FPS: First-person shooter
更强的代入感与沉浸体验:游戏以第一人称呈现画面,玩家的视野与角色视野相同,角色的两只手及所操作的枪械等武器
细节在玩家面前直接展示,如玩家亲临现场
更精准的操作与射击反馈:玩家与角色视角重合,武器所带来的后坐力和操作反馈直接影响视角的变化,与玩家操作的关
联性更强
更贴合“战术与信息差”的竞技玩法:视野的限制,致使玩家无法拉动相机直接观察周围,只能通过转向,探头等操作
主动寻找目标信息,更具竞技性,对抗性,公平性

FPS游戏基础框架

FPS游戏重要元素
武器 角色 玩法

从技术角度分析
Gameplay层(Weapon 3C Gameplay)
游戏系统层(Game System)
游戏层(Game Core Third Party Library)
游戏引擎层(Game Engine)
操作系统层(Operating System)

Weapon System

FPS中常见的武器类型
按种类分:
步枪、狙击枪、手枪、手雷等
按装备位分
主武器、副武器、近战武器、投掷武器
按程序逻辑分
lnstantHit、Projectile等

关键基础组件
物理引擎
PhysX havok bullet cars

弹道模型
影响弹道的主要因素
主视角角度
后坐力
连发数
精准度
散发度
拆解弹道模型
主弹道子弹射出方向=主视角角度+后坐力+精准度+散发度
后坐力、精准度、散发度与具体武器相关,通过配置参数与公式计算得出
举例一种散发方向公式:散发方向=随机数*散发度*水平/垂直方向

3C System

3C,最早由Ubisoft提出的游戏设计概念
Character:角色,具有一定的能力或行为,玩家可以进行扮演或观察
Camera:相机,玩家通过它观察游戏世界,获得体验感和沉浸感
Control:控制,为玩家提供不同方式、不同体验的交互
好的3C系统就是对控制硬件输入响应零延迟感,对角色操作灵活,逻辑与玩家预期一致性,角色动作与相机的反馈高度协同达到1+1+1>3的效果,让玩家操作随心所欲,指哪打哪

Character技术要点
表现方面
模型 贴图 材质 动画 物理 特效 音频
逻辑方面
角色状态的设计与转换
细节问题

Camera技术要点
渲染顺序
FOV
碰撞、位置控制
屏幕效果

Control技术要点
设备与手感
什么是手感:
结合技术实现,与玩家体验双向调整,最终目标是让玩家在操作时即能感受到可控性又能获得反馈感,从而形成操作,反馈,再操作的愉悦循环
手感-手游适配问题
同样代码,iOS与Android灵敏度不同
系统响应延迟的差异,导致手感差异,可以通过灵敏度调节,安卓开启高采样率支持来尽量规避与IOS的灵敏度差异
不同Android手机,灵敏度不同
通过获取当前机型的DPI信息,通过DPI缩放,使结果与标准输入机型一致
部分Android手机灵敏度偏低
手感-辅助瞄准
手感-硬件功能
除以上所述手感因素外,要保证手感稳定且低延迟,针对从系统层获取的输入信息,开发者还需要明确数据的来源和处理阶段
CFM优化了Unity底层输入数据生成逻辑,绕过安卓Java输入事件响应的回调,直接从NDK层去获取输入信息来生成输入数据
自定义输入处理模块,不依赖UI输入响应去处理输入数据
输入模块作为一个SubSystem在所有子系统模块处理之前处理

其他技术点

网络同步
帧同步与状态同步
Peek’s Advantage

反外挂
外挂分类
定制外挂
专用插件类
so
dylib
通用工具
内存修改器
变速器
抓包工具
辅助类
按键精灵
模拟器
虚拟机
破解版
脱机挂
破解版客户端
外挂原理
透视作弊基本原理
应用层
游戏逻辑(读取逻辑坐标 修改渲染参数)
游戏引擎(读取引擎坐标 修改可见性判定)
系统层
图像渲染(修改渲染指令及过程) 声音效果(还原声源坐标)
硬件层
显卡驱动(增删显示内容) 网络通信(解密坐标协议) 内存读取(读取坐标内存)
反外挂处理
服务器校验
将服务器作为关键决策层如:伤害判断,移动位置朝向,角色属性加成,对局流程驱动及数据统计等都由服务器处理并同步
服务器数据下发
服务器数据下发校正客户端,如位置同步信息
客户端数据加密
对网络协议进行动态加密
安全组件及动态检测
接入反外挂组件:代码混淆,内存加密,游戏逻辑安全检测

性能优化
客户端优化
CPU性能优化
物理性能优化
动画优化
流程逻辑优化
Pool的使用
渲染性能优化
UI场景优化
制定制作逻辑
内存优化
合理合图
资源压缩
资源分包
流量优化
减少网络总类
合并网络包
游戏卡顿优化
预加载
分帧处理

游戏图形渲染技术基础

背景知识

计算机图形学能做什么
Video Games(游戏)
Movies(电影)
Design & Simulation(工业设计&仿真)

数学基础
向量
矩阵变换
齐次坐标矩阵变换
三角形重心坐标系

硬件图形渲染管线

GPU架构
典型的GPU架构:多处理核心少量调度核心(SIMD)
同样的运行逻辑+每个像素不同的输入参数进行计算
GPU渲染往往可以选择两种方式一种是用光栅化的方式,一种是模拟真实光照去追踪光线的走向收集结果
光栅化由于其高效性和内存访问友好性作为了实时渲染的首选接下来将以光栅化传统管线介绍后续内容

可编程图形管线介绍
输入场景 -> Application(CPU) -> Geometry Processing -> Rasterization(GPU) -> Pixel Processing -> 输出图像
渲染管线的基本结构,包含了四个阶段:应用阶段,几何阶段,光栅化阶段,以及像素着色阶段
几何阶段(Geometry Processing):
组装图元,在GPU端把三维空间的顶点变换到二维屏幕空间(透视投影,正交投影),并根据远近裁剪面进行裁剪(引入可编程顶点计算程序),朝向剔除
除了刚才的3D到2D的投影矩阵外,一般还会有这几个步骤,从局部空间到世界空间,再到投影空间,最后变换到图像空间
顶点着色可以实现的效果
如上所述几何阶段的大部分计算都是对于顶点位置相关的计算
在顶点着色器中可以实现顶点位移相关的效果,如顶点动画,骨骼蒙皮动画,平面阴影等效果
并且所有顶点着色计算是对每个顶点的
所以可以实现纹理的坐标动画,和顶点光照的计算
光栅化(Rasterization):
GPU端将投影完成的网格数据离散化成像素点
光栅化的过程是GPU帮我们做的,其实就是离散化的过程,那GPu是怎么做的呢?
光栅化有两种实现方法:1. 判断像素中心点是否在三角形内,2. 扫描线算法
像素着色阶段(Pixel Processing):
逐像素计算每个点的颜色(引入可编程像素着色程序)
可编程像素着色程序在这个阶段相当于给我们一个自定义三角形投影到屏幕后的颜色计算方式,我们可以在这个阶段定义我们自己的着色程序

图形API间接(OpenGL)
渲染硬件层接口(Render hardware interface ):
跨平台RHI,标准开放,GPU生成厂商负责实现API定义的函数接口(驱动层)
OpenGL Vulkan
好处在于多端共享
缺点在于:调试工具欠缺,平台兼容性不一定最好
平台独享API,是各个操作系统为自己单独研发的APl
Metal DirectX
好处在于平台兼容性好,运行效率高,有独享的一些特性
我们以OpenGL为例,介绍我们如何用RHI来写我们的图形程序的:
概念
模型 顶点数据(Vertex Buffer Object) 索引数据(Index Buffer Object)
定义一个最简单的可编程管线
glProgram
VertexShader FragmentShader
再了解几个可编程管线的输入接口的概念:
glVertexAttribute(0~8)对应vertex shader里的layout(location)
OpenGL最多支持同时绑定16个纹理GL_TEXTURE0 to GL_TEXTURE15
入门学习资料
OpenGL: https://learnopengl-cn.readthedocs.io/zh/latest/
Vulkan: https://vulkan-tutorial.com/
Directx: http://www.directxtutorial.com/LessonList.aspx?listid=11
Metal: https://developer.apple.com/metal/sample-code/

渲染引擎及相关性能优化策略

引擎渲染循环
应用阶段:
在CPU端识别出潜在的在可视范围内的网格数据,组织渲染命令,并根据GPU的特性,将绘制命令排序,并将其提交给GPU硬件进行渲染,这就是游戏渲染模块要处理的事情
可见性检测
可见性检测(visibility determination)找出摄像机可看的渲染物体
平截头体剔除(view frustum culling)
遮挡剔除(occlusion culling)
细节层次剔除(level-of-detail/LOD culling)
对于投影阴影的光源,也需要从光源角度找出可见的阴影投射物体
分组和排序
通常按照渲染层(layer)分组
半透明物体不能用z-buffer排序
先绘制不透明物体
之后对于半透明物体从后往前排序绘制
但是两个物体不一定有全序关系
如需要解决这一问题,需要使用次序无关透明技术(Order lndependent Transparency,OIT)
提交图元
提交图元(primitive)就是所谓的drawcall由应用阶段输出数据给接下来的阶段提交前需要设置图元数据和渲染状态
图元:顶点数据与索引数据
顶点数据通常储存在顶点缓冲区(vertex buffer,vb)索引通常储存在索引缓冲区(index buffer,ib)

前向渲染管线(Forward Shading)
前向渲染管线则不存在G-Buffer,而是针对每个物体独立绘制到最终的屏幕上

延迟渲染管线(Deferred Shading)
延迟渲染会先将场景可见的地方以G-Buffer存起来,然后再利用G-Buffer进行多次光照计算

GPU架构与管线设计
IMR (Immediate Mode Rendering)绘制模式
PC端IMR模式在DDR,CPU,GPU三者交互时会产生总线带宽开销,所以在设计PC端渲染管线时优先考虑减少这三者交互为优先
(比如GPU Driven等GPU驱动型算法)
TBR(Tile Based Rendering)绘制模式
移动端架构为Tile Based渲染模式,对绘制刷新和OverDraw更为敏感,与主存传输数据产生过多的带宽会导致发热降频
GPU架构相关的参考文档:
PowerVR Hardware Architecture Overview for Developers
http://cdn.imgtec.com/sdk-documentation/PowerVR+Hardware.Architecture+Overview+for+Developers.pdf
Mali GPU Architectures
https://developer.arm.com/architectures/media-architectures/gpu-architecture
渲染架构比较:IMR、TBR & TBDR
https://zhuanlan.zhihu.com/p/390625258
INTRO TO GPU SCALARIZATION
https://flashypixels.wordpress.com/2018/11/10/intro-to-gpu-scalarization-part-1/

渲染管线对比
适合TBR的GPU架构
前向渲染(Forward Shading) :
优点:
1.带宽消耗小
2.对MSAA抗锯齿友好
3.使用灵活
缺点:
1.多光源渲染消耗大
2.OverDraw严重
3.针对一些后期特效不友好(SSAO)
适合IMR的GPU架构
延迟渲染(Deferred Shading) :
优点:
1.绘制高效
2.对一些屏幕后期特效友好
3.多光源消耗小
缺点:
1.带宽消耗大
2.对MSAA抗锯齿不友好
3.使用不灵活

Unity 2019渲染管线介绍及使用
Unity可选管线:
Built-In Rendering Pipeline
传统的渲染管线,包含前向和延迟渲染管线,灵活性较小,但包含功能较完整,易于上手
Universal Rendering Pipeline
通用渲染管线,实际上是一个可编程的渲染管线,包含一些内置的模块,适用于有一定基础,需要对渲染模块做─定优化的用户
High Definition Rendering Pipeline
高分辨率渲染管线,用于一些影视级别的渲染,性能消耗大,只在一些特殊平台可使用
Scriptable Rendering Pipeline
高灵活度渲染管线,适用于对引擎以及渲染管线很了解的用户做定制化开发

UE4渲染管线介绍及使用
UE4针对不同平台提供了不同的渲染管线选择,相对Unity则没有那么多样性
UE4,PC端支持:
Deferred Shading Render
Destop Forward Render
UE4,移动端支持:
Mobile Forward Render
UE5:
Mobile Deferred Render

管线设计与选择
移动端前向管线一般绘制流程
绘制ShadowPass
绘制PreZPass
绘制Opaque&Mask物体
1.对物体状态排序
2.减少状态切换
绘制Translucent物体
绘制后处理
怎么解决移动端的多光源的问题呢?(最小化无用计算)
ClusterForwardLighting(Forward+)
Mobile Deferred Rendering Pipeline(利用OnChip内存保存GBuffer)

移动端渲染优化的—些需要关注的问题
1.首先定位是CPU瓶颈还是GPU瓶颈.(可以借助perfdog)
CPU瓶颈:
(1).场景过于复杂导致CPU开销大
(2).调用RHI命令开销过大(DC相关)
GPU瓶颈:
(1).shader简化(借助mali offline compiler)
1.Shader中少用if else语句
2.多用vector,少用scalar
3.借助工具判断Shader指令周期数
Shader最优化编写策略可以参考如下几个链接:
low-level thinking in high-level shading languages
https://www.gdcvault.com/play/1018182/Low-Level-Thinking-in-High
Low-level Shader Optimization for Next-Gen and DX11
https://www.gdcvault.com/play/1020352/Low-Level-Shader-Optimization-for
(2).简化RT的Load & Store减少发热(渲染管线优化)

光与影——光与渲染方程

光的基础物理特性
光本质上是电磁波,电场与磁场在与传播方向垂直的方向上振荡
当光在介质中传播时,介质中的电子受到电磁场作用
一部分能量被吸收,另一部分被以电磁波的形式重新释放
不同的介质的光传播特性各不相同,使得他们的视觉表现也大相径庭
当光波到达不同介质的分界面时,粒子产生的电磁波发生干涉
形成反射与折射现象
分界面的平滑程度决定了反射与折射波的发散,越平滑的平面使得光波越能够集中在同方向
对于很多不需要关心纳米级别的不平滑及其产生的衍射效应的场景来说,几何光学更易于研究
几何光学将光的传播路径进行简化
对于光学平滑( Optically Smooth )的介面,光在其上产生的
反射符合:
入射角等于出射角
折射符合Snell’ s law
渲染方程
渲染方程(Rendering equation)是图形渲染中一个重要的概念,其描述了光能在场景中的传递
其说明了一个物体表面在方向wo上的出射辐射率( Radiance )等于表面本身的辐射Le(x , wo)加上,所有方向的入射光Li(x,wi)经过物体表面的BRDF方程fr (x , wi, wo)在wo上的贡献
局部光照是渲染方程的简化,其只考虑光源与物体表面之间的光照计算,不考虑其他对象对光照的影响
对于面光源,因为入射光只在wl范围内,渲染方程可以简化为:

image-20251231193920351

对于点光源、聚光灯或者方向光,入射光只在lc方向上,渲染方程可以简化为:

image-20251231194002944

光源
现实中的光源种类非常多也很复杂,在实时渲染中比较准确地计算每个光源的光照非常困难,通常会将光源进行简化,以便于在实时应用中进行计算
方向光(Directional Lights)
假定所有入射光来自同一方向,入射光线平行
常用于模拟距离非常远的光源,比如太阳
点光源( Point/Omni Lights )
光源抽象成一个点,向四周传递光能
点光源的辐射率( Radiance )以距离的平方(r2)衰减
在游戏应用中,往往需要给点光源设定范围,以便于在渲染时进行光源裁剪以提升性能,为了获得平滑的光照过渡,当距离趋近光源最大范围时,衰减值应该趋近于0
乘上窗口函数,在趋近最大范围时,函数趋近于0
聚光灯
距离衰减方式与点光源相同,不同之处在于聚光灯还需要考虑方向
方向衰减函数自由度较大,很多引擎或应用会使用自己定义的衰减函数
image-20251231194809025
面光源
光源表面向外辐射能量,相比点光源更贴近现实中的光源,计算需要考虑光源表面所有点的辐射贡献
Real-Time Polygonal-Light Shading with Linearly Transformed Cosines 2016 SIGGRAPH
https://sgvr.kaist.ac.kr/~sungeui/ICG_F18/Students/Real-Time%20Polygonal-Light%20Shading%20with%20Linearly%20Transformed%20Cosines.pdf
环境光
对于一定范围外的辐射,可能直接来自某个光源又或者其他物体表面的反射,可以看做是来自环境的光照
计算所有的光源不切实际,实际渲染中通常用一些方式直接记录这些光照辐射信息
高低频分离
对于需要高频信息的光照,如光滑物体表面的高光反射效果,通常用纹理(Texture )记录周围环境的光照
对于需要低频信息的光照,如粗糙物体表面的漫反射效果,通常用一些函数重建的方式计算环境光照,如球谐函数( Spherical harmonics,SH )
全局光照
全局光照需要考虑其他对象的影响,其他对象的存在会对计算产生很大的影响
其他对象可能会遮挡入射光,由此产生阴影
其他对象可能会辐射光能,照亮当前的渲染对象
在离线渲染中,全局光照会有相对通用的解决方案,但对于实时渲染来说,这些方案都过于昂贵,因此全局光照通常被拆分成多个部分,对于各个部分用针对性的技术方案进行解决,多种技术结合使用逼近真实结果
通常游戏中主要的几个全局光照的分类:
漫射全局光照( Diffuse globalillumination )
漫射全局光照主要关注光能经由物体表面的漫反射传递的情况
对于介电质材质,尤其是表面粗糙的材质,其大部分入射光通过漫反射的形式传递出去,入射光的分布可以用低频的、平滑的方式描述
光照贴图( Lightmap )
光照贴图是全局光照预计算中常用的手段,其核心思路是通过离线计算全局光照的结果,将物体表面的辐照度( Irradiance )存储到纹理贴图中
Light Probe,光照探针
预计算放置点处的光照信息,通过周围探针数据插值得到任意点光照信息
球谐系数是常用的存储方式
实时全局光照,动态变更光照环境以及场景
Virtual point lights (VPLs)
Reflective shadow maps (RSM)
Light Propagation Volumes (LPV)
Voxel cone tracing global illumination(VXGI)
Screen space global illumination (SSGI)
UE5 Lumen

高光全局光照( Specular globalillumination )
高光全局光照主要关注高光反射的部分,对于金属、光滑物体影响较大
反射探针(Reflection Probe)/环境贴图(Environment Map)
通过纹理贴图记录周围的光照信息
预烘焙、实时更新
平面反射(Planar Reflection)
依据平面反射,渲染场景生成反射贴图
屏幕空间反射(Screen SpaceReflection,SSR)
利用深度信息,在屏幕空间做光线追踪
《实时光线追踪(RealtimeRaytracing)》

阴影( Shadow )
阴影的产生源于其他对象对入射光的遮挡
由于现实中的光源都不是无限小光源,因此其入射光方向是一个范围,软阴影也由此产生
平面阴影并不基于阴影的产生原理,而是基于阴影的结果
想法是将产生阴影的物体通过投影变化到平面上,然后在平面上渲染该物体,从而在视觉上做出阴影效果
平面阴影的一个问题是不支持曲面,投射阴影通过另外─种思路解决这个问题
投射阴影通过一张阴影贴图表示阴影,然后将接受阴影的物体在渲染时转换到光源空间,并采样阴影贴图,从而实现在曲面上的阴影效果
平面阴影和投射阴影实现简单,但在某些情况下不能够产生正确的投影,比如自阴影以及多个遮挡物体重叠的情况
Shadow Volume根据光源以及遮挡体生成volume,然后通过渲染volume并且统计视线进出volume的次数,从而得出渲染点是否处在阴影之中
虽然Shadow Volume能够在大部分情况下获得正确的阴影,但其性能消耗随着场景复杂度的提升而变得糟糕
Shadow map是目前使用最为广泛的阴影技术
在光源位置渲染场景深度,然后在渲染的时候采样这张深度图并判断遮挡关系
Shadow acne
在使用Shadow map时第─种会遇到的问题就是Shadow acne,其造成的主要原因就是Shadow map的分辨率有限,并且是离散化的数据
一个简单而直接的处理方法是对Shadow map中记录的深度值进行常量偏移
但常量偏移的问题在于,一个场景中有的表面可能需要较大的偏移量才能消除Shadow acne,而较大的偏移可能会造成Peter panning问题
结合normal/slope-scaled偏移,normal偏移指依据物体表面的法线进行偏移,而slope-scaled则依据深度的变化率调整偏移量的大小
提升Shadow map的利用率,使其覆盖真正可视的范围
对于方向光,一个常用的提升Shadow map利用率的方案就是级联阴影( Cascaded shadow map,CSM )
对视锥进行切分,用多张Shadow map分别覆盖多个切分部分,经过这种处理,离相机较近的场景可以使用更高的Shadow map精度,而远处的场景由于其覆盖的平面空间更小,因此使用更低精度的Shadow map也不会造成很明显锯齿
Percentage-Closer Filtering ( PCF )
PCF是常用的软阴影之一,其做法就是在传统的Shadow map的基础上,在原始采样点周围增加多次采样,从而使得在阴影的边缘有一个过渡区域
硬件采样并且比较Shadow map时开启线性插值,与一般插值不同的是,其结果是像素比较的结果之后的插值,有些地方称为硬件PCF
在PCF采样方法上,常见的两种优化方向:
一个是依然用常规的采样点分布,但是利用双线性插值采样并调整采样点位置,优化采样的效率
另一种是用随机的采样分布,使得阴影的锯齿呈现随机,从视觉上,有规律的锯齿更容易被察觉
Percentage-Closer Soft Shadows( PCSS )
PCSS可以看做是PCF在软阴影效果上的扩展,PCF的软硬阴影一个明显的问题就是其采样的范围是固定的,但对于真实的软阴影,当遮挡体距离渲染点越远时,其被遮挡的范围更小,软阴影更明显
PCSS的做法是通过采样Shadow map计算遮挡体的距离,并依据光源位置和大小计算半影大小,并依次调整PCF的采样范围
Variance shadow map ( VSM )
VSM通过另一种方式实现软阴影,其直接对Shadow map进行采样和过滤
VSM的原理是基于切比雪夫单边不等式(one-sided Chebyshev ‘s inequality):
image-20251231202302284
通过计算M12和M2可以计算出Shadow map中的深度大于当前阴影接收点深度的概率
VSM可以很好地处理acne问题,因为局部的微小的深度差不会大幅增加遮挡概率
但VSM的一个很难处理的问题就是Light bleeding,一般出现在有多个遮挡体重叠的情况
《GPU Pro 360 Guide to the Shadow》

环境光遮蔽( Ambient occlusion )
不同于常见的阴影技术,环境光遮蔽用于处理对环境光的遮挡
预计算遮蔽信息
对于静态场景或者模型,可以预计算遮蔽信息在顶点或者纹理贴图中
屏幕空间环境光遮蔽(Screen Space Ambient Occlusion,SSAO)
在屏幕空间依据深度信息采样,计算遮蔽信息

后处理(Post Processing)

由图像处理(lmage Processing)技术衍生而来,与一般渲染不同的是,其输入主要是图像,一般用于在渲染完成后对图像做进一步的处理,因此一般称作后处理
在实际后处理技术中,除了最终渲染出的颜色结果外,通常还会利用渲染过程中输出的场景其他参数作为后处理的输入,如场景的深度、法线、速度向量等等
Grayscale
Blur
看做是一个卷积计算,不同的卷积核可以生产不同的模糊效果
对于一些模糊是可分离的,通过两次模糊处理减少采样的数量
利用硬件线性采样,减少采样数量
通过降采样( Down sampling) 减少需要处理的图像尺寸
Dual Kawase Blur
多次升降采样,得到接近高斯模糊的效果,但性能更优
Radial Blur
径向模糊
沿着径向对图像进行采样和加权平均
Bloom
模拟真实的透镜相机,光在透镜的理论路径之外传播,造成一种扩散的效果
Bloom的简单流程:
提取高光部分
模糊
叠加到原始的图像上
Bloom效果往往需要较大的模糊半径,导致性能瓶颈,目前更常见的做法是通过多次升降采样的叠加
Color Grading
后期的调色处理
Hue Shift
Saturation
Contrast
Lift/Gamma/Gain

Color Grading LUT
Chromatic Aberration
模拟真实透镜相机中的色散现象
对于不同波长的光,透镜的折射率不同,不同波长的光不能汇聚到一点
Depth of field
真实的相机使用透镜成像,当物体不处于焦点时,其发射的光线将不能汇聚到成像平面的一点上,从而造成模糊
Motion Blur
当物体高速移动或者相机本身高速移动时,往往会出现模糊的效果,称为动态模糊
动态模糊的产生是由于人眼的视觉残留效应或者相机的成像时的曝光时间导致的。最终的成像结果是一段时间内的入射光的平均值,因此当物体高速移动时,在曝光时间内,其产生的入射光分布到了画面的不同位置,从而产生模糊的效果
Grain
通过叠加噪声图模拟真实中相机等设备录制中的瑕疵
Vignette
模拟真实相机中,生成的图像的外围部分的亮度或饱和度比中心区域低
Lens Distortion
镜头扭曲
对屏幕空间坐标进行重映射

雾效

体积渲染( Volumetric rendering )
Participating media是另一种现实中常见的介质,这种材质的粒子分散在一定体积内,光在这类材质中会传播一段较长的距离,因此不能用一般的BRDF来描述光的传播
雾是现实中常见的Participating media之一
Phase function
当光遭遇粒子发生散射时,Phase function用于描述,散射在各个方向上的分布

雾效
广告牌(Billboards)/粒子(Particles)
通过美术制作的面片或者粒子模拟雾效
解析式(Analytical)
假定雾的分布是简单的,通过解析解计算雾的浓度

后处理(Post processing)
基于后处理模拟雾效的散射效果:
提取未被遮挡的背景部分
基于光源的位置做径向模糊
将模糊的结果叠加到原图像上

Ray-marching
基于蒙特卡洛求解积分:
计算屏幕视线
在视线上选择采样点
计算采样点的光照,并依据采样点的密度计算散射并更新到视点的透射率
累计采样结果

Froxel
对视锥进行切分
将场景中的体渲染材质的相关参数存入3D纹理贴图中
对每个Froxel计算光照和散射
沿深度方向累计每个Froxel的结果
最终在屏幕空间采样Froxel计算体渲染结果

扩展阅读
Akenine-Moller, Tomas, Eric Haines,and Naty Hoffman. Real-time rendering. Crc Press, 2019.
Pharr,Matt, Wenzel Jakob, and Greg Humphreys. Physically based rendering: From theory to implementation. Morgan Kaufmann, 2016.

  • Titre: 腾讯游戏开局一课——客户端
  • Auteur: tiny_star
  • Créé à : 2025-12-04 17:27:12
  • Mis à jour à : 2025-12-31 21:31:08
  • Lien: https://tiny-star3.github.io/2025/12/04/Cpp/TencentGamesFirstLesson——Client/
  • Licence: Cette œuvre est sous licence CC BY-NC-SA 4.0.
Commentaires