前言

关键词:
Deferred Rendering 延迟渲染
Frame 帧
Occlusion Culling 遮挡剔除

看完本篇内容你将对以下概念心中有数:

  1. 实时渲染分为 前向渲染 Forward Rendering延迟渲染 Deferred Rendering ,如何认识这两个概念
  2. 延迟渲染 Deferred 过程中每一帧在计算什么
  3. 遮挡剔除 Occlusion Culling 为什么重要,如何结合实际情况组合解决方案

01 前向渲染 or 延迟渲染?

首先重要的是需要理解这么一个过程,每一帧画面的渲染,其中包含对几何体本身的计算,它的形状、位置,还包含受复杂影响的计算,它受光照后的着色和材质。对于前向渲染来说,这两大块在同一环节计算,而对于延迟渲染来说,先进行几何体计算,再进行渲染光照结果混合的计算。

所有的特性都围绕一根本区别产生,具体来说,

前向渲染 Forward Rendering :着色/光照渲染和几何体在同一环节计算

  1. 在如何计算光照和材质上更多的自由度,但在混合各种功能时会受限。
    • 因为在同一环节处理,几何体的对象信息是完全的,不像延后渲染在处理光照时只有有限存储下来的几何体的信息数据。
    • 渲染引擎的很多功能是在后期处理的,采用前向渲染后只能在这一结果基础上进行,而延后渲染的几何体信息和光照信息是分开的,混合功能兼容性和效果都会相对好一些。
  2. 适合半透明的渲染
  3. 对于简单应用要快得多
    • 对于延后处理来说,一帧画面从发出信号到输出到屏幕要慢于同一环节处理的前向渲染
    • 比如很多移动 App 都会采用前向渲染以提高效果
  4. 采用动态光照会对性能有很大影响
    • 动态光照对于每一个对象又要重新计算混合
    • 看到 UE 方说目前的新技术效果可以达到基本同延迟渲染了
  5. 可以采用 MSAA(多重采样抗锯齿) 和 TAA(时间性抗锯齿) 方案抗锯齿

延后渲染 Deferred Rendering :着色/光照渲染发生在延迟环节中,通过 Gbuffer 缓存图像计算

  1. 对动态光照友好/性能更好
    *. 本身就是延后处理,光照/着色前的计算都缓存下来了
  2. 在涉及几何体表面相关处理时相对受限,但在混合各种功能是更灵活。
    *. 几何体对象信息不完全,对于几何体表面的复杂处理受限于描述信息
    *. 各种后期处理,类似动态光照的处理过程会有很有。
  3. 应用表现稳定可预测,适合大型应用性能稳定
  4. 不能采用 MSAA(多重采样抗锯齿) 方案,只能采用 TAA(时间性抗锯齿) 方案抗锯齿

对于 UE4 来说,默认采用的是 Deffered Rendering,修改渲染模式在项目设置中


02 计算过程

整个计算过程中有三个众所周知的重要角色: CPU、DRAW(CPU+GPU)、GPU

请对照图中的橙色色块,将其简单理解为一个画面

以 30帧率的模型为例,每一帧是33.33ms,对于一个要处理的画面,在第一帧会在 CPU 处理,第二帧在 渲染线程 处理,第三帧 66.66ms 才由 GPU 绘制画面。(实际过程更复杂,这里简化模型理解延迟)

在 Frame0 时,CPU 会进行大量的逻辑计算,目标是得到世界有哪些对象、这些对象在世界哪里的信息
涉及到

  1. 动画
  2. 模型和对象的位置
  3. 物理
  4. 人工智能
  5. 生成和销毁、显示和隐藏

就是计算所有可能影响对象的位置变化、存在与否、显示与否的功能模块


在 Frame1 时,渲染线程会进行大量的计算,目标是得到屏幕可见部分渲染对象的信息
重要概念是,在这个过程会进行遮挡计算,也就是我们透过屏幕/视口看不到或者不希望看到的对象进行剔除,只渲染眼见的对象,而不是渲染整个世界。
涉及到

  1. 距离剔除 Distance Occlusion
  2. 视椎体剔除 Frustum Occlusion
  3. 预计算可见性 Precomputed Visibility
  4. 遮挡剔除 Olccusion Culling

最终得到一份需要渲染的对象列表,至于这些遮挡计算到底是什么、又怎么使,我们将在下文继续展开。


03 遮挡计算

遮挡计算看似是个简单的问题,无非是,我现在屏幕/视口要展示的就这么块区域,为了节省开销,我看不见的就不要给我渲染了,引擎你反正把能显示的算出来展示上就是了。

但现实总是更加复杂,比如

  1. 遮挡计算到底是按照对象来计算、还是面来计算呢?如果按照对象计算,这个对象很大很大但只是在视口中露出一点点,那么不是很浪费渲染;同时考虑如果按面计算,要遍历的数量就成几何倍上涨,计算开销瞬间增大。
  2. 有些物体离得很远,要不要剔除?怎么界定? 现在桌面上有一个杯子,摄像机来到窗户外杯子变得很小了,再把摄像机放到楼房全景,杯子几乎小到看不见了,对于引擎来说,不论多小多大,它都会渲染,我们怎么节省这些消耗,尤其是在一些大全景的画面下。

好了,我们来聊聊 UE 给出的方案

首先,UE 采用的是逐对象的遮挡计算,注意是逐对象不是逐面。对于我们上面提到的第一点问题是无法避免的,那么优化的思路就是,在审视和检查性能时有必要将一些大对象拆分成小对象,这里就是需要根据场景情况不断测试和平衡。

然后,记得上文提到的 4 种剔除计算过程吧,它们是逐次进行的,但它们不都是默认开启的,这意味在 UE 中遮挡计算是一个由开发者定义的组合招式,只能根据场景情况做适合的方案。

  1. 距离剔除 Distance Occlusion —— 默认不开启
  2. 视椎体剔除 Frustum Occlusion —— 默认开启,无法关闭
  3. 预计算可见性 Precomputed Visibility —— 默认不开启
  4. 遮挡剔除 Olccusion Culling —— 默认开启

顺序1
距离剔除 是效率最高的,为 单个actor 或 创建 Cull Distance Volumes 块指定可视的距离

1
2
3
最小绘制距离(Minimum Draw Distance): 这是在不再渲染Actor之前能够接近Actor的最近距离。
最大绘制距离(Maximum Draw Distance): 这是在不再渲染Actor之前能够远离Actor的最远距离。
当前最大绘制距离(Current Maximum Draw Distance):它显示剔除距离体积(如果存在)设置的已存储剔除距离。

顺序2
视椎体剔除 是默认开启的,计算摄像机视角内的对象。

如下图,黄色区域内有包含的对象都属于可见,之外的对象则不会进入要处理的对象列表。(但这幅图是二维的,还不够直观)

如下图,紫色的椎体内有包含的对象都属于可见

顺序3
预计算可见性 是对可见进行预处理。
在最后的剔除遮挡过程中,实际是基于前几个步骤得到的对象列表,在当前摄像机视口逐个对象去询问是否可见,而摄像机很可能是高速移动的,这一询问剔除的过程很容易由于问询对象过多而遭到性能压迫。
而预见性处理是建立一个体积,在这体积内划出一个个的立方格(通常我们叫它小蓝格),每个立方体都会预先计算这个立方体下有哪些可见对象并缓存下来。
这意味着,基于这种处理后,最后的动态剔除的问询对象很有可能大量减少。比如在某个三面墙的位置,必要有大量对象是被遮挡看不见的,那么就不会进入可见对象列表;而不做这个可预见处理,摄像机每移动一下,就需要去遍历询问上一步得到的所有可见对象,哪怕我们显而易见是被遮挡了的对象。

使用教程:简述重点,布置预计算可视性体积 Precomputed Visibility Volume到场景中进行预计算,根据场景情况调节单元立方格的尺寸

顺序4
遮挡剔除 这是最精准,也是剔除计算里开销最大的部分。会轮询基于上一步得到的可视对象列表,逐一发起检查是否可见,并筛选出最后的可见对象列表。

我们通过控制台可以查看遮挡相关的数据,指令 stat initviews

上半部分 Cycle Counters 是统计计算花费的循环数量,就是帧时间量
View Visbility 整个可见性计算
Occlusion Cull 遮挡计算
View Relevance 其他视图相关计算
Frustum Cull 视椎体剔除计算
Decompress Occlusion 加载预计算可见性的数据

下半部分 Counters 是统计每一帧各过程的对象数量
Processed primitives 场景中剔除后最终被处理的对象总数
Frustum Culled primitives 视椎体剔除的对象总数(视椎体外)
Occluded primitives 遮挡剔除的对象总数
Occlusion queries 遮挡剔除一轮要查询的对象数量
Visible static mesh elements 场景中移动性为“静止”的可见网格体数量
Visible dynamic primitives 场景中移动性为“动态”的可见网格体数量

另外还有 Freezerendering 冻结当前的遮挡,stat RHI查看绘制帧的三角面数,stat unit现实帧时间、绘制时间等等,充分挖掘和发挥检测工具的效用吧~


04 优化总结

  1. 检测渲染之前的预处理计算,充分利用检测工具得到量化数据,再开始抓重点优化;
  2. 平衡 CPU 和 GPU 的消耗,这两个互为瓶颈;
  3. 控制对象数量,场景内有 1w~1.5w 的对象数量是很难优化到正常性能的;
  4. 管理设置上距离剔除,针对高频访问区域也设置好可见性与计算。

100 相关参考