大概记录遇到的可以优化的点。
1.Mesh.UploadMeshData:预先把网格送到GPU
unity是这样的,它对一个网格,先把它搞到内存,然后在第一次渲染它时把它送到GPU。但送GPU经常是个瓶颈,所以我们可以提前(没渲染前)分帧送,减轻掉帧压力,
并且UpdateMeshData(true)的话,会把内存的网格卸掉,省内存(但这样就不能改变此网格了,因为内存没网格了),不过我们一般很少更新网格,所以可以用来优化内存。
2.纹理压缩
在很多情况下,美术会觉得纹理压缩后效果不理想。我们建议的是:可以把原图的分辨率长宽都扩大一倍,保持原有压缩格式。
这样压缩过后的文件还是比不压缩的文件要小,并且视觉效果可以得到较大的改善。
3.去掉纹理导入设置中的 Read/Write Enabled 勾选状态
4.去掉模型文件导入设置中 Read/Write Enabled 勾选状态
除了需要脚本中访问的网格,作为网格碰撞器中的网格,脚本中用StaticBatchingUtility.Combine静态合批的网格,以及粒子系统发射的网格之外,
其它模型建议不要勾选此项 ,否则会在内存也保留一份网格实例占用内存。
5.勾选模型导入设置[Rig]选项页中Optimize GameObject,建议勾选,而对作为挂点需要保留的骨骼添加为“例外”就不会被优化掉。
6.不要频繁调用的Camera.main
建议脚本做好Main Camera的Cache。Camera.main实际为GameObject.FindGameObjectsWithTag(“MainCamera”)调用,
主要因为引擎无法得知用户通过脚本设置的MainCamera,CPU消耗较高。
7.减少脚本中UnityEngine.Object的判等操作(不是判空)
建议改为用InstanceID来判断即Object. GetInstanceID,运行期间保证唯一。 因为Object的判等还有额外的耗时操作。
同理,使用Object作为key的数据结构也建议改用InstanceID做key,因为作为key一般都有大量判等操作。
8.少用list来存储数据
List线性结构Contains的耗时非常高,建议改为hashset,hashtable之类的查询操作效率高的数据结构。
9.限制加载资源时每帧从Assetbundle加载的Asset数量
在场景内每帧从Assetbundle加载的Asset数建议限制在2到5个,数量高时耗时过长容易造成卡顿。
10.控制静态变量的使用,特别是引用大资源的静态变量
一些内存占用较大的资源如纹理,因为有静态索引而无法在切换场景或者调用UnloadUnusedAssets时被卸载掉,因此内存的泄漏量会随着用户切换场景的次数而增加。
11.因为mono内存池只增不减,所以一下子加载大资源,或者在释放资源之前/GC.Collect之前不断加载资源,会使得内存池变大,所以要挑好时机释放资源和GC.Collect,
memory profiler的Reserved Total/Unity/Mono的大小很大的话就要注意了。
另外一个容易忽视的点是:函数内的内存分配,如果一个函数分配很多内存,就可能使得内存池变大或者引发GC而造成卡顿(mono分配新内存如果池子木有空闲内存就先gc,还是不够就扩张池子),我们可以把临时变量抽取出来,优化里面分配的数据结构,尽量
减少一下子分配大内存的情况,并且分配完记得及时归还等。
12.减少特效渲染的Pass数量
一些特效的渲染可以合并到同一个Pass以节省GPU开销,另外RenderTexture在可以共用的情况下尽量共用

13.同屏顶点不要超过20W个,尽量在10W个以下。

14.大量使用AssetBundle情况下,要及时Unload掉它。

  Q:我们项目的资源主要使用AssetBundle动态加载资源,发现Profiler中Detailed模式下PersistentManager.Remapper一项占用时多时少,这一项主要是做什么的呢?
  A:Remapper主要提供文件的持久化存储,包括各种序列化的asset,项目的setting文件等,维护文件系统的中的文件与内存中数据的对应关系。那么如果项目大量使用AssetBundle的话,在对AssetBundle进行Unload之前都会需要占用Remapper的内存的。而Remapper本身的实现使用内存池,其数值只会增大,那么为了使Remapper占用的内存保持在一个稳定的数值上,我们需要每次在加载一定数量的AssetBundle之后进行Unload操作,而不要一次性把所有AssetBundle都加载后才调用Unload。(这样的操作对维持整个mono heap的大小也是至关重要的,因为mono heap本身也是只增大不减小的)
15.对于局部数据,使用结构体而不是类。类被存储在堆;而结构体被存储在栈。分配在堆上会被GC。
16.一篇性能Profiler文章,可观:记一次Unity Profiler
17.静态合批
  1.为何要静态合批?静态批处理的基本原理每次渲染,CPU要做SetPass和调用DC,SetPass就算设置渲染状态,属于比较重要的分工,对于加载到游戏中的资源和对象等,CPU需要计算其顶点相关的矩阵,渲染所用的贴图,渲染所用到的材质和shader,渲染所用到的灯光等,即给Shader准备数据。正常情况下,我们需要给每个渲染对象设置渲染状态,这个有点耗,但如果使用静态合批,对许多渲染对象就只需要设置一次渲染状态,但前提是参与合批的渲染对象,他们的渲染状态要一样,即贴图,材质,shader要一致,不然无法合批。其实在unity 引擎内部做了优化,里面先对渲染对象排序,渲染状态一样(贴图/材质/shader一样)的对象相邻,这样在不合批时,也不会太耗(一样的就不用重新setpass了)。但我们不仅要关注setpass,还要关注dc,对于DC,不合批则每个渲染对象一个DC,合批后因为是当成一个对象来渲染,DC就变为1了,。所以在引擎的优化下,静态合批反而是对减少DC有极大提高。
  2.静态合批时,Unity引擎做了什么?把合批的对象的网格组合起来,生成一个大网格,并且网格顶点都变换到世界坐标系(所以合批的对象不能移动等,同时也不用CPU上做顶点转换,优化了性能),每个对象,都有一个索引,指向大网格中自己对应的那部分顶点数据。渲染时,即使只渲染一部分对象,也需要把整个网格加载到内存,然后送给GPU,让GPU去裁切(关于这点,是我胡乱总结的,做不得准,但看起来挺合理的,或许CPU也做了一些抛弃处理比如disable的对象的顶点数据不传过去等),所以静态合批会使用更多内存,但却少了SetPass和DC。另外地,除了渲染状态要一致,静态合批对合批后的总顶点也有限制,上限是65536。
  3.因为静态合批真的把网格合批了,所以要注意使用,一般合批不同几何外形的网格;而像网格相同的物体,不合批的话内存只有一份网格,合批的话就N份了,这个时候就不要合批了,比如浓密的森林,要是把整个森林合批了,那内存大概会爆了吧。
  4.听一位前辈说,静态渲染需要保留一份网格在内存,不好,他经历一个项目是这么做的:把需要静态渲染的所有物件一起烘焙成一个大网格,并且去掉Read/Writeable选项,这样,提交到GPU后,就自动把内存的网格卸载了,挺好,只不过需要额外处理:美术更改场景时需要重新烘焙大网格;注意不同材质的物件烘焙时可能有些问题(可以用meshbaker插件搞定)等。这种方法经过我测试,确实能够把网格从内存卸载掉!
18.动态合批,动态合批是unity自己做的,我们只需在Player setting里开启即可。而我们剩下要做的就是为物体提供动态合批的条件:单个模型顶点属性集数目小于900,材质一样,木有缩放(或者大家都缩放),木有镜像(scale=1,1,1和scale=-1,-1,-1是不能合批的),不使用mutil-pass shader等,不过动态合批虽然少了dc(搞成一个大网格),但只要其中一个变了,其余的也都一起计算顶点变换(在cpu),一起送到gpu(我猜的),要根据实际性能选择。
19.项目特效优化:
  1)图集优化:特效使用了多个贴图,多个材质,优化:像ngui一样把多贴图搞成图集,共用材质,这样,他们就可以动态合批了(ngui则自己生成一个网格,倒有些类似)。
  2)动作优化:
  3)特效再优化:

记录Unity的优化tip(不断更新)的更多相关文章

  1. Unity性能优化(3)-官方教程Optimizing garbage collection in Unity games翻译

    本文是Unity官方教程,性能优化系列的第三篇<Optimizing garbage collection in Unity games>的翻译. 相关文章: Unity性能优化(1)-官 ...

  2. Unity性能优化(4)-官方教程Optimizing graphics rendering in Unity games翻译

    本文是Unity官方教程,性能优化系列的第四篇<Optimizing graphics rendering in Unity games>的翻译. 相关文章: Unity性能优化(1)-官 ...

  3. Unity性能优化(2)-官方教程Diagnosing performance problems using the Profiler window翻译

    本文是Unity官方教程,性能优化系列的第二篇<Diagnosing performance problems using the Profiler window>的简单翻译. 相关文章: ...

  4. Unity 性能优化(力荐)

    开始之前先分享几款性能优化的插件: 1.SimpleLOD : 除了同样拥有Mesh Baker所具有的Mesh合并.Atlas烘焙等功能,它还能提供Mesh的简化,并对动态蒙皮网格进行了很好的支持. ...

  5. Unity性能优化(1)-官方教程The Profiler window翻译

    本文是Unity官方教程,性能优化系列的第一篇<The Profiler window>的简单翻译. 相关文章: Unity性能优化(1)-官方教程The Profiler window翻 ...

  6. Unity内存优化(贴图层面)

    聊聊近况: 距离上一篇文章已经过了好久,主要原因是我懒了.公司项目也到了开始优化的阶段,上网找的资料,看过了就忘.还是想把它整理一下,写出来.其实我说的东西,网上都有,我只是搬运工而已. 贴图压缩: ...

  7. Unity 代码编译成dll 更新dll实现热更代码

    Unity 代码编译成dll 更新dll实现热更代码 实现流程 代码编译成DLL DLL打包成AssetBundle 加载AssetBundle 加载代码程序集 获取指定类 使用反射赋值 C#代码编译 ...

  8. Unity全面优化

    前言 Unity的项目优化已经是老生常谈,很多人在项目完成之后,即便创意新颖,也会觉得差强人意,原因就在于没有做详细的项目优化.众所周知,Unity是一个综合性的3D开发引擎,其中包含图像渲染,逻辑处 ...

  9. Unity内存优化技术测试案例

    笔者介绍:姜雪伟,IT公司技术合伙人,IT高级讲师,CSDN社区专家,特邀编辑,畅销书作者,已出版书籍:<手把手教你架构3D游戏引擎>电子工业出版社和<Unity3D实战核心技术详解 ...

随机推荐

  1. JVM系列之:JIT中的Virtual Call

    目录 简介 Virtual Call和它的本质 Virtual Call和classic call Virtual Call优化单实现方法的例子 Virtual Call优化多实现方法的例子 总结 简 ...

  2. python IF while逻辑判断语句

    if判断语句 if 1==1 and 2==2: pass else: print('error') if 1==1 or 2==2: pass else: print('error') while循 ...

  3. kubernetes 中安装 heapster 问题

    step1: 在官网下载部署文件 https://github.com/kubernetes-retired/heapster/tree/master/deploy/kube-config/influ ...

  4. 付费?是不可能的!20行Python代码实现一款永久免费PDF编辑工具

    PDF(Portable Document Format),中文名称便携文档格式是我们经常会接触到的一种文件格式,文献.文档…很多都是PDF格式.它以格式稳定的优势,使得我们在打印.分享.传输过程中能 ...

  5. C、C++、boost、Qt在嵌入式系统开发中的使用

    概述 嵌入式系统开发相对来说属于偏底层的开发,也就是与硬件结合比较紧密,只能使用C/C++语言.对于做平台开发的人来说,C语言真的是很"古老"的语言,属于操作系统语言!好多人会觉得 ...

  6. 痞子衡嵌入式:恩智浦i.MX RT1xxx系列MCU启动那些事(13.A)- LPSPI NOR启动时间(RT1170)

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是恩智浦i.MX RT1170 1bit SPI NOR恢复启动时间. 本篇是i.MXRT1170启动时间评测第三弹了,前两篇分别给大家评 ...

  7. Python精选库大全,建议收藏留用!

    Python为啥这么火,这么多人学,就是因为简单好学,功能强大,整个社区非常活跃,资料很多.而且这语言涉及了方方面面,比如自动化测试,运维,爬虫,数据分析,机器学习,金融领域,后端开发,云计算,游戏开 ...

  8. 解决Xshell 工具连接不上VirtualBox虚拟机

    初次尝试用VirtualBox安装Linux虚拟机,却遇到了一些问题,特地记录于此,方便后面查阅! 首先简易记录下安装Linux虚拟机过程: 大致经过如下步骤:新建虚拟电脑,加载Linux版本镜像安装 ...

  9. pandas | 详解DataFrame中的apply与applymap方法

    本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是pandas数据处理专题的第5篇文章,我们来聊聊pandas的一些高级运算. 在上一篇文章当中,我们介绍了panads的一些计算方法, ...

  10. C#LeetCode刷题之#345-反转字符串中的元音字母​​​​​​​(Reverse Vowels of a String)

    问题 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/3935 访问. 编写一个函数,以字符串作为输入,反转该字符串中的元 ...