Unity项目优化

 参考文章:

Unity优化记录 - 哔哩哔哩

Unity游戏优化最佳实践-游戏优化9种

Unity移动端性能优化总结

Unity Optimization Tips « Unity Coding – Unity3D

Learn how to optimize your Unity project | Habrador

Unity游戏项目常见性能问题 - 知乎

一些关于移动平台上Unity3D的性能优化经验,供分享。

Unity性能优化 – 设置篇 | Tim's Blog

Unity3D性能优化——工具篇 - 知乎

Profiler 窗口 - Unity 手册

Optimizing Graphics in Unity - Unity Learn

Optimizing for Performance - Unity Learn

Unity用户手册-性能优化 - 知乎

Unity3D研究院之使用Android的硬件缩放技术优化执行效率 | 雨松MOMO程序研究院

  • 导航网格 NavMesh.SamplePosition采样距离由 50 改为 2,25,50三段采样,调用七次的时间从 3.4ms 降至 0.86ms,CPU消耗减少6%左右

  • 带有Animator组件的Object频繁的SetActive会导致性能警告,使用移出屏幕的方式代替SetVisible

  • ILRuntime热更框架

  • foreach和使用while(iter.MoveNext())方式的遍历全部替换成for,两者在ILRuntime中都会产生内存垃圾,调用次数太多会触发垃圾回收,经测试foreach大概每次循环分配 47 Bytes,改成for以后不会造成GC Alloc。原生的foreach调用并不会造成GC Alloc,但是执行效率比for低一半。Dictionary类型的遍历可以使用List等可以用for遍历的容器辅助,必要时可以使用辅助容器多存储一份数据专门用来遍历,比如:

int key;
var iter = m_testDict.GetEnumerator();
while(iter.MoveNext()){
  key = iter.Current.Key;
}

或者:

int key;
foreach (var item in m_testDict){
    key = item.Key;
}
改为:
List<int> keys = m_testDict.Keys.ToList();
int key;
for (int i = 0; i < keys.Count; i++){
   key = keys[i];
}
  • 在ILRuntime中尽量去掉调用的空函数,比如空Update,因为空函数也会消耗时长,并不会被编译优化掉,真机测试空函数调用一次消耗0.1ms,而且调用空Update时Unity会在内部进行安全检查,检测挂载的对象是否有效。

  • 尽量不在Update函数中new对象,缓存频繁使用的对象,比如协程中new出来的 WaitForSeconds(时间常量);减少string类型对象的创建,相同的字符串只创建一次并且缓存使用,减少字符串操作,比如需要拼接字符串来Update一个Text组件,考虑将分割成两个Text组件其中一个来更新需要改变的部分,使用StringBuilder类操作字符串不会产生垃圾内存; 

  • 尽量不要在Update中使用Find,GetComponent等接口,改成在初始化函数中缓存组件和对象。设置Transform的位置旋转会引起内部所有子对象的计算,如果没有位置和旋转等改变不要对其进行设置,每次调用Transform.position都会导致世界坐标的计算,需要使用时缓存position的值,尽量用Transform.localPosition代替访问position,因为localPosition的值被存储在Transform中,不会每次访问时都计算;Camera.main会在内部调用Find()查找MainCamera,应该缓存下来使用;Mesh.normals[i]的访问会在内部生成新的数组,需要用 Vector3[] meshNormals = mesh.normals这样的方式缓存下来后使用;GameObject.name或 GameObject.tag的访问都会生成新的字符串,如需对比使用GameObject.CompareTag();

  • 尽量避免装箱操作,将值类型当作Object类型使用会导致创建新的Object,比如:

    int cost = 5;
    string str = String.Format("Cost: {0}",cost);//cost会被装箱放入新的Object中
    
    yield return 0;//0这样的数值会被装箱,改成 yield return null
    

  • 在Update等频繁调用的接口中使用全局变量(包括static变量),先引用为局部变量再使用,可以将执行效率提升一倍多,因为局部变量在栈上访问,速度可以快一倍多。例如:

for (int i = 0; i < 1000; i++){
   bool b = ChatMgr.singleton.IsInPublicChannel;
}
改为:            
ChatMgr chatMgr = ChatMgr.singleton;
for (int i = 0; i < 1000; i++){
  bool b = chatMgr.IsInPublicChannel;
}
  • Update中调用的逻辑如果不需要逐帧处理,改成使用协程处理或者每隔N帧(N秒)调用,将逻辑错开到不同帧中处理可以避免出现峰值,例如

  • private int interval = 3;
    void Update(){
       if(Time.frameCount % interval == 0){//每三帧调用一次
         ExampleExpensiveFunction();
       }else if(Time.frameCount % 2 == 1){
         AnotherExampleExpensiveFunction();
       }
    }
    
private float timeSinceLastCalled;
private float delay = 1f;//每秒调用一次
void Update(){
    timeSinceLastCalled += Time.deltaTime;
    if (timeSinceLastCalled > delay)
    {
        ExampleGarbageGeneratingFunction();
        timeSinceLastCalled = 0f;
    }
}

GC: 1.GC Alloc: 任何一次性内存分配大于2KB的选项。每帧都具有20B以上内存分配的选项 。2. Time ms:注意占用5ms以上的选项

GPU:

  1. 小心使用 Renderer.material,对其进行修改会导致内部复制出新的材质,打破动态合批,如果是单个不需要合批的对象可以使用 Renderer.sharedMaterial 访问材质,否则使用切换材质的方式修改表现。

  2. 不透明UI层级遮挡时禁用场景摄像机 

顶点优化:

  1. 模型优化,静态动态合批,减面减材质

  2. 使用LOD

  3. 使用遮挡剔除Occlusion Culling

像素优化:

  1. 控制渲染顺序,减少OverDraw,尤其是透明物体

  2. 尽量减少实时光照

带宽优化:

  1. 减少纹理大小

  2. 利用缩放

性能适配开关:

  1. 多线程渲染

  2. 分辨率缩放,硬件分辨率缩放,摄像机动态分辨率Unity%20-%20Manual%3A%20Dynamic%20resolution

  3. 每种后处理效果开关

  4. 使用简化版本Shader

  5. Blit Type 改为Auto

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

逍遥游侠

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值