Unity优化丨CPU篇

提示:选中右侧目录,可快速找到所需内容

本系列博客链接:传送门

CPU(中央处理器)决定设备运行的快慢。

CPU优化不够会出现的问题:

1、由于短时间内的计算量太大,导致画面流畅性降低,俗称跳帧

2、发热严重,耗电量高

CPU优化方向:

1、DrawCalls、

2、物理组件、

3、GC(GC为处理内存,此项为CPU使用GC处理内存时产生的性能损耗)、

4、资源设置

5、代码

一、Drawcalls

Drawcall是啥?其实就是对底层图形程序(比如:OpenGL ES)接口的调用,以在屏幕上画出东西。使用Draw Call Batching,也就是描绘调用批处理。Unity在运行时可以将一些物体进行合并,从而用一个描绘调用来渲染他们。

1、优化Draw Call Batching

Draw Call Batching分为:

1)静态批处理Static Batching:静态、不动的物体且具有相同材质的话就可以使用静态批处理来降低描绘调用
2)动态批处理Dynamic Batching:动态批处理是引擎自动进行,无需设置,当物体共享相同的材质,则引擎就会自动对Drawcall进行优化,也就是动态批处理(如实例化预制体)。动态批处理存在约束,稍有不慎就会增加Drawcall。动态批处理有很多约束:顶点数、缩放、不同材质等约束都不会自动批处理。

相对而言,静态批处理操作允许引擎对任意大小的几何物体进行批处理操作来降低绘制调用(只要这些物体不移动,并且拥有相同的材质)。因此,静态批处理比动态批处理更加有效,你应该尽量低使用它,因为它需要更少的CPU开销。

注意:

1、静态Batching会导致内存和存储的开销,动态Batching会导致CPU开销

2、当前只有Mesh RenderersTrail RenderersLine RenderersParticle SystemsSprite Renderers可以被批处理。这意味skinned Meshes、Cloth和其他类型的渲染组件都不能被批处理

3、使用静态批处理操作需要额外的内存开销来储存合并后的几何数据。在静态批处理之前,如果一些物体共用了同样的几何数据,那么引擎会在编辑以及运行状态对每个物体创建一个几何数据的备份。这并不总是一个好的想法,因为有时候,你将不得不牺牲一点渲染性能来防止一些物体的静态批处理,从而保持较少的内存开销。比如,将浓密森里中树设为Static,会导致严重的内存开销。

如何设置:

静态静态批处理Static Batching

a、静止、在游戏中永远不会移动、旋转和缩放的物体,Inspector勾选Static。

b、PlayerSettings=OtherSettings:勾选StaticBatching

动态批处理Dynamic Batching

PlayerSettings=OtherSettings:勾选DynamicBatching

2、UGUI需将同一界面的UI元素打包成图集。

二、MeshSkinning.Update

我们能看到下图MeshSkinning.Update占了19.94ms,经优化后仅占0.03ms

注:该优化可能会有问题!我在这样优化时,发现模型消失了,优化时注意观察!

优化方法:

打开模型的OptimizeGameObjects选项。

二、物理组件

1、处理Rigidbody时,使用FixedUpdate,设置Fixed timestep(固定时间步),减少物理计算次数,运动起来也平滑,提高游戏性能。

2、减少FPS,即减少每秒的帧数,在ProjectSetting-> Quality中的VSync Count 参数会影响你的FPS,EveryVBlank相当于FPS=60,EverySecondVBlank = 30;这两种情况都不符合游戏的FPS的话,或通过代码手动设置。

降低FPS的好处:

  • 省电,减少手机发热的情况;
  • 能稳定游戏FPS,减少出现卡顿的情况。

3、尽量不用MeshCollider

如果可以的话,尽量不用MeshCollider,以节省不必要的开销。如果不能避免的话,尽量用减少Mesh的面片数,或用较少面片的来代替。

4、粒子组件,屏幕上最大粒子数量建议小于200个,并关闭粒子的碰撞功能。

三、GC

虽然GC是用来处理内存,即回收垃圾的,但是却会增加CPU的开销。因此要合理减少GC

首先我们要明确所谓的GC是Mono运行时的机制,而非引擎的机制,而它管理的也是Mono的托管堆,而非引擎的本机堆。所以,GC不是用来处理引擎的assets(纹理,音效等等)的内存释放的,因为U3D引擎也有自己的内存堆而不是和Mono一起使用所谓的托管堆。其次我们要搞清楚什么东西会被分配到托管堆上?就是引用类型咯。比如类的实例、字符串、数组等等;而作为int,float,包括结构体struct其实都是值类型,它们会被分配在堆栈上而非堆上。所以我们关注的对象无外乎就是类实例、字符串、数组这些了,所以GC的优化说白了也就是代码的优化。

此部分的代码优化只针对是否会触发GC:

  1. 字符串处理。如需多次用String的+运算符来拼接字符串,就用StringBuilder的Append方法。
  2. 不要直接访问gameobject的tag属性。比如if (go.tag == “human”)最好换成if (go.CompareTag (“human”))。因为访问物体的tag属性会在堆上额外的分配空间。如果在循环中这么处理,留下的垃圾就可想而知了。
  3. 使用对象池,以实现空间的重复利用。
  4. 最好不用LINQ的命令,因为它们会分配临时的空间,同样也是GC收集的目标。

四、资源设置

1、音频设置

a、音频压缩格式:

对iOS平台,建议采用mp3格式压缩音频文件,安卓平台建议使用Vorbis格式,因为这两种格式分别在这两个平台上有硬件解码的支持。

b、Force to Mono:

手机游戏往往对声音质量要求不高,如果不需要立体声效果,可以把这个选项打开,将音频文件导入为单声道音频。

2、模型设置

a、检查Animation Type有没有设置成None

Unity默认的Animation Type是Generic,对包含动画数据的FBX文件是适用这个选项的。但是如果FBX文件中没有包含动画数据,而只是普通静态Mesh的话,设置为Generic会导致引擎自动为这个Mesh的GameObject添加一个Animator组件,导致不必要的消耗。因此对于不包含动画数据的模型文件,我们建议把这个选项设置为None。

b、当摄像机没看到的模型时,不播放模型动画。

c、动画帧率

在Animation页面检查动画的帧率,一般30FPS足够满足大部分游戏的效果,如果发现有制作成60FPS的,建议美术重新制作成30FPS。

五、代码

除了使用使用合理的算法和数据结构外,还有如下需要注意:

  • 不要频繁使用GetComponent去频繁获取组件。如果要使用,可申明为全局变量,并只需在Awake函数中GetComponent。
  • 使用内建数组如使用Vector3.zero而不是new Vector(0,0,0);
  • 脚本在不使用时,禁用之,需要时再启用;
  • 可以使用射线Ray来代替OnMouseXXX类方法
  • 尽量少用模运算和除法运算,比如a/5f,一定要写成a*0.2f
  • 不要使用原生的GUI方法,即OnGUI函数
  • 务必删除脚本中为空或不需要的默认方法
  • 同一脚本中频繁使用的变量建议声明其为全局变量,脚本之间频繁调用的变量或方法建议声明为全局静态变量或方法
  • 尽量使用整数数字,因为iPhone的浮点数计算能力很差
  • 将计算分到多个逻辑帧中进行计算,避免短时间内的性能超过负荷,俗称“分帧”。
  • 将可以缓存的数据尽可能的缓存起来,避免重复计算和重复分配内存。例如:不要重复实例化同一个对象,可以事先建好对象池
发布了329 篇原创文章 · 获赞 85 · 访问量 19万+

猜你喜欢

转载自blog.csdn.net/weixin_38239050/article/details/104558465