文章来源: 博客园
原文链接: UE4学习笔记:实时渲染原理 | U_N_Owen原文写得很好,但是主题格式我不太喜欢,所以我对文章的格式进行了修整,方便自己日后阅读
本随笔介绍 UE4 引擎在渲染及其性能影响方面的工具和概念,同时也包括一些光照基础概念。该随笔整理自官方教程视频:实时渲染原理。
本随笔作者还在学习阶段,对于UE4引擎的使用和理解还不是非常透彻,难免出现书写上和技术上的问题,若出现了类似的问题欢迎在评论区或私信与我讨论。
实时渲染(Real—Time Redndering,RTR)
- 只有在项目为空白项目的时候,实时渲染才能达到最高性能。
- 从那以后在项目里做的任何事情都会让项目损失性能。
- 实时渲染流程的本质是管理性能损耗。
- 需要设计者在 “最佳性能”、“最佳画质” 和 “最佳特性” 三者之间寻找到一个合适的平衡点。
- 设计者必须清楚性能会在哪里损耗,或会在哪里提升。
- 例如你有内存和处理器,如果你很清楚你添加的内容会对处理器造成很大的负担,那么后续的工作流应该更加依赖内存,这样才能将负担分摊到所有可用的硬件上。
- 渲染不仅和硬件组件有关,也和带宽有关。
- 渲染在硬件上的基本过程:硬盘等类似的设备用于存储数据,然后数据被传输到内存里,内存负责存储我们要使用到的数据,之后数据会在 CPU 和 GPU 之间来回传输(内存与 CPU 互相传输数据和内存与 GPU 之间互相传输数据,这两部分多数时候是同步执行的)
渲染之前发生的过程
CPU 和 GPU 是同时(并行)处理的,但不是在同一个时间点处理同一帧的内容。
渲染之前首先会由 CPU 进行画面内容的处理,然后交由绘制线程进行画面后续内容的处理,最后是 GPU 进行最终画面的处理。该过程各个硬件之间会以相同的速度和间隔同步执行,且严格以 CPU->绘制线程->GPU->CPU 的顺序执行。
| 执行时刻(30FPS) | CPU | 绘制线程 | GPU |
|---|---|---|---|
| 0毫秒 | A帧 | ||
| 33毫秒 | B帧 | A帧 | |
| 66毫秒 | C帧 | B帧 | A帧 |
执行时刻 0 毫秒开始,第 A 帧开始处理对象逻辑及位置信息:
我们最先需要知道对象的位置,这也是这一时刻CPU的工作:计算所有逻辑和变换。如动画、对象和模型的位置、物理效果、AI、生成和销毁,隐藏和取消隐藏等一切和改变对象位置有关的工作。
CPU 处理完毕之后,我们现在知道了场景里面所有对象的位置,但是却不清楚我们能够看到什么,或者说哪些对象需要被看到哪些对象不需要被看到。
执行时刻 33 毫秒开始,第 A 帧画面中对象逻辑及位置信息计算完毕,开始计算哪些对象需要被绘制:
计算哪些对象需要被看到哪些对象不需要被看到,这就是绘制线程在这一时刻的工作,因为某些时候(比如说在玩家视角中隔着一面墙的对象)在玩家眼中并不会被看到,因此该对象并不需要被绘制。
判断对象是否需要被绘制就涉及到引擎中的 “遮挡过程(Occlusion Process)”。
遮挡过程会为场景中所有可见对象和模型建立一张表,也会为所有不可见对象和模型建立一张表。遮挡会 逐对象 进行而不是 逐多边形 进行。
遮挡过程一共分为 四步 且按照顺序依次执行(这四个步骤共构成了一个混合方案):
1. 距离剔除(Distance Culling):
- 将任何距离超过 X 的对象移除。
- 该设置默认不会启用。
- 每个可见对象都会包含最大绘制距离(Max Draw Distance)属性,不仅是模型,粒子也是如此。
- 该属性的设置可在
细节面板(Details)->渲染(Rendering)->LOD下可设置,在该属性里不仅可以设置最大绘制距离(超过该距离则该对象不进行绘制)还可以设置最小绘制距离(小于该距离则该对象不进行绘制)。需要注意的是 最小绘制距离的设置即可以在 编辑器模式 也可以在 运行模式 里看到效果,而最大绘制距离只能在 运行模式 里看到效果(其实也能在编辑器模式下看到,但是需要按G快捷键将场景从编辑器视图切换为游戏视图,感觉应该是个 BUG)。 - 最大绘制距离分为 “期望最大绘制距离(Desired Max Draw Distance)” 和 “当前最大绘制距离(Current Max Draw Distance)”,这两个的 区别 是后者是经由 “剔除距离体积(Cull Distance Volume)” 来控制,且该属性呈灰色不可手动调整,前者可通过手动调整并且会覆盖后者设置的距离。
2. 视锥体剔除(Frustum Culling):
- 视锥体剔除会检查摄像机能够看到什么内容,视野以外的对象会被自动剔除。
- 该设置默认启用且不能被禁用。
3. 预计算可见性(Precomputed Visibility):
- 每个预计算可见性单元格(在编辑器模式下呈蓝色方格状,可视化的方式为勾选
显示(Show)->可视化(Visualize)->预计算可见性单元格(Precomputed Visibility Cells)) 都保存了一张 周围哪些物体是可见的哪些物体不是可见 的表格,当摄像机进入到某个单元格的时候,摄像机会询问单元格 “哪些物体被遮挡,我应该渲染什么,不应该渲染什么” ,然后引擎就会根据当前单元格存储的表格回复 “我记得这里应该渲染这个这个,不应该渲染那个那个”,通过提前计算的方式来确立渲染对象。 - 该设置默认禁用。
- 可以通过勾选
世界设定(World Settings)->预计算可见性(Precomputed Visibility)分类下面的 复选框预计算可见性(Precomputed Visibility),然后添加一个预计算可见性体积(Precomputed Visibility Volume)到关卡中,让该体积立方体包括住需要预计算的内容,最后在构建(Build)按钮的下拉框里选择构建预计算静态可见性(Precomputed Static Visibility),体积立方体内的所有内容都会被预计算可见性的单元格(呈蓝色方格状,大小可在勾选复选框同一位置的分类里进行设置,高度需要在 Lightmass 的 ini 文件里设置)填充。
4. 遮挡剔除(Occlusion Culling,四个步骤中最为精确的一步,通常能处理大部分情况):
- 遮挡剔除会精确地计算每个模型地可见性状态,例如玩家在一面墙的这一边,一个物体在那一边,因为物体被墙壁遮挡了,所以我们不会去渲染墙壁那一边的物体。
- 默认启用,而且应该不能被禁用。
- 这会 消耗很多性能,因为需要询问每个对象是否需要被渲染。
- 之所以要将最精确的剔除方案放到最后的步骤来进行处理,是为了负担其 “最大的性能损耗”,因为经过前三个步骤之后场景中的大部分对象已经确立好了其自身的可见性,最后再使用遮挡剔除功能来计算 剩余对象 的可见性,就比一开始使用遮挡剔除功来得高效。因此也可得出该四个步骤的性能损耗程度是依次递增的。
可通过引擎命令 Stat InitViews(Initialized Views) 可提供关于剔除对象相关的统计信息。
优化渲染小贴士:
- 设置距离剔除(Distance Culling),虽然该设置默认禁用,但是该设置也是非常容易设定的一个设置。
- 当你的场景里面存在超过 10,00 或 15,000 个对象时,性能就会开始受到影响,需要开始着手优化了。
- 这种性能损耗大部分都是 CPU 上的损耗,但是也会有部分的 GPU 损耗。
- 大型开放式场景可能会没有办法很好地应用剔除,因为玩家将能看到一切对象,因此可以设法弄一些障碍物之类。
- 几乎一切可见对象能够被遮挡,包括粒子对象。粒子对象是通过边界盒(Bounding Box)来确立遮挡的,在优化粒子的时候需要多注意这一点。
- 大型模型因为很容易进入视野内,因此很少会被遮挡,且因为需要渲染的内容增加,会增加 GPU 的性能损耗。
- 由部件拼凑出来的大型模型虽然可以实现遮挡,但是这会加大需要绘制的对象数量,因此会增加 CPU 的性能损耗。
- 上述两点注意事项就要求我们根据实际项目的情况进行一个平衡。