Unity性能优化CPU优化
CPU主要进行计算机的各种计算操作,因此关于CPU性能优化的方面和Tips有很多,有些影响大有些影响小,有些容易优化有些不易优化,细节方面也有很多,归类之后重点讲几个方面,并列出常见Tips。
对CPU性能影响比较大的主要有以下几个方面:
DrawCalls,物理组件,GC,代码质量,其中DrawCall是CPU优化最先考虑的点。
1.Draw Call优化
Draw Call实际上是一个命令,发起方是CPU、接收方是GPU,引擎每对一个物体进行一次DrawCall,就会产生一个Batch,这个Batch里包含该物体所有的网格和顶点数据,当渲染另一个相同的物体时,引擎会直接调用Batch里的信息,将相关顶点数据直接送到GPU。
(1)使用Draw Call Batching(批处理)
Batching技术的主要目标是在一次DrawCall中批量处理多个物体。只要物体的变换和材质相同,GPU就可以按照相同的方式进行处理,即使用同一次DrawCall中。
分为静态批处理和动态批处理。动态批处理机制是引擎自动进行的,静态批处理要把场景物体手动设置static。
动态批处理:自动进行的,顶点数在300以内的可移动物体,只要使用相同的材质,就会组成Batch。(收费)
静态批处理:把需要静止的物体标记为static,无论大小,都会组成Batch。初春合并后的数据,会增加内存的消耗。
(2)纹理打包成图集减少材质的使用
Editor>Project Settings>Editor 设置SpritePackage模式,设置为允许打包图集。
Unity2018中Project中可以创建Sprite Atlas,再添加要打包的纹理图片即可打包。
比如将3张纹理合并为一个图集,Batches就会从3降低为1。
(3)减少渲染次数
避免使用大量很小的网格,尽量合并或使用通用;
避免使用过多的材质;
减少实施灯光、阴影、特效等减少渲染次数。
2.物理组件
(1)处理Rigidbody时,使用FixedUpdate,设置Fixed timestep,减少物理计算次数,提高性能。碰撞检测使用离散的检测。
(2)不使用网格碰撞器,使用简单模型;关闭粒子的碰撞功能。
GC指的是Unity内存管理进行垃圾回收,GC操作会需要大量的时间运行,如果GC在CPU运行的关键时刻运行,会对其他操作带来很大的应先个,使游戏帧率下降。
什么时候会触发GC:
- 堆内存进行内存分配操作而内存不够的时候都会触发垃圾回收来利用闲置的内存;
- GC会自动的触发,不同平台运行频率不一样;
- GC可以被强制执行。
特别是堆内存进行内存分配时内存不足时,GC会频繁触发。
大体上通过三种方法降低GC的影响:
- 减少GC运行次数;
- 减少单次GC的运行时间;
- GC运行时间延迟,避免在关键时候触发。
解决这三个方面影响,主要有三种策略:
- 重构代码,减少堆内存分配和引用的分配,更少的变量和引用会减少GC操作检测的次数;
- 降低堆内存分配和回收的频率,尤其是关键时刻;
- 试着测量GC和堆内存扩展的时间,使其按照预测的顺序执行,当然这样操作的难度极大。
具体方法:
(1)缓存变量重复使用,避免反复调用堆内存分配的函数;
(2)不在频繁调用的函数如update中进行堆内存分配,或进行缓存或降低获取频率;
(3)使用clear函数清空链表替代反复多次的创建分配链表;
(4)对象池
(5)其他堆内存分配因素:字符串、协程、装箱…
(6)主动调用GC操作System.GC.Collect(),如场景切换的时候。
4.提高代码质量
许多操作需要CPU消耗很长的时间,可以尽量避免操作或缩短时间。
(1)GetComponent方法不要频繁使用,声明为全局变量,保存组件以引用;
(2)使用合理的算法和数据结构。少使用复杂运算,如除法、开平方根、反余弦,可以使用+、*代替
(3)使用内建数组如使用Vector3.zero而不是new Vector(0,0,0);
(4)可以Break掉的循环直接退出,减少不必要的循环;
(5)将可以缓存的数据尽可能的缓存起来,避免重复计算和重复分配内存(比如不要重复实例化同一个对象,可以事先建好对象池)
(6)FixedUpdate等频繁调用的方法可以扩大间隔,可以使用协程、InvokeRepeating代替;
(7)Shader尽量使用简单的算法,不使用太复杂的效果,尽量不使用透明的处理。
(8)等等等
5.其他
动画系统,使用简单的动画;粒子系统减少粒子数量,缩小效果。
物理组件:
1) 处理Rigidbody时,使用FixedUpdate,设置Fixed timestep(固定时间步),减少物理计算次数,运动起来也平滑,提高游戏性能。碰撞检测方面、使用离散的检测。
2)减少FPS,即减少每秒的帧数,在ProjectSetting-> Quality中的VSync Count 参数会影响你的FPS,EveryVBlank相当于FPS=60,EverySecondVBlank = 30;这两种情况都不符合游戏的FPS的话,或通过代码手动设置。
降低FPS的好处:
1.省电,减少手机发热的情况;
2.能稳定游戏FPS,减少出现卡顿的情况。
3)尽量不用MeshCollider
如果可以的话,尽量不用MeshCollider,以节省不必要的开销。如果不能避免的话,尽量用减少Mesh的面片数,或用较少面片的来代替。
4)粒子组件,屏幕上最大粒子数量建议小于200个,并关闭粒子的碰撞功能。
代码方面:
1)使用合理的算法和数据结构。少使用复杂运算,如除法、开平方根、反余弦,可以使用+、*代替
2)不要频繁使用GetComponent去频繁获取组件。如果要使用,可声明为全局变量,并只需在Awake函数中GetComponent。
3)使用内建数组如使用Vector3.zero而不是new Vector(0,0,0);
4)脚本在不使用时,禁用之,需要时再启用;
5)可以使用射线Ray来代替OnMouseXXX类方法
6)尽量少用模运算和除法运算,比如a/5f,一定要写成a*0.2f
7)不要使用原生的GUI方法,即OnGUI函数
8)务必删除脚本中为空或不需要的默认方法,如Update方法
9)同一脚本中频繁使用的变量建议声明其为全局变量,脚本之间频繁调用的变量或方法建议声明为全局静态变量或方法
10)尽量使用整数数字,因为iPhone的浮点数计算能力很差
11)将计算分到多个逻辑帧中进行计算,避免短时间内的性能超过负荷,俗称“分帧”。
12)将可以缓存的数据尽可能的缓存起来,避免重复计算和重复分配内存。
例如:不要重复实例化同一个对象,可以事先建好对象池
13)使用for循环代替foreach,使用List代替 ArrayList,尽量少使用封箱拆箱操作
其他或者其他说法:
14)可以Break掉的循环直接退出,减少不必要的循环。
15)FixedUpdate等频繁调用的方法可以扩大间隔,可以使用协程、InvokeRepeating代替
16)不使用打印、不出现警告,打包出去的时候