首页 > 其他分享 >Unity手机游戏性能优化系列:针对CPU端的性能调优

Unity手机游戏性能优化系列:针对CPU端的性能调优

时间:2024-02-17 11:12:19浏览次数:23  
标签:动画 渲染 性能 Unity 调优 UI 模块 CPU Animator

做手机游戏开发的时,经常会遇到手机游戏的性能问题,手机游戏的性能问题可能有很多的方面,今天我们从CPU调优的角度来給大家介绍一下常用的CPU调优的一些经验和手段。这些经验和手段都有可能随着时间与环境的变化改变而改变,具体还是要以实际的为准,先定位性能问题,再上具体的手段。接下来我们从CPU的性能调优的角度来总结一下Unity手游开发中需要注意和优化CPU的一些点。我们把手机游戏的CPU调优分成几个模块,列举一下每个模块的一些经验,供大家参考。模块如下:

(1) 渲染模块;
(2) 物理模块;
(3) 动画模块与粒子系统;
(4) 逻辑代码优化;

渲染模块调优

渲染模块是游戏开发中的性能大户,首先建议开启多线程渲染模式,在Unity项目中Project Setting里面默认开启了Multithreaded Rendering的,建议大家一般不要去改。单线程渲染流程中,游戏每一帧执行的时候,先调用组件的Update, 做完大量的逻辑运算等,最后做渲染相关的指令调用。如果是单线程,就需要在主线程main thread里面去提交操作显卡,在过程中容易产生主线程等待外部设备的状态就绪等,照成卡顿导致帧率下降。而此时可能有其它的CPU核心处于空闲状态,所以为了发挥手机上的多核优势,我们可以把这部分用多线程来做,也就是是我们stats里面的render thread, 让其它的CPU核心去处理这个事情,而不是让主线程等在上面。对于开启了多线程的渲染的游戏来说,还会有Gfx.WaitForPresent,等待渲染完成,如果这个函数非常耗时,说明了,目前GPU的工作压力很大,这个时候就要考虑去优化GPU相关的内容。

影响渲染CPU执行效率的本质就是两个东西,一个是渲染的面数(Triangle), 一个是渲染提交的次数(Drawcall)。这个部分很多开发者就会陷入一个所谓的标准”手机上模型一般多少个面合适?”这种问题其实没有任何意义的,需要结合自己的游戏来进行实测。时空背景不一样,游戏玩法不一样结果就不一样。一半我们的做法就是到自己目标客户的机型上进行实测。在我们的Shader确定后的效果下,我们目标客户的机型上面能跑多少个面。然后我们结合游戏的玩法,这些面放在哪些地方。比如近距离我们的面就分配得多,远距离就分配得少。重要主角面分配得多,不重要物体的面分配得少。也可以通过LOD工具在低端手机上减少模型面数。Drawcall大家比较熟悉了,有动态合批,静态合批,SRP Batcher合批,GPU Instancing合批,具体可以参考教程《Unity 如何优化Drawcall》。还有一个被很多人忽视的就是Set Pass Call开销,在这个过程中,第一次加载Shader容易造成瞬间卡顿。Shader.CreateGPUProgram, 解决的方案是运行的时候做好Shader缓存,避免瞬间CPU卡顿。

渲染中还有一个比较让人容易忽视的问题就是culling, 当一个游戏场景中相机数目越多的时候culling的占比就可能会越高。另外如果场景中有很多的小物体,也可能会导致culling的耗时比较高,可以考虑动态加载分块显示,考虑使用Culling Group、Culling Distance来进行优化。另外还要注意一下开启了遮挡剔除Occlusion Culling带来的开销。我们开启遮挡剔除Occlusion Culling,确实降低了渲染的压力,但是同时也增加了CPU的计算,如果发现Occlusion Culling,是性能瓶颈的时候,最后需要进行开启与关闭来权衡利弊。同时Culling中有FinalizeUpdateRendererBoundingVolumes函数占用过高,说明现在在游戏运行过程中不断的更新物体的包围盒,这个时候,可能需要检查一下,哪些Skinned Mesh或者粒子导致了不断的更新包围盒,看能否避免。

在UGUI的优化中,主要是检查UI的逻辑响应函数是否占用过高,同时把不用事件响应的UI元素去掉选项”Raycast Target”, 这样不用在每个UI元素去检测用户是否有UI操作,减少EventSystem.Update()耗时开销。每个Canvas会调用BuildBatch为UI元素合并的Mesh。一旦UI元素发起移动,这样就会引发BuildBatch, 合并过程是在其它线程处理的,如果合并的消耗过大,就会导致主线程发起等待。这个是我们我们可以把静态的物体分到一个Canvas,动态的物体分到一个Canvas,这样,能降低合并的难度与合并的开销。UGUI的使用过程中也注意一下几个点:

(1)同一Canvas下的UI元素才能合批。不同Canvas即使Order in Layer相同也不合批;

(2)尽量使用图集,让UI Drawcall合并有可能;

(3)在同一Canvas下、且材质和图集一致的前提下,尽量把同一个图集的节点放一起渲染,避免打乱drawcall合批;

(4)将相关UI的Pos Z尽量统一设置为0,Z值不为0的UI元素只能与Hierarchy中相邻元素尝试合批,所以容易打断合批。

(5)对于Alpha为0的Image,需要勾选其CanvasRender组件上的Cull Transparent Mesh选项,否则依然会产生DrawCall且容易打断合批。

最后选取合适的渲染管线与策略也是渲染性能与效果的关键,比如使用URP做实时光照等。

物理模块调优

不使用物理引擎的项目,我们可以关闭物理引擎的Auto Simulation, 如果不用射线检测等,还可以关闭物理的射线检测(Auto Sync Transform)。物理引擎的迭代,主要是在FixedUpdate去迭代物理世界的Update,如果FixedUpdate的调用频率的次数越高,那么物理迭代次数就越高,更新越频繁。物理引擎的迭代参数设置,如图 1.1-1:

图1.1-1

Fixed Timestep: 独立于帧率,按照固定的时间间隔进行迭代,物理引擎就是基于它,迭代;

Maximum Allowed Timestep: 允许最大的时间步长, 物理计算的时间开销,不允许超过这个值,限定了单帧的物理计算的最大时间, 所以这个值越小,迭代的次数可能就越少。

可以通过调节这两个值来调整物理引擎的迭代次数与开销。由于FixedUpdate的迭代与帧率无关,所以不要在FixedUpdate里面写过多的复杂的逻辑。最后控制物理引擎中刚体的数目,这个结合自己的项目来做设定,用性能好的碰撞器来代替性能查的碰撞器。

动画模块与粒子系统

使用新版的Mechanic动画系统Animator控制动画代替传统的Legacy的Animation控制动画。功能上的好处比如人形动画就不说了,在性能上骨骼动画且曲线较多的动画,使用Animator的性能是要比Animation要好,因为Animator是支持多线程计算的, Animator还可以通过开启Optimized GameObjects进行优化。所以动画控制Animator比Animation要高效一些。还有一种就是动画在每个顶点在每一帧都Bake出来,用空间换时间的方法来做好处理,适合MOBA、SLG中的小兵具体可以参考《千人战斗场景优化》教程。

控制Active Animator的一个方法是针对每个动画组件调整合理的Animator.CullingMode设置。该设置有三个选项:

AlwaysAnimate:当前物体不管是不是在视域体内,或者在视域体被LOD Culling掉了,Animator的所有东西都仍然更新;其中,UI动画一定要选AlwaysAnimate,不然会出现异常表现。

CullUpdateTransforms: 当物体不在视域体内,或者被LOD Culling掉后,逻辑继续更新,就表示状态机是更新的,动画资源中连线的条件等等也都是会更新和判断的;但是Transform这些显示层的更新就不做了。在不影响效果的前提下把部分动画组件尝试设置成CullUpdateTransforms可以节省物体不可见时动画模块的显示层耗时。

CullComplete:完全不更新,适用于场景中相对不重要的动画效果,在低端机上需要保留显示但可以考虑让其静止的物体,分级地选用该设置。

Animator还有个很重要的标志就是开启Apply Root Motion,如果动画不发生位移,就不要开启这个选项,开启后可能会导致动画中Animator.ApplyBuiltinRootMotion开销过高。

当我们Active/Deactive一个Animator组件物体的时候,会导致Animator.Initialize函数的调用,当检测到这个开销比较大时,可以将其移出屏幕,比如关闭Animator组件,scale = 0,而代替activie/deactive。

Meshskinning.Update和Animators.WriteJob网格资源对于动画模块耗时的影响是十分显著的。一方面,Meshskinning.Update耗时较高时。主要因素为蒙皮网格的骨骼数和面片数偏高,所以可以针对网格资源进行减面和LOD分级。另一方面,默认设置下,我们经常发现很多项目中角色的骨骼节点的Transform一直都是在场景中存在的,这样在Native层计算完它们的Transform后,会回传给C#层,从而产生一定的耗时。在场景中角色数量较多,骨骼节点的回传会产生一定的开销,体现在动画模块的主函数之一PreLateUpdate.DirectorUpdateAnimationEnd的Animators.WriteJob子函数上。可以考虑勾选FBX资源中Rig页签下的Optimize Game Objects设置项,将骨骼节点“隐藏”,从而减少这部分的耗时。

粒子系统开销与粒子系统数量和Playing状态的粒子系统数量有关。前者是指内存中所有的ParticleSystem的总数量(包含正在播放的和处于缓存池中的);后者指的是正在播放的ParticleSystem组件的数量(包含了屏幕内和屏幕外),针对这两个数值,我们一方面关注粒子系统数量峰值是否偏高,可选中某一峰值帧查看到底是哪些粒子系统缓存着、是否都合理、是否有过度缓存的现象;另一方面关注Playing数量峰值是否偏高,可选中某一峰值帧查看到底是哪些粒子系统在播放、是否都合理、是否能做些制作上的优化。在底端机上就可以考虑控制这些粒子数量,或者干脆关闭粒子特效来让游戏流畅,具体可以从这个角度去操作与思考。

逻辑代码调优

逻辑代码编写就没有什么可说的了,平常注意一些开发代码的习惯,避免过的new 对象导致的GC等,提升算法的时间空间复杂度,用空间换时间,用时间换空间,多线程处理来发挥多核优势, 做好代码review。具体的结合自己的项目做好对应的处理。

今天的分享就到这里了,学习更多的Unity开发的相关知识 可以一起在学习小组交流哦。

标签:动画,渲染,性能,Unity,调优,UI,模块,CPU,Animator
From: https://www.cnblogs.com/bycw/p/18017800

相关文章

  • Unity资源管理系列:Unity 框架如何做好资源管理
    Unity资源管理需求分析作为架构师,在开始动手之前,先分析清楚需求,你才能设计出合理的方案,我们来分析一下Unity资源管理都有哪些需求,把需求想清楚了,设计是自然而然的事情。Unity资源管理主要需求:1:为开发与正式发布提供资源的加载/卸载;2:方便远程更新资源。3:带资源与不带资源......
  • Unity 类胡闹厨房游戏 KitchenChaos 阶段1整理记录
    原教程地址:https://youtu.be/AmGSEH7QcDg部分代码:usingSystem.Collections;usingSystem.Collections.Generic;usingUnityEngine;publicclassPlayerAnimator:MonoBehaviour{privateconststringIS_WALKING="IsWalking";[SerializeField]priv......
  • 【Redis】【高性能】Redis 批量查询技巧
    1  前言Redis,我们做开发的想必都用过,他是一种缓存,主要用于快速响应结果嘛。比如我们要获取商品的详情,有日销量、月销量、库存数量、评价数量,这些数据都在Redis缓存中,那么我们是要拿四趟?还是一趟呢?当然是一趟最好呀。接下来我们来看看为什么我们要一趟这么做,以及怎么做。2  ......
  • 【记录】 unity插件 Addressables
    介绍Addressables是Unity官方推出的用于资源热更的系统,可在PackageManager里面下载。安装可在PackageManager里面下载、安装即可使用配置Addressables配置使用基础Addressables使用远程分发Addressables远程分发......
  • 频繁调一个http请求和多个不同http请求性能一样吗
    在讨论频繁调用一个HTTP请求和多个不同HTTP请求的性能时,我们需要考虑几个关键因素,包括网络延迟、服务器处理能力、请求的复杂性以及网络带宽等。在某些情况下,频繁调用一个HTTP请求可能和多个不同HTTP请求具有相似的性能,但在其他情况下,这两种做法可能会产生截然不同的结果。以下是......
  • 性能测试-性能压测脚本的生成以及完善和增强
    1.通过JMeter代理服务器录制脚本为什么用JMeter做性能测试时要 设置客户端的代理JMeter在进行性能测试时,设置客户端代理的主要目的是为了监听和记录浏览器在相应端口的操作。通过设置代理,JMeter可以捕获和记录用户的网络请求和响应,从而模拟用户在真实场景中的行为,对系统进行性......
  • Lag-Llama:第一个时间序列预测的开源基础模型介绍和性能测试
    2023年10月,我们发表了一篇关于TimeGPT的文章,TimeGPT是时间序列预测的第一个基础模型之一,具有零样本推理、异常检测和共形预测能力。虽然TimeGPT是一个专有模型,只能通过API访问。但是它还是引发了对时间序列基础模型的更多研究。到了2024年2月,已经有了一个用于时间序列预测的开源......
  • 【性能测试】MYSQL锁和mysql事务问题排查04
    一、MYSQL锁目的:解决客户端并发访问冲突问题查看死锁showOPENTABLESwhereIn_use>0案例登录接口 #锁定表LOCKTABLESlitemall.litemall_userREAD;#睡眠160秒SELECTSLEEP(160);#解锁表UNLOCKTABLES;当用户表被锁定时,接口无法登录访问,解锁后可以正......
  • 【性能测试】MYSQL缓存命中率03
    一、查询缓存(querycache) 缓存命中率:所有的查询语句,命中缓存的请求数,占所有请求数的比例查看是否开启缓存命中率#缓存的开关showvariableslike'%query_cache_type%';#缓存的大小showvariableslike'%query_cache_size%';开启缓存设置MySQL的配置文件my......
  • MySQL - 创建高性能索引
    索引基础要理解MySQL中索引是如何工作的,最简单的办法就是去看看一本书的"索引"部分:如果想要在一本书中找到某个特定主题,一般会先看书的"索引",找到对应的页码在MySQL中,存储引擎用类似的方法使用索引,其先在索引中找到对应值,然后根据匹配的索引记录找到对应的数据行。假如要运行......