Unity 性能优化方案

‌Unity性能优化的主要方案包括以下几个方面‌:

一、减少Draw Call‌

Draw Call就是CPU调用图形编程接口,是CPU向GPU发送的命令

1.CPU和GPU并行工作的原理

CPU和GPU工作有一个命令缓冲区(Command Buffer)

命令缓冲区包含了一个命令队列,由CPU向其中添加命令,而由GPU从中读取命令。当CPU需要渲染一些对象时,它可以向命令缓冲区添加命令,而GPU完成了上一次的渲染任务后,它就可以从命令队列里取出一个命令并执行它。

命令缓冲区中的命令有很多种类,而Draw Call是其中的一种,其它命令还有改变渲染状态等命令(改变使用的Shader,使用不同的纹理等)。

2.为什么 Draw Call多了会影响帧率?

在每次调用Draw Call之前,CPU需要向GPU发送很多内容,包括数据,状态,命令等。CPU完成了这些准备工作,GPU就可以开始本次的渲染。如果Draw Call的数量太多,CPU就会把大量时间花费在提交Draw Call命令上,造成CPU的过载。

3.如何减少DrawCall?

DrawCall是CPU调用底层图形接口。比如有上千个物体,每一个的渲染都需要去调用一次底层接口,而每一次的调用CPU都需要做很多工作,那么CPU必然不堪重负。但是对于GPU来说,图形处理的工作量是一样的。所以对DrawCall的优化,主要就是为了尽量解放CPU在调用图形接口上的开销。所以针对drawcall我们主要的思路就是每个物体尽量减少渲染次数,多个物体最好一起渲染。所以,按照这个思路就有了以下几个方案:

·通过把纹理打包成图集来尽量减少材质的使用,相同的材质直接共用。

·尽量少的使用反光阴影之类的,因为会使物体多次渲染。

·mesh合并,减少CPU需要提交的模型信息次数。

·使用GPU Instance一次绘制多个相同的物体。

·优化shader 减少pass通道

·注意OverDraw

·合理规划场景中的物体层级‌

二、优化渲染性能‌

1.纹理压缩‌:使用适当的纹理压缩格式可以显著减少内存使用和GPU负担。Unity支持多种压缩格式,如ETC2、PVRTC等‌。

‌2.减少模型数量和三角形面数‌:通过减少模型数量和使用法线贴图代替细节模型来优化渲染性能‌。

‌3.使用LOD技术‌:根据物体与摄像机的距离调整模型的细节级别,减少远距离物体的渲染负担。

4.Occlusion Culling-遮挡剔除:只渲染在视野内的游戏物体,可以很大的优化我们的性能。

5.减少是实时光照的使用,使用光照贴图。

三、优化物理计算‌

‌1.减少物理组件的使用‌:只在必要的GameObject上添加物理组件(如Rigidbody、Collider),避免不必要的物理计算‌。如果可以使用BoxCollider等简单的,尽量不要使用meshcollider。

‌2.调整物理引擎设置‌:通过调整物理引擎的精度和迭代次数,例如减少Fixed Timestep,可以提高帧率但可能牺牲物理模拟的准确性‌。

四、内存管理‌

1.卸载非活动资源‌:使用Resources.UnloadUnusedAssets()函数卸载当前未使用的资源,减少内存占用‌。

五:代码优化‌:

1.提高代码效率

·减少循环的执行次数和循环中的指令数目。

·将不需要频繁执行的方法从 Update() 中移出。

·只在变化发生时才去执行代码。例如,不对未变化的量进行反复的输出。

·将需要频繁执行且不能通过事件触发的方法改为每隔几帧执行一次。例如,记录帧数(Time.frameCount)并通过模运算跳过某些帧,通过该方式,也能做到让几个方法不在同一帧中执行。

·使用缓存存储需要反复获取和使用的值。例如,将GetComponent()方法的返回值存储到变量中,避免反复获取。

·根据需求选用正确的数据结构,尤其是在数据驱动的开发模式中。

·使用对象池优化内存使用和降低CPU开销。创建和销毁对象的开销通常要比激活(SetActive(true))和取消激活对象的开销更高,尤其是对于那些含有初始化内容的对象,如发射子弹。

2.避免调用高开销的Unity API

·SendMessage()和BroadcastMessage()。在了解项目结构的前提下,SendMessage()和BroadcastMessage()方法使用起来非常灵活而且容易实现,但它使用了反射,而反射会造成更多的CPU开销。在清楚要调用哪个组件的哪个方法时应该通过组件的引用直接调用方法;在不清楚具体要用的组件和方法时,考虑使用 委托和事件。

·Find()方法会遍历内存中的每个GameObject和组件,随着项目规模的扩张,它的开销将会越来越大。不要频繁的使用Find()和与其类似的方法,可以考虑在Inspector中设置对对象的引用,或者创建一个专门用于管理需要搜索的对象的引用的脚本,包括Camera.main 类似。

·Transform。localPosition存储在transform中,访问该值时,Unity会直接将其返回,而position在每次访问时都会重新计算,如果要经常获取position,可以将其缓存起来。

·Update()和LateUpdate()等事件方法的每次调用都需要引擎代码与托管代码之间进行通信,还要Unity进行安全检查(GameObject状态是否合法等),即使这些事件方法的方法体是空的,引擎任然会对其进行调用。因此,为避免浪费CPU时间,应该 删除空的事件方法。另外,如果某个活动状态(gameObject.active == true)的GameObject上的脚本中含有Awake()方法,即使这个脚本没有被启用(enabled==false),Awake()方法也会执行。如果游戏中含有非常多的带有Update()方法的MonoBehavior,应该尝试改变代码结构来减少开销。

·Vector2 Vector3。向量的数学运算要比普通的浮点数和整数的数学运算更加复杂,访问向量的某些属性可能会带来隐含的开销,例如magnitude属性(不仅针对向量,例如上文提到的Transform.position)。每次访问magnitude,引擎都会进行开平方运算,虽然单次计算并不会消耗多少时间, 但当数量级足够大时,这种开销将变得明显。可以尝试使用sqrMagnitude(即magnitude的平方)替代magnitude,减少开平方操作。

相关推荐
明明明h9 小时前
Unity Assembly Definition & Assembly Definition Reference
unity·游戏引擎
龙中舞王9 小时前
Unity学习笔记(4):人物和基本组件
笔记·学习·unity
无敌最俊朗@13 小时前
unity3d————协程原理讲解
开发语言·学习·unity·c#·游戏引擎
夜色。13 小时前
Unity6 + Android Studio 开发环境搭建【备忘】
android·unity·android studio
2402_8575893615 小时前
Spring Boot编程训练系统:实战开发技巧
数据库·spring boot·性能优化
爱搞技术的猫猫15 小时前
实现API接口的自动化
大数据·运维·数据库·性能优化·自动化·产品经理·1024程序员节
这不比博人传燃?18 小时前
传奇996_19——常用函数
游戏引擎
erxij19 小时前
【游戏引擎之路】登神长阶(十四)——OpenGL教程:士别三日,当刮目相看
c++·经验分享·游戏·3d·游戏引擎
咩咩觉主20 小时前
尽量通俗易懂地概述.Net && U nity跨语言/跨平台相关知识
unity·c#·.net·.netcore