Profiling and Optimization in UE4
介绍理解什么会导致游戏的性能问题。
概述可以帮助您找到瓶颈的内置工具。
分享一些提示,你应该开始寻找问题。
为什么要控制性能?
心灵的安宁(心安)。
它在目标硬件上运行得越好,你可以添加到游戏中的东西就越多。
易于开发访问其他平台。
避免错误思维,不要有以下想法。
作为项目后期或最后一步的优化
性能是程序员的唯一责任。
引擎可以为你优化事情。
比较好的做法
您可以进行的最佳优化通常始于项目开始时所做的工作。
快写,常写。
避免“看门人”综合症表现(就是全交给看门的人负责)
应该是整个团队的责任确保每个团队成员都知道基本的分析过程这包括艺术家和音响工程师。
要问自己“现在性能问题是GPU的问题还是CPU的问题”
identifying bottlenecks(识别瓶颈)
查看性能的时候要用stat unit而不是stat fps
因为stat unit会告诉你硬件渲染某一帧所需的实际时间。
下面是几个线程数字的解释:
Frame:显示硬件渲染某个帧所需的总时间。
Game:C++或者蓝图游戏运行的时间gameplay operations。
Draw:指CPU渲染的时间。
GPU:指GPU渲染的时间。
您还可以使用stat unitGraph,它可以显示线形图回放。主要用于发现重复的故障。
在理想情况下,当你做性能分析时,当你寻找游戏存在的瓶颈时,游戏的运行环境越接近目标硬件和目标平台,你活的的数据就越准确。
如果可以的话,要避免在编辑器里面进行性能分析。特别是主机和手机平台,因为你不是在实际的运行平台上做调试。
PC和主机它们在渲染方便非常类似。
但是移动平台它采用正向渲染路径,情况完全不同。一定要使用合适的打包版本。并且在目标硬件上做测试。
如果你是做PC游戏,并且必须在编辑器里做性能分析,
1.记得在独立模式下运行(standalone Mode)
2.记得最小化编辑器
3.切记关闭帧率平滑turn off Frame rates smoothing
4.并且用控制台命令r.VSync=0关闭垂直同步。
框架分析Analysis of a frame
这几个线程是并行运行的。
当游戏按照图中的流程执行时,
Game线程会计算所有的游戏逻辑,game线程计算的所有数据都会被储存起来,并被Draw线程使用,它会算出不需要渲染的内容(这些内容不会显示在屏幕上)。完了之后GPU线程会在屏幕上实际渲染出最终的像素。
所有的东西 从游戏逻辑所有的Actor的位置,场景中所有物体的位置 动画,实际动画帧,物理效果,AI,一切与场景最终效果有关的计算,在进行处理时都会在Game线程中计算。这步完成后,整个游戏世界就被计算完毕了。引擎就会知道什么东西该干什么。在下一步“Draw”线程他会过滤掉(剔除掉)所有不在相机范围内的却还需要引擎去渲染的对象,然后创建一个列表(包含所有的对象Object,着色器Shaders,材质Materials,纹理贴图Textures和所有需要发送给GPU的数据)。然后GPU会处理这些数据(包括顶点Vertex,着色器Shaders,纹理Textures等各种数据),然后会在屏幕上绘制最终像素。
generate chart over a period of time在一段时间内生成图表
StartFPSChart和StopFPSChart
它会主要获取stat unit的输出结果记录在一个文本文件里,也就是CSV文件。(其实会有三个)
用表格的软件打开(例如Excel),然后创建一个图表(Create Graph)去分析
可以帮助你找到游戏过场动画中出现卡顿的原因或者你甚至可以执行一些自动化的任务(例如让摄像机扫拍整个关卡),然后记录所有数据,并导出到CSV,然后你可以每周或者每晚定期做一次检查是否有潜在问题或导致性能不稳定的各种问题。
CPU优化
stat Startfile 和 stat Stopfile
会在项目底下这个路径生成几个数据文件。
ProfileGPU命令
Unreal Insights 工具
Game Thread 游戏线程
通常“游戏”线程中的性能问题,都是“Tick”函数中包含了复杂的逻辑。
因为Tick 是每一帧都会执行,计算引擎中所有东西状态的函数。
但事实是 蓝图 至少是GamePlay蓝图,它们很少需要每帧更新。
因为大部分游戏脚本都是基于事件的。或者不一定需要每帧都更新,虽然也有例外的时候,但大部分情况下你不需要那么做。
要记住如果你的场景和世界中,有许多Actor的“Tick”函数在运行。那就会严重拖累游戏的流畅度。
Stat game命令
它能查阅游戏逻辑在特定情况下的每帧更新耗时。
Dumpticks命令
它能列出正在更新的所有Actor,以及它们的总数。
如果非不得已要在Tick里面添加复杂的逻辑,请慎重斟酌,是否真的需要这么做。
下面列出几个替代Tick的方案:
2. Timer
3. manual toggling of Actor Tick 手动切换Tick
手动禁用和开启Tick,比如禁用那些距离玩家太远的Actor,它们不在摄像机里,在你靠近他们的时候再重新启用。
4. reducing the tick interval 增加Tick的时间间隔.(分帧处理)
5. Event drien systems(use dispatchers!)事件驱动.
材质效果方面,假如是要做简单的淡出效果或者动画,也就是像素着色器实现这类效果,这是个很简单的例子,是要经过了开始的时间,算法就会完成剩下的工作,即再两个值之间插值,你就完全不会用到CPU线程,这都在GPU上运行。对这类效果来说,运行速度会非常快。
在游戏开发中,我们还会遇到大量的包含简单循环移动逻辑的对象,所以如果是某些和游戏玩法关系不大的逻辑:例如一些和关卡美化有关的逻辑,一些让场景更好看的逻辑,可以让材质实现,把它们改用顶点着色器实现(vertex shader),甚至用原生代码来赋予它们旋转动画。
C++的“RotatingMovementComponent”就是个很好的方法。它用于让对象自旋,但假如你还想进一步榨取性能,你就可以用顶点着色器实现它。
GetAllActorsOfClass
ForLoop
SpawnActorXXX
用这些函数的时候一定要多加谨慎。
如果真的要调用这个函数,请在基于事件的逻辑中调用它,比如在游戏启动时调用它。或者编写某种基于事件的逻辑。在只有需要访问数据的时候才调用这个函数。然后把数据全部存到数组中,请记住这些好习惯!
如果用到for loop,尤其是涉及多重循环时,记得要及时中断循环,这样等你找到需要的对象后就不用运行其余的循环了。
SpawnActor实际上官方已经优化完善了许多,但是在生成Actor的时候还是会占用很多资源,因为这同样需要占用当前平台的IO接口。所以如果你在游戏中需要频繁生成Actor,可以考虑把场景中的Actor保存在缓存池中,还有要注意如果你真的要在Tick函数中实现复杂算法的和运算请考虑使用原生代码 或者说C++。
也不需要把所有的功能都挪到C++里面,只需要把复杂代码的那部分移过去,因为可能只需要把有复杂代码的那部分移过去因为它们需要做各种复杂计算只把那部分移到C++然后把它作为函数公开给蓝图然后就可以了。
如果你制作的3D游戏会用到动画蓝图,记得要使用Fast Path,基本上动画蓝图中的这种闪电图标越多就越好。
stat scenerendering命令 场景渲染
Draw调用对性能有很大的影响。每当渲染器完成时,它需要接收来自渲染线程的命令,这增加了开销。在许多情况下,DrawCall比polycount有更大的影响。在来回调用时,每当渲染器需要发送命令,或者你增加了开销它实际的影响polycount(多边形数量)影响还大。
你可以用RenderDoc来调试绘制调用.
那要如何减少DrawCall?
使用更少更大的模型,把不同模型不同对象合并成一个模型(MergeActors)。当然这也不是绝对这么做就好,例如这样做程序就不好做删减,例如玩家在高楼大厦门口,只是看一眼一楼,就要将整栋楼一起渲染,引擎没法将模型拆分成多个部分,因为这是个完整的模型。这对光照贴图很不利,如果你使用了静态光照,你就需要更大的光照贴图(larger lightmaps)以便显示更多细节。这对碰撞计算很不利,相比拆分成多个小型模型。碰撞效果的精度会差一些。当然这对内存也不利,要加载更大的资源,可能会导致卡顿。
(未完待续···坑爹传Word只能5M)
Copyright © 2002-2022 盛煌-盛煌娱乐-盛煌全球注册认证站 版权所有