Unity 性能相关因素(一)

Unity 性能相关因素(一)

CPU方面

渲染模块

Draw Call

Draw Call ,就是CPU对图形绘制接口的调用,CPU通过调用图形库接口,命令GPU进行渲染操作。
因为每次绘制时,CPU都要调用Draw Call,而每个DrawCall都需要很多准备工作,检测渲染状态,提交渲染数据
提交渲染状态等,而GPU本身具有很强大的计算能力,可以很快处理完渲染任务。但是当DrawCall过多时,CPU就会产生很多
额外的开销用于准备工作,CPU就可能处于负载状态。

降低Draw call
  • 降低Draw Call的方法主要是减少所渲染的材质种类,并通过合批来减少Draw Call数量。
  • 通过将纹理打包合并到一个图集内来减少材质的使用。
  • 尽量减少反光和阴影开销,会使物体多次渲染。
  • 控制UI的渲染顺序,相同材质尽量不要被其他材质打乱Z轴顺序。
  • 特效清理,不使用的特效要对其进行回收,将其设置为非激活状态。

注意: 游戏性能Draw Call不是越小越好。这是因为决定渲染模块性能除了Draw Call之外,还有用于传输
渲染次数的总线带宽。当我们使用Draw Call合批之后,可能会造成同一时间内传输的数据(Texture ,VB/IB)大大
增加,以至于造成带宽“堵塞”。在资源无法及时传输过去的情况下,GPU只能等待,反倒降低了游戏的运行帧率。
所以Draw Call次数与带宽之间要有一个平衡。就像一个天平一样,都不能太过极端。

简化资源
代码效率

遵循二八法则,找出代码cpu占用较高的进行优化。

LOD

最常用的优化方式。根据相机距离显示不同的模型,可以使用SimpleLOD插件减少工作量,在不影响
美术效果的前提下。

帧频限制

为了降低耗电发热量,对不同机型进行限制帧数。可以将逻辑帧与渲染帧分开执行,逻辑代码执行更低帧频
。部分逻辑也可以使用线程。

算法

代码本身运算就可以进行优化。例如优化物理运算,减少频繁索引find 或者GetComponet以及各种运算。
优化遍历利用稀疏矩阵九宫四叉树。

服务端或者客户端计算

根据不同类型的游戏调整运算是在服务端还是在客户端,如果服务器性能强大可以让服务器计算物理、寻路、AI、战斗逻辑
等复杂运算,客户端负责展现即可,特别是MMO项目。帧同步方式会将绝大部分运算放在客户端。

Unity接口

OnGUI、FixedUpdate、Update等空函数也会有GC开销,因为会产生从C++到C#层调用的开销。
MainCamera是一个遍历操作,尽量不要频繁调用。
尽量少使用GetComponent,AddComponet(还会产生GC),Find等操作。
Unity新函数SetPositionAndRotation,因为position与rotation改变了都会发送一次消息,并且新函数会开启线程来进行这个操作
极大的提升性能,所以最好每帧设置一次。一次可以提升一倍的性能开销。

物理

Unity使用PhysX作为物理引擎,本身优化还是很好的,会做空间划分。Unity官方建议碰撞对小于100,其实这个标准非常严苛,我们测试在300左右物理的开销还是蛮少。优化方面可以通过分层减少碰撞对,尽量使用BoxCollider而不是MeshCollider,UI界面不需要点击的控件不要打开Raycaster。因为我们只使用了最基本的射线检测,其他物理是自己实现的,主要的优化还是在物理算法上。如过在Profile中发现Physucs.Simulate开销比较大就是物理需要优化了。

IL2CPP & C++

把Unity编译设置成IL2CPP(前提是所有使用的方案都支持IL2CPP,有一些插件就不支持,这个地方就需要进行取舍了),编译成C++版运行效率会有较大提升。还可以把一些运算逻辑放到C++的库里,这样可以优化更极致减少gc。

动画

如果Prifile中发现Animator.Update或者MeshSkinning.Udpate开销比较大就说明动作可能需要优化。

UI

UI也是个开销大头,一般会占到30%-50%。UGUI对应Profile中Canvas.BuildBatch &
Canvas.SendWillRenderCanvases开销,类似NGUI的LastUpdate,UI的优化又很多文章这里也简单列举一下。

  • 动态静态分离:因为UI会合并。NGUI是按Panel进行重建的、UGUI是按Canvas进行重建的,防止动态UI触发合并导致静态UI也一起合并。
  • 预加载,常驻,即时释放:UI按类型划分,比较大的常用的UI在创建的时候会卡顿,可以进行预加载。主城到战斗场景,在保证峰值内存的情况下,将英雄界面工会界面等常驻内存,可加快Loading速度,实测优化后提升一倍以上loading速度。其他不常用界面拆分成小界面,使用即时加载,关闭时卸载节省内存。需要注意的是,UI节点过多也会导致加载缓慢,我们曾经Loading要10秒,其中序列化UI占了一半左右的时间(贴图预先加载测试),减少UI节点数,太大了拆开。
  • 图集:合理拆分UI图集,区分公共图集(常驻)和非公共图集。太大容易造成冗余加载,容易导致内存占用过大,导致内存显存交换开销。太小有容易导致显存碎片影响效率。规则很复杂。
  • 内存池:UI冒字等频繁创建的UI使用内存池减少创建的时间和内存碎片。
  • Active/Deactive:不推荐通过Active/Deactive来频繁切换UI界面,因为会触发UI合并操作,可以通过移到屏幕外的做法或者设置Layer。但需要注意移到屏幕外还是会被合并渲染,如果是长时间不显示的还是Deactive比较好需要视情况而定。
  • UISprite来代替UITexture:Texture不会合并。
  • 不移动不可见的UI不更新:例如血条名字等。
  • layout group, canvas group组件,任何子节点变了父节点都会用getcompent找到laygroup。这是Unity的UGUI的两大坑。
  • 检查不需要拾取的Raycast target是否关了。
  • 资源预加载:例如前面介绍的UI预加载,内存允许的情况下所有资源都应该预加载,结合内存池。我们游戏中所有变现逻辑,角色,怪物,道具,UI都会做预加载,并且有一套池膨胀和回收的策略。
  • Shader预加载。
GC

GC是一个非常高开销的系统调用也,是大部分卡顿的主要原因,不能完全控制。因此我们要尽量减少代码堆内存分配过量防止频繁触发GC,同时也可以在Loading或者对性能不敏感的时候主动GC。

  • 升级Unity:Unity5.6修改了粒子系统的源码减少了lamda表达式的gc。
  • 减少一些字符串拼接,使用StringBuilder代替string减少GC开销,不要使用富文本改变Text组件的颜色直接通过修改Text组件颜色来改。
  • 内存池:前面说过GameObject的内存池,另外还有类对象的内存池。所有频繁反复创建删除的都应该使用。两个用途,减少加载创建释放的时间,减少内存碎片降低GC的频率。
  • Unity接口:AddComponent,OnGUI,UI合并频率,delegate,等(一些Foreach,协程等Unity已经优化)。
  • 逻辑优化:避免频繁创建开辟空间。
  • 插件的GC优化:对行为树,FMODStudio等一些插件的源码进行了修改减少GC。
  • C#源生的linq会产生过多GC,可以自己封装优化。

参考博文

Unity 性能优化总结—CPU篇
Unity优化技巧(中)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值