游戏性能优化是一个非常重要的话题,在游戏开发过程中,优化主要从三个方面入手,CPU端优化,数据传输过程和GPU端优化。
在游戏性能遇到瓶颈时,首先要明确是谁拖了后腿,在CPU端还是GPU端,游戏逻辑由CPU执行,如果是UE4蓝图或者C++代码执行效率低,则是CPU端需要优化,如果是渲染速度慢,则需要GPU端进行优化,如果是CPU向GPU发送指令过程慢,则说明要减少Draw Call(CPU向GPU发送渲染指令数量)数量。
游戏有“帧”的概念, 一帧的运行时间并不等于CPU渲染时间+CPU向GPU发送渲染指令时间+GPU渲染时间,因为这三项是由三个线程执行的,基本等于其中耗时最长的那一项,因此只要降低耗时最长的一项,就能有效提升帧速率。
由于上述三者之间执行由不同线程执行,但是只有CPU端处理完成后GPU才能进行渲染,因此有以下的执行顺序:
在第0帧时什么也没做,第一帧时CPU处理逻辑,第二帧时CPU线程继续处理逻辑,同时CPU开辟一个线程向GPU发送渲染指令(Draw Call),第三帧时GPU开始处理CPU第二帧发送过来的数据,因此GPU每一帧处理的数据都是CPU前一帧发送过来的数据,这样就达到了看似顺序执行的目的
CPU端优化
CPU端主要处理的逻辑有动画,物理,AI等
刚刚提到,CPU端主要处理逻辑,对性能影响最大的便是Tick,如果在Tick里做复杂逻辑,就会使帧速率变低,因此能用事件触发就用事件触发,毕竟游戏中大部分的逻辑都可以通过事件触发,不必每一帧都去刷新,如果必须在每一帧都刷新,比如旋转这种简单的逻辑,可以尝试使用Shader实现。或者使用TimeLine是一个很好的方案。
- 如果程序上无法简化代码,那么尽量使用C++,而不用蓝图编写。
- 另一点是尽量使用内置函数,不要自己写了。
- 在UE4里比较耗费性能的节点有Get All Actors Of Class,ForLoop,Spawn Actor等,尽量避免使用这些节点。或者不要在tick里用。
数据传输
Draw Call对性能的大致影响如下:数百万个顶点,大概3000次draw call,上万次draw call,帧数已经惨不忍睹了。
数据传输就是Draw Call了,如果想减少Draw Call,可以选择一下方案:
- 共享材质,对不同的mesh尽量使用相同的材质,或者继承自相同的父材质,这样引擎可以对这些mesh打包发送给GPU做渲染,减少传送指令和数据次数。
- 减少模型复杂度,减少顶点数量,这是最直接的方案
- 使用LOD(层次细节),这是减少绘制mesh顶点数的有效方案,根据距离相机距离进行优化。
- 利用遮挡剔除,减少绘制模型数量
- 采用图集(常用于UI)
- 采用常见的烘焙技术,如烘焙光,代替实时光照
- 使用引擎自带的merge actors和HLODs
HLOD的优点如下:
GPU端优化
UE4的性能调试工具,和Unity的类似:
GPU端的优化主要就是简化shader运算了,我做了以下总结:
- 优化shader,不要写太费的shader,尽量简化运算
- 蓝图材质尽量避免使用if,用lerp代替
- 尽量避免over draw
- 尽量使用texture代替noise
- 使用mipmap优化纹理寻址
- 能在顶点着色器计算,就不在片元着色器计算
- 尽量减少光照和阴影的开销
版权声明:本文为CSDN博主「绿洲守望者」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_36696486/article/details/106393360