UI模块:
NGUI:UIRect.Start()函数在耗时监测时绿色线条很多的话,说明UI界面在频繁Instantiate/Destory。 [改为将对象移回屏幕内。这样性能就好多了。 UGUI:如何定位Mesh重建是否合理? 1.动态元素和静态元素分离; 2.合理配置UI Canvas/Panel,一个Canvas下的Widget不宜过多 UGUI和NGUI的性能区别: 如果都合理搭配,UGUI在性能上还是有一点优势的,在Unity5.2、5.3之后UGUI有一部分网格合并的操作是放在多线程中进行,相对来讲,性能有一定的提升; 但NGUI的优化相对更简单一些,主要是因为NGUI的Drawcall相对容易估计,可以知道Drawcall从哪里来的,也更容易定位网格的刷新是由什么元素引起的, 但UGUI的Drawcall难以估计,且网格重建的开销因为引入了多线程,也会被隐藏起来,所以优化起来,UGUI的难度相对更高一些; UI被多线程渲染影响的原因: 无论是UGUI,还是NGUI,都有一个特点,就是他的UI mesh可能会因为没有动静分离或别的原因产生一个网格的重建, 在网格重建之后,我们会发现它的半透明会非常的高,WaitingForJob会开销比较大,具体原因没有一个理论上的解释。 解决方案: 1.解决动静分离的问题 2.优化DrawCall 如何进行UI的动静分离: 首先要区分动态元素和静态元素的区别,静态元素就是比如主页面,都是静止的一些icon等,当你不去点击的时候都是精致的 动态的就是你改变了它的Active/Deactive或Instantiate/Destory 从UGUI或NGUI的底层来讲的话,就是要看哪些东西是引起了UI DrawCall的变化, 如果这个panel或canvas引起了DrwaCall的变化,那么可以认为是动态的 如果在一些帧中不变,那么可以认为是静态的; 对于NGUI中UIPanel.LateUpdate的优化,主要着眼于UIPanel的布局,其原则如下: 1.尽可能将动态UI元素和静态UI元素分离到不同的UIPanel中(UI的重建以UIPanel为单位),从而尽可能将因为变动的UI元素引起的重构控制在较小的范围内; 2.尽可能让动态UI元素按照同步性进行划分,即运动频率不同的UI元素尽可能分离放在不同的UIPanel中; 3.控制同一个UIPanel中动态UI元素的数量,数量越多,所创建的Mesh越大,从而使得重构的开销显著增加。比如,战斗过程中的HUD运动血条可能会出现较多,此时,建议研发团队将运动血条分离成不同的UIPanel,每组UIPanel下5~10个动态UI为宜。这种做法,其本质是从概率上尽可能降低单帧中UIPanel的重建开销。
物理模块:
物理模块的耗时跟Update其实是没有太大关系的,举个例子,比如物理模块的timestep默认为0.02,就是20毫秒更新一次, 如果游戏比较卡的话,比如一帧用了100ms,那么物理模块就要执行5次,耗时直接就上去了; 如果对物理模块完全没有使用的话,可以把0.02直接变成0.1,也就是100毫秒更新一次,对游戏运行不会有特别大的影响 如果对物理模块没有使用,并且FixedUpdate也没有使用的话,timestep值可以调的更高; Contacts数量:碰撞对数量 NGUI将UI控件都当做3D世界中的物体来做碰撞体,当碰撞对中出现UI碰撞对的时候,是因为NGUI将带有collider和rigidbody的同一深度的UI物体都当成了碰撞体。 解决方案:Edit/Project Setting/Physics,把ui和ui的碰撞去掉; Active Rigidbody数量小于50是比较好的,因为大家经常调用Rigidbody里面的API; 少量调用没有问题,如果某一帧里面大量Rigidbody大量在调用,会造成一些物理上的开销, 因为Rigidbody的physics是自己计算的,由于重力的原因,当我们移动时,跟mesh collider地表会有一个大的开销; [ 影响物理系统耗时的因素主要为Contacts数量(碰撞对数量)、Rigidbody API的使用情况和每帧的调用次数。 1.第一种情况是最为常见的引发物理模块耗时较大的原因,因此,我们在UWA性能报告中对其进行了详细的分析,如果你的报告中Contacts数量较高,切记要验证其合理性。 2.第二情况造成较大CPU开销的情况不多,不过如果你的项目是多角色游戏(比如MMO、MOBA、ARPG割草游戏等),那么你需要注意了。在我们优化过的一些项目中,通过Rigidbody API来移动GameObject位置(设置velocity、改变center等)确实会存在较高的性能开销。如果你的项目也有类似的做法,那么要时刻关注物理模块的开销了。 3.第三种情况同样也是目前引发物理模块耗时较高的原因。因为Unity引擎默认情况下,物理的更新频率是0.02s,即每20ms更新一次,所以,当你的项目比较卡时(开发过程中的项目在中低端设备上恐怕没几个是不卡的),物理模块会让你的项目更卡。举个例子,如果上一帧CPU耗时为100ms的话,那么物理模块会执行5次,从而进一步加大物理系统的耗时。这种情况下,物理模块的耗时是很有欺骗性的,你花了好长时间去研究物理的耗时,最后发现原来这个“锅”不是它的…所以,如果你的项目也遇到了这种情况,切记不要再上当了。
动画模块:
MeshSkinning.Update耗时越低越好,蒙皮网格的顶点的面片尽可能的降低,1500面片左右就非常合理; [
粒子系统:
unity5.3之后,粒子系统由主线程调到了子线程 ParticleSystem.ScheduleGeometryJobs 粒子系统的计算和准备 [ ParticleSystem.Update的优化建议: 1.严格控制粒子系统的active的数量,每一帧里面的数量越多,ParticleSystem.Update就越高,无论这个粒子系统是否在视域体里面 2.对于视域体外面的,可以根据一些具体情况看看ParticleSystem是否可以进行关闭,可以通过一些方式, 一.比如说直接就计算粒子系统它的一个距离,当距离比较远时,可以进行关闭; 二.其次就是算一个它的UV,就是往屏幕上做投影,发现它在屏幕外测的时候,也是可以尝试着进行关闭 三.在unity5.2之后,unity有一个很好的功能就是CullingGroup, CullingGroup可以告许你每一帧它是否在视域体外或者是它跟相机的一个距离 这样就会有效的降低ParticleSystem.Update的cpu性能开销。 根据移动设备对粒子系统进行管理,对于低端设备尽可能降低粒子系统的复杂程度和屏幕覆盖面积,从而降低其渲染方面的开销,提升低端设备的运行流畅性。具体做法如下: 1.在中低端机型上降低粒子数、同屏粒子数,比如仅显示“关键”粒子特效或自身角色释放的粒子特效等,从而降低Update的CPU开销; 2.尝试关闭离当前视域体或当前相机较远的粒子系统,离近后再进行开启,从而避免不必要的粒子系统Update的开销; 3.尽可能降低粒子特效在屏幕中的覆盖面积,覆盖面积越大,层叠数越多,其渲染开销越大; 4.对于Unity 5.x项目,可尝试升级到5.3以后版本,因为Unity在5.3版本后对粒子系统底层进行了深入的优化。
加载模块:
当GameObject数量和资源数量较高时,会造成RUUA CPU开销比较高,耗时会增高; [ 加载资源是放在Update里面合适还是放在协程里面: 一般是用协程,不过放在Update里面也没什么问题 目前大部分手游可以使用2048*2048的贴图;
GC调用:
调用频率是一个很重要的标准, 1.要尽可能的优化代码的堆内存,可以减少foreach,link的使用,减少stream关联等,这些问题并不是最主要的 最主要的是如果项目里的运行一万帧超过了20M,那么GC回来的很快,实际项目中会把代码都拆开, 然后定位到底哪个函数在这一万帧中分配了多少堆内存,所以其实并不是特别在意foreach,link使用,stream关联等 XML文件或者配置文件或者解密加密这一块经常会有几十M的堆内存分配,大部分的堆内存都是配置文件造成的 所以尽可能的要在1万帧以下小于20M,最高不要超过30M; 2.当堆内存降下来后,可以尝试放开手动的GC调用; GC释放策略: 在场景切换的时候进行一些GC的,会耗费100毫秒左右; 不建议在UI开启或关闭的时候进行 UWA视频链接:https://v.qq.com/x/page/x0378dxq4m3.html