Unity3d性能优化(CPU)

简介: 性能优化是项目开发中一个永恒的话题。用户的需求和项目的要求总在不停地增长,同屏人数、屏幕特效和场景复杂度永远在向着“榨干”硬件的趋势逼近。所以,无论硬件设备发展到何种程度、研发团队有多么丰富的经验积累,性能优化依旧是一个令人棘手却又难以规避的问题。

性能优化是项目开发中一个永恒的话题。用户的需求和项目的要求总在不停地增长,同屏人数、屏幕特效和场景复杂度永远在向着“榨干”硬件的趋势逼近。所以,无论硬件设备发展到何种程度、研发团队有多么丰富的经验积累,性能优化依旧是一个令人棘手却又难以规避的问题。

项目的性能优化主要围绕CPU、GPU和内存三大方面进行。今天,我们就这三方面来谈谈当前普遍存在的性能问题和相应的解决方案。此文为第一篇:CPU专讲,同时如果各位在UWA上已经提交了性能测试,请结合报告阅读本文,效果更佳

img_1e2dec0a7f687d73666155aa096af9dd.jpe

通过大量的性能测评数据,我们发现渲染模块UI模块加载模块往往占据了游戏CPU性能开销的Top3。

渲染模块

渲染模块可以说是任何项目中最为消耗CPU性能的引擎模块。几乎所有的游戏或VR项目都离不开场景、角色和特效的渲染。对于渲染模块的优化,主要从以下两个方面入手:

降低Draw Call

Draw Call是渲染模块优化方面的重中之重。一般来说,Draw Call越高,则渲染模块的CPU开销越大。究其原因,要从底层Driver和GPU的渲染流程讲起,限于篇幅我们不在这里做过多的介绍。有兴趣的朋友可以查看以下链接中的说明(http://stackoverflow.com/questio ... raw-calls-expensive),或者自行Google相关的技术文献。

img_fb8f6ea3153cc75b6741ba3ebb4883d6.jpe

降低Draw Call的方法主要是减少渲染物体的材质种类,并通过Draw Call Batching来减少其数量。Unity文档对于Draw Call Batching的原理和注意事项进行了非常详细的讲解,感兴趣的朋友可查看其官方文档(http://docs.unity3d.com/Manual/DrawCallBatching.html)。

但是,需要注意的是,游戏性能并非Draw Call越小越好。这是因为决定渲染模块性能的除了Draw Call之外,还有用于传输渲染数据的总线带宽。当我们使用Draw Call Batching将同种材质的网格模型拼合在一起时,可能会造成同一时间需要传输的数据(Texture、VB/IB等)大大增加,以至于造成带宽“堵塞”,在资源无法及时传输过去的情况下,GPU只能等待,从而反倒降低了游戏的运行帧率。

Draw Call和总线带宽是天平的两端,我们需要做的是尽可能维持两者的平衡,任何一边过高或过低,对性能来说都是无益的。

简化资源

简化资源是非常行之有效的优化手段。在大量的项目中,其渲染资源其实是“过量”的,如过量的网格资源、不合规的纹理资源等等。所以,我们在UWA测评报告中对资源的使用进行了详细的展示,如每帧渲染的三角形面片数、网格和纹理资源的具体使用情况等。

img_d46d4cf08deb9187aec1a6323c86269e.jpe

我们知道,在项目中美术设计师对资源的把控可谓举足轻重。UWA测评中特有的项目管理功能,支持项目内成员相互邀请,使得开发团队能更高效地查找和完善存在问题的各种资源。

关于渲染模块在CPU方面的优化方法还有很多,比如LOD、Occlusion Culling和Culling Distance等等。我们会在后续的渲染模块专题中进行更为详细的讲解,敬请期待。

UI模块

UI模块同样是几乎所有项目中必备的

模块。一个性能优异的UI模块可以让用户体验再上一个台阶。在目前国内的大量项目中,NGUI作为UI解决方案的占比仍然非常高,因此UWA也对NGUI

的性能分析进行了深度的研究。我们会根据用户使用的UI解决方案(UGUI或NGUI)提供相应的性能分析和优化建议。

img_7a2e5ae6433eaa57097d240ffadeadf0.jpe

在NGUI的优化方面,UIPanel.LateUpdate为性能优化的重中之重,它是NGUI中CPU开销最大的函数,没有之一。UI模块制作的难点并不在于其表现上,因为UI界面的表现力是由设计师来决定的,但两套表现完全一致的UI系统,其底层的性能开销则可能千差万别。如何让UI系统使用尽可能小的CPU开销来达到设计师所期望的表现力,则足以考验每一位UI开发人员的制作功底。

通过对大量的UWA测评数据进行统计,我们将NGUI中CPU开销最为耗时的几个函数一一展示,并提供详细的CPU占用和堆内存分配。这样,研发团队既可以对UI系统的性能有更为清晰的了解,又可以结合运行截图对性能瓶颈进行直观的定位。

img_6d2ef48a02b6ac882a7a0972ccb605c8.jpe

对于UIPanel.LateUpdate的优化,主要着眼于UIPanel的布局,其原则如下:

尽可能将动态UI元素和静态UI元素分离到不同的UIPanel中(UI的重建以UIPanel为单位),从而尽可能将因为变动的UI元素引起的重构控制在较小的范围内;

尽可能让动态UI元素按照同步性进行划分,即运动频率不同的UI元素尽可能分离放在不同的UIPanel中;

尽可能让动态UI元素按照同步性进行划分,即运动频率不同的UI元素尽可能分离放在不同的UIPanel中;

控制同一个UIPanel中动态UI

元素的数量,数量越多,所创建的Mesh越大,从而使得重构的开销显著增加。比如,战斗过程中的HUD血条可能会大量出现,此时,建议研发团队将运动血条

分离成不同的UIPanel,每组UIPanel下5~10个动态UI为宜。这种做法,其本质是从概率上尽可能降低单帧中UIPanel的重建开销。

另外,限于篇幅限制,我们在此仅介绍NGUI中重要性能问题,而对于UGUI系统以及UI系统自身的Draw Call问题,我们将在后续的UI模块专题中进行详细的讲解,敬请关注。

加载模块

加载模块同样是任何项目中所不可缺少的组成部分。与之前两个模块不同的是,加载模块的性能开销比较集中,主要出现于场景切换处,且CPU占用峰值均较高。

这里,我们先来说说场景切换时,其性能开销的主要体现形式。对于目前的Unity版本而言,场景切换时的性能开销主要体现在两个方面:前一场景的场景卸载和下一场景的场景加载。下面,我们就具体来说说这两个方面的性能瓶颈:

场景卸载

场景卸载一般是由引擎自动完成的,即当我们调用类似Application.LoadLevel的API时,引擎即会开始对上一场景进行处理,其性能开销主要被以下几个部分占据:

(1)Destroy.

引擎在切换场景时会收集未标识成“DontDestoryOnLoad”的GameObject及其Component,然后进行Destroy。同时,

代码中的OnDestory被触发执行,这里的性能开销主要取决于OnDestroy回调函数中的代码逻辑。

(2)Resources.UnloadUnusedAssets.

一般情况下,场景切换过程中,该API会被调用两次,一次为引擎在切换场景时自动调用,另一次则为用户手动调用(一般出现在场景加载后,用户调用它来确保

上一场景的资源被卸载干净)。在我们测评过的大量项目中,该API的CPU开销主要集中在500ms~3000ms之间。其耗时开销主要取决于场景中

Asset和Object的数量,数量越多,CPU开销越大。

img_60f5136d64f751241c18fc393997d9c5.jpe

场景加载

场景加载过程的性能开销又可细分成以下几个部分:

(1)资源加载

。资源加载几乎占据了整个加载过程的90%时间以上,其加载效率主要取决于资源的加载方式(Resource.Load或AssetBundle加载)、

加载量(纹理、网格、材质等资源数据的大小)和资源格式(纹理格式、音频格式等)等等。不同的加载方式、不同的资源格式,其加载效率可谓千差万别,所以我

们在UWA测评报告中,特别将每种资源的具体使用情况进行展示,以帮助用户可以立刻查找到”问题资源“并及时进行改正。

(2)Instantiate实例化

。在场景加载过程中,往往伴随着大量的Instantiate实例化操作,比如UI界面实例化、角色/怪物实例化、场景建筑实例化等等。在

Instantiate实例化时,引擎底层会查看其相关的资源是否已经被加载,如果没有,则会先加载其相关资源,再进行实例化。这其实是大家遇到的大多数

“Instantiate耗时问题”的根本原因,也是为什么我们在之前的AssetBundle文章中所提倡的资源依赖关系打包并进行预加载,从而来缓解

Instantiate实例化时的压力(关于AssetBundle资源的加载又是另一个很深远的话题,我们会在以后的AssetBundle加载专题中

进行详细的讲解)。

img_b9d6acecac76cca1c8120159f37c4e78.jpe

另一方面,Instantiate实

例化的性能开销还体现在脚本代码的序列化上,如果脚本中需要序列化的信息很多,则Instantiate实例化时的时间亦会很长。最直接的例子就是

NGUI,其代码中存在很多SerializedField标识,从而在实例化时带来了较多的代码序列化开销。因此,这一点是大家在为代码增加序列化信息

时需要时刻关注的。

以上是游戏或VR项目中性能开销最大的三个模块。当然,游戏类型的不同、设计的不同,其他模块仍然会有较大的CPU占用。比如,ARPG游戏中的动画系统和物理系统,音乐休闲类游戏中的音频系统和粒子系统等。对此,我们会在后续的技术专题中进行深入的讲解。

代码效率

逻辑代码在一个较为复杂的项目中往往占据较大的性能开销。特别地,在MOBA、ARPG、MMORPG等移动游戏类型中非常多见。

img_e92e00c35a0503e85238310e9bd177a5.jpe

在项目优化过程中,我们经常会想知

道,到底是哪些函数占据了大量的CPU开销。同时,绝大多数的项目中其性能开销都遵循着“二八原则”,即80%的性能开销都集中在20%的函数上。所以,

我们在UWA测评报告中将项目中代码占用的CPU开销进行统计,不仅可以提供代码的总体累积CPU占用,还可以更近一步看到函数内部的性能分配,从而帮助

大家更快地定位逻辑代码的性能瓶颈。

img_694395ce2195e659410fb2813f649f34.jpe
img_c4d6aa87062f79f3c2ffbd573fd86b1d.jpe

当然,我们还希望可以为大家提供更多信息,比如更为具体的性能分配、更为准确的截图信息等等。这些都是我们目前正在努力研发的功能,并将在后续版本中提供给大家进行使用。

img_7a4eca2de27b70bfa84d03310232ed43.jpe

相关文章
|
3月前
|
图形学 iOS开发 Android开发
从Unity开发到移动平台制胜攻略:全面解析iOS与Android应用发布流程,助你轻松掌握跨平台发布技巧,打造爆款手游不是梦——性能优化、广告集成与内购设置全包含
【8月更文挑战第31天】本书详细介绍了如何在Unity中设置项目以适应移动设备,涵盖性能优化、集成广告及内购功能等关键步骤。通过具体示例和代码片段,指导读者完成iOS和Android应用的打包与发布,确保应用顺利上线并获得成功。无论是性能调整还是平台特定的操作,本书均提供了全面的解决方案。
156 0
|
4月前
|
存储 Java 图形学
UNITY性能优化☀️一、GC介绍与Unity内存管理方法
UNITY性能优化☀️一、GC介绍与Unity内存管理方法
|
7月前
|
机器学习/深度学习 并行计算 Android开发
Int8量化算子在移动端CPU的性能优化
Int8量化算子在移动端CPU的性能优化
209 0
|
7月前
|
缓存 编译器 调度
【C/C++ 性能优化】了解cpu 从而进行C++ 高效编程
【C/C++ 性能优化】了解cpu 从而进行C++ 高效编程
401 0
|
机器学习/深度学习 缓存 Linux
很底层的性能优化:让CPU更快地执行你的代码
很底层的性能优化:让CPU更快地执行你的代码
|
缓存 负载均衡 Linux
【车载性能优化】将线程&进程运行在期望的CPU核心上
如果我们能够将程序的**进程**或**线程**运行在指定的CPU核心上,原则上就可以实现动态调节应用的执行效率。实现这种需求要用到一个Linux的函数—`sched_setaffinity`。
664 0
【车载性能优化】将线程&进程运行在期望的CPU核心上
|
机器学习/深度学习 人工智能 Linux
TensorFlow 2.9上线:oneDNN改进实现CPU性能优化,WSL2开箱即用
TensorFlow 2.9上线:oneDNN改进实现CPU性能优化,WSL2开箱即用
322 0
|
SQL 监控 前端开发
网页性能优化实战之CPU拉满问题处理
今天测试小哥屁颠屁颠的找过来说查询会员信息这块访问速度很慢,之前没有问题,现在输入信息之后根本就没有反应.要等好好长时间才行.另外点击其他页面都是显示网络连接异常,感觉整个系统都会崩溃了。每次测试找过来都当做是对自己的一次技术提升,尤其是对和业务逻辑关联不高的问题更感兴趣,哈哈!现在把问题分析以及处理过程简单记录一下,希望对有相同线上问题的同学能提供一些解决思路.
网页性能优化实战之CPU拉满问题处理
|
Linux BI 开发者
Linux性能优化之cpu性能评估工具| 学习笔记
快速学习Linux性能优化之cpu性能评估工具。
Linux性能优化之cpu性能评估工具| 学习笔记
|
应用服务中间件 Linux PHP
嵌入式实践教程--Linux性能优化实战之CPU使用率满载怎么办
嵌入式实践教程--Linux性能优化实战之CPU使用率满载怎么办
嵌入式实践教程--Linux性能优化实战之CPU使用率满载怎么办