Unity优化方面的一些小总结

时间:2024-03-14 19:41:06

前言:

我做了3年的Unity了,但是却没有深入优化模块的内容,只能怪自己做项目的时候做的内容太杂乱了。去面试的时候被面试官问道优化方面的内容的时候自己一脸懵逼。本来有机会去MK的,让自己错失了。 所以自己将优化的内容做一个小小的总结,后续再做细化的研究。

正文:

根据性能指标设定优化目标

游戏的性能指标有:帧率,稳定性(卡顿),等待时间(Loading),内存占用(手机上最重要指标,绝大部分闪退的原因,理想值是内存占用低于150M),安装包大小,网络延迟,网络流量,耗电量(手机比较重要,限帧)等等。

根据性能指标设定优化目标

一般来说游戏优化也遵循28原则,游戏优化又是很费时费力的一件事,我们需要找出性能瓶颈。按照优先级来进行优化。

望闻:根据优化目标,先大概分析一下性能指标。包括帧数多少,是否稳定,是否存在卡顿。较长时间运行,发热量如何,是否存在闪退。安装包多大。网络流量多大等。找到最优先需要解决的点。

问:询问相关开发人员性能热点大概从什么时候开始出现。我们之前的项目在开发到中后期会找测试同学测试每日构建的版本,及时监控性能指标,第一时间发现性能瓶颈,发现越早越容易优化。

切:通过一些工具分析来进行深度的分析,必要时需要自己开发分析工具,定位热点。

优化工具

https://mp.csdn.net/mdeditor/88038813#

Unity需要优化的前提是安装包过大或者运行时候卡。
需要进行优化的地方有:
1.渲染优化
1.CPU GPU分工
2.LOD层级细节
3.Occlusion Culling-遮挡踢出
4.Lightmapping-光照贴图
5.合并Mesh
6.Gpu Instance
7.FPS优化
2.代码优化
3.资源优化
1.资源优化的标准
2.模型优化
3.贴图优化
4.如何减少冗余资源和重复资源
5.资源的检测和分析
6.合并材质球
4.DrawCall优化

一、渲染优化

1.CPU和GPU的分工

    CPU是负责游戏逻辑的,GPU是负责显示特效

2.LOD - 层级细节

   		  LOD 即 Levels of Detail 的简称 , 意为多细节层次 . LOD技术指根据物体模型的节点在显示环境中所处的位置和重要度 , 可根据距离动态地选择渲染不同细节的模型 , 决定物体渲染的资源分配 ,
从而获得高效率的渲染运算 . 是最常用的游戏优化技术 .
   		  优点 : 			降低非重要物体的面数和细节度,从而获得高效率的渲染运算 .
   		  缺点 : 			加重美工的负担 , 要准备不同细节的同一模型 . 			会稍微增加游戏的容量 .

3.Occlusion Culling-遮挡踢出

http://blog.csdn.net/cartzhang/article/details/52684127

4.Lightmapping-光照贴图

https://www.cnblogs.com/tgycoder/p/4853534.html

5.合并Mesh

  http://blog.csdn.net/chenggong2dm/article/details/41699029 	
  Mesh Baker

1.静态合并

  手动勾选为Static,所有被勾选了“Static”的GameObject,其中的Mesh Filter中的mesh都会被合并到 "Combined Mesha (root: scene)" 中。

2.动态合并

using UnityEngine;
using System.Collections;
 
public class MyClass : MonoBehaviour
{
    void Start ()
    {
        MeshFilter [] meshFilters = GetComponentsInChildren<MeshFilter> ();
        CombineInstance[] combine = new CombineInstance[meshFilters.Length];
 
        for (int i = 0; i < meshFilters.Length; i++) {
            combine [i].mesh = meshFilters [i].sharedMesh;
            combine [i].transform = meshFilters [i].transform.localToWorldMatrix;
            meshFilters [i].gameObject.active = false; 
        }
 
            transform.GetComponent<MeshFilter> ().mesh = new Mesh ();
            transform.GetComponent<MeshFilter> ().mesh.CombineMeshes (combine);
            transform.gameObject.active = true;
    }
}
  1. 先在 Unity 中建立 空物件 ( Empty )
  2. 再创建2个 Cube 方块,并放入 空物件底下 (可以改成你自己的模型)
  3. 把 MyClass 代码丟进 空物件上 。
  4. (可选) 建立一个 Material 材质,并且丢进 空物件上
  5. 执行

6.Gpu Instance

Gpu Instance是一种用来提高渲染大量物体效率的技术,随着手游游戏品质需求的提升,我需要在场景里绘制越来越多的物体,这里面主要涉及 两个方面的性能 瓶颈,一是cpu对gpu提交数据的次数(包括设置数据buffer,渲染状态以及调用对渲染原语的绘制即drawcall),二是gpu上的绘制(包括顶点处理和像素绘制),随着场景物体的提升,cpu和gpu的压力都会上升。目前在一些典型的3D游戏的制作中,我们的经验值是全屏不超过10万个顶点和200个draw call左右,不然对中端机器会有一定压力。
为了解决场景绘制效率这个问题,主要有以下几种优化方案:
static batching: 即静态合批,静态合批的原理即化整为零,将多个场景物体预先合成一个大的物体进行绘制,unity5的实现就是整合成一个大的vbo,而不整合IBO,一次性提交vbo给gpu,然后并不是把整个vbo都绘制,而是每次需要绘制其中某个某些物体时改变IBO,选择大vbo上的某一段进行绘制。静态合批可以将多个小物体的绘制合并成一个大物体的绘制,减少对渲染状态的改变,它一次并行绘制多个物体,理论上是最快的绘制方法,不过最大的缺点是因为合成新的大vbo需要耗费额外的大量内存,同时不能渲染动态物体,因为合并vbo的时候已经确定顶点数据了,顶点数据不能更改(例如unity5对LOD合批的实现也是讲所有层次的lod都预先合并进去),另外一个vbo的大小是有限制的,如果物体数量过多,也会被拆成多个绘制。
dynamic batching:动态合批,可以解决对顶点数据有变化的物体的合批,它动态的合并vbo进行提交,组建vbo的时间有消耗,为了减少这个消耗,unity对动态合批的vbo大小有限制,以致于很小顶点数的物体才有可能被动态合批。
vertex constant instancing:Instancing 是不同于batching的另一种方案,它的原理是对于模型一致的物体,只提交原始的模型的vbo给gpu,然后将每个物体不同的属性单独抽出来组成buffer发给gpu,在显卡中根据这一份vbo和每个物体不同的属性来绘制多个物体,即一次提交,在gpu上绘制多个,对于大量同样模型的物体绘制是一个很好的方案。vertex constant的instancing是利用顶点常量属性来存储这些per instance attributes,但是也需要一个大的vbo存储所有未经顶点变换的相同的n个原顶点数据,在shader里面读取不同的vertex constant内容绘制不同的instance
gpu instancing:这是最新渲染api提供的一种技术,如果绘制1000个物体,它将一个模型的vbo提交给一次给显卡,至于1000个物体不同的位置,状态,颜色等等将他们整合成一个per instance attribute的buffer给gpu,在显卡上区别绘制,它大大减少提交次数,它在不同平台的实现有差异,例如gles是将per instance attribute也当成一个vbo提交,然后gles3.0支持一种per instance步进读取的vbo特性,来实现不同的instance得到不同的顶点数据,这种技术对于绘制大量的相同模型的物体由于有硬件实现,所以效率最高,最为灵活,避免合批的内存浪费,并且原则上可以做gpu skinning来实现骨骼动画的instancing。

7.FPS优化

减少在ProjectSetting-> Quality中的VSync Count 参数会影响你的FPS,EveryVBlank相当于FPS=60,EverySecondVBlank = 30;这两种情况都不符合游戏的FPS的话,我们需要手动调整FPS,首先关闭垂直同步这个功能,然后在代码的Awake方法里手动设置FPS(Application.targetFrameRate = 45;)
降低FPS的好处:
1)省电,减少手机发热的情况;
2)能都稳定游戏FPS,减少出现卡顿的情况
待机时,FPS设置为1,节省电量
关闭垂直同步
两种同步参数:
水平同步是水平同步信号决定了CRT画出一条横越屏幕线的时间
垂直同步是垂直同步信号决定了CRT从屏幕顶部画到底部,再返回原始位置的时间,垂直同步代表着CRT显示器的刷新率水平。
注意:垂直同步的存在,才能使得游戏进程和显示器刷新率同步,使得画面更加平滑和稳定,取消了垂直同步信号,固然可以换来更快的速度,但是在图像的连续性上势必打折扣。

二、代码优化

1.Foreach

频繁调用容易触及堆上限,导致GC过早触发,出现卡顿现象。
Foreach会产生GC Alloc,说明他在调用GetEnumerator()的时候会有堆内存上的操作:new和dispose。
如非必要的情况下不要使用。用for代替foreach,foreach每次迭代产生24字节垃圾内存。100次循环就是2.4kB。

2.string修改

熟悉C++就会了解每次使用string的时候,都要在内存中创建一个新的字符串对象,就需要为该对象分配新的空间。特别是在循环中需要修改string对象,就会频繁的分配新的空间。字符串的拼接会产生临时字符串内存,移除代码中的字符串拼接,改用string.format,或stringbuilder。

3.gameObjet.tag

gameObjet.tag会在内部循环调用对象分配的标签属性以及拷贝额外的内存。对象标签tag比较采用comparetag,不要用tag=="mytag"这样,推荐使用gameObject.CompareTag("XXX")来代替.tag。

4.ObjectPool对象池

https://blog.csdn.net/wwlcsdn000/article/details/78778970
 避免频繁的Instance,Destroy操作。

5.避免在OnGui中堆变量、方法进行更新、赋值、输出变量建议在Update内.

6. 尽量直接声明脚本变量,而不使用GetComponent来获取脚本。

7. 只在一个脚本中使用OnGUI方法

8. 同一个脚本中频繁使用的变量建议声明为全局变量,脚本之间频繁调用的变量或方法建议声明为全局静态变量或方法。

9. 数组、集合类元素优先选择Array,其次是List。

	数组:在初始化时必须指定其大小和类型,他在内存中是连续存储的,所以可以看出数组的索引速度是非常快的。在确定了数组的长度和类型后,选择数组存储数据是比较好的选择。不适合插入操作。

ArrayList:在初始化的时候不需要指定其大小和类型。他可以存储不同的数据类型,但是在存取得过程中会引起装箱和拆箱,降低了性能。插入操作方便。
  List:在初始化的时候必须指定其类型,但是不需要指定大小,所以他不会像ArraryList那样在存取过程中引起装箱和拆箱操作。在类型相同的情况下,List和数组的性能相当。插入操作方便。
  Dictionary:在初始化的时候也必须指定其类型,而且他还需要指定一个Key,并且这个Key是唯一的。正因为这样,Dictionary的索引速度非常快。但是也因为他增加了一个Key,Dictionary占用的内存空间比其他类型要大。他是通过Key来查找元素的,元素的顺序是不定的。

10.尽量少用模运算和除法运算,比如a/5f,一定要写成a*0.2f。

11.对于不经常调用或更改的变量或方法建议使用Coroutines & Yield;

12. 尽量使用struct而非class,因为struct是栈区,class是堆区。

13. Iphone:尽量使用整数数字,因为iPhone的浮点数计算能力很差

14.务必删除脚本中为空或不需要的默认方法

15.少使用的函数:pow,sin,cos等

三、资源优化

Shader 尽量减少复杂数学运算 减少discard操作

1.模型优化

动态模型::面片数<3000 材质数<3 骨骼数<50
静态模型:顶点<500
骨骼:数量<30
限制模型面数和定点数
https://jingyan.baidu.com/article/c74d60007b4d510f6a595db2.html

2.音频优化

1.播放较长的音乐,使用.ogg或者.mp3格式
2.播放较长的音乐,使用.wav或者.aif格式
3.音乐格式
	MP3属于有损失的格式,牺牲音乐文件的质量以换取较小的文件体积,WAV是无损的格式,标准格式化的WAV文件和CD格式一样,是44.1K的取样频率,16位量化数字,因此在声音文件质量和CD相当。
	https://blog.csdn.net/u012565990/article/details/51794486

3.贴图优化

标准:Texture 贴图长宽<1024	

1.压缩格式

 	不透明的贴图采用ECT 4Bit的格式,透明的采用RGBA 16Bit。
 	尽可能是使用ETC1和PVRTV4等GPU直接支持的图片格式,不仅内存占用低、性能也更好;当出现质量不及格时,再逐步的提升压缩格式,来满足需要。
 	Unity 对于平台不支持的压缩格式,会默认转为 RGBA 32bpp。而 Android 平台普遍支持的含透明度格式为 RGBA 16bpp。如果采用 RGB ETC 4bpp 的两幅图,那么需要 8bpp(使用该格式可能会导致遮罩出现问题)。如果能够把两幅图放在同一张纹理里面,那么能够再节省一半,大概4bpp(shader处理的时候会比较消耗GPU)。

Unity 在为 Android 打包时,默认对JPG采用 ETC1,对PNG采用 RGBA 16。
NPOT 的图最终会被转为 POT 的图,而且 Unity 会把 NPOT 的图会被转为 RGBA 32 格式 (GUI Texture 支持 NPOT,图片格式不会改,但是最终送 GPU 的时候还是会转为 POT)。Unity优化方面的一些小总结

2.九宫格

 	可以采用九宫格切图的方式将大型的图片压缩成小图进行拉伸。	

3.明智的使用 Mip Maps

 	呈现小物件的时候,像岩石树木这样的远处物体,一个高精度的贴图对于玩家来说是没有意义的,因为看不到那么多的细节。但是如果使用这张高精度的贴图会损失原本不应该的性能,这时候需要一个较少细节的纹理来提升程序性能。
 	Mip Maps的发明就是来解决这个问题 的,通过启用 Generate Mip Maps   它会自动产生不同分辨率的多张相同纹理。在运行的时候,GPU根据在透视投影下出现的面积选择适当的Mip Map(这是一种叫做 texel-to-pixel ratio的技术 )。启用Mip Maps还会让最后生成的纹理文件增大33%左右,它唯一有用的地方是摄像机需要渲染不同距离的纹理时。
 	如果我们的纹理总是呈现在摄像头的同样距离,这时候开启Mip Map就一点用都没只是在浪费空间。还有如果只有单一的一种远距离物体我们也应该禁用它,应该从原纹理缩放一个小纹理给这个远处物体。
 	以下时候应该禁用这个选项:
		在2d游戏中的几乎所有的纹理(2d游戏正交投影不存在近大远小)
		UI界面
		Mesh贴图,Sprites,Particle Effects,因为他们总是在摄像机差不多的距离渲染不会有很明显的距离差	

4.将图片打包成图集

  	 Unity现在版本会自动打包成图集。也可以手动将图片打包图集。
  	 图集的优化	

5.贴图合并

https://mp.weixin.qq.com/s?__biz=MzAxMDcxOTkxNQ==&mid=402245125&idx=1&sn=6f6e768fa88e3c16f110f21813dcae02&scene=1&srcid=0425OWRBedO3NCVjYX72ntOj&from=singlemessage&isappinstalled=0#wechat_redirect

4.如何减少冗余资源和重复资源

A、Resources目录下的资源不管是否被引用,都会打包进安装包 不使用的资源不要放在Resources目录下
B、不同目录下的相同资源文件,如果都被引用,那么都会打包进资源包,造成冗余 保证同一个资源文件在项目中只存放在一个目录位置

5.资源的检测和分析

https://www.uwa4d.com/#assetbundle

6.光源优化

1.光源“Important”数量

   建议1个,一般为反向光,“Important”个数应该越小越少。个数越多,drawcall越多。

2. Pixel Light数量

  	  建议1-2个。

3.性能占用顺序

  	  聚光灯>点光源>平行光。
  	  点光源和聚光灯只影响它们范围内的网格。
  	  如果一个网格处于点光源或者聚光灯的照射范围之外,并且光源的attenuate开关是打开的,那么这个网格将不会被光源所影响,这样就可以节省性能开销。

这样做理论上来讲可以使用很多小的点光源而且依然能有一个好的性能,因为这些光源只影响一小部分物体。
一个网格在有8个以上光源影响的时候,只响应前8个最亮的光源。
场景中如果没有使用灯光和像素灯,就不要使用法线贴图,因为法线效果只有在有光源(Direct Light/Point Light/Angle Light/Pixel Light)的情况下才有效果。
8.粒子特效
标准:屏幕上的最大粒子数建议小于200,每个粒子发射器的最大粒子数建议不超过50个。如果可以粒子的size尽可能的小。因为Unity的粒子系统的shader无论是alpha test还是alpha blending都是一笔不小的开销。同时,对于非常小的粒子,建议粒子纹理去掉alpha通道。尽量不要开启粒子的碰撞功能,非常耗时。
alpha test是采用一种很霸道极端的机制,只要一个像素的alpha不满足条件,那么它就会被fragment shader舍弃,“我才不要你类!”。被舍弃的fragments不会对后面的各种Tests产生影响;否则,就会按正常方式写入到缓存中,并进行正常的深度检验等等,也就是说,Alpha Test是不需要关闭ZWrite的。Alpha Test产生的效果也很极端,要么完全透明,即看不到,要么完全不透明。
alpha blending是则是一种中庸的方式,它使用当前fragment的alpha作为混合因子,来混合之前写入到缓存中颜色值。但Alpha Blending麻烦的一点就是它需要关闭ZWrite,并且要十分小心物体的渲染顺序。如果不关闭ZWrite,那么在进行深度检测的时候,它背后的物体本来是可以透过它被我们看到的,但由于深度检测时大于它的深度就被剔除了,从而我们就看不到它后面的物体了。因此,我们需要保证物体的渲染顺序是从后往前,并且关闭该半透明对象的ZWrite

7.合并材质球

TexturePacking
1、遍历gameobject,取出material,并根据shader来将material分类
2、调用Unity自带的PackTextures函数来合并每个shader分类中的material所对应的textures(PackTextures函数有缺陷,不过可以将就用)
3、根据合并的大的texture来更新原有模型的texture、material已经uv坐标值。
PS:需要合并的纹理应该是物体在场景中距离相近的,如果物体在场景中的距离较远,
则不建议合并纹理,因为这样做很有可能非但起不到优化的作用,反而降低了运行效率。

8.Shader优化

备注:最近一直在研究Unity3D的性能优化问题,这段时间可能会多翻译这方面的文章。
尽量减少复杂数学运算 减少discard操作
前两天,MadFinger,就是当今iOS与Android上画质最牛逼闪闪的游戏之一——ShadowGun的开发商,令人惊异地放出了一个ShadowGun的样例关卡以及若干可免费使用的Shader,国外同行们的分享精神真的是令人赞叹不已。原文在这里,以下是我的一些摘录和笔记。

首先是一些优化常识。针对图形方面的优化主要包括三角形数量,纹理所占内存,以及Shader,前两项基本没什么好讲的,针对设备机能的限制制定相应的指标即可,所以Shader就成为了图形性能优化的关键。

Alpha blending

在Unity官方文档中讲,由于硬件原因,在iOS设备上使用alpha-test会造成很大的性能开销,应尽量使用alpha-blend代替。这里提到,在同屏使用alpha-blend的面数,尤其是这些面所占屏幕面积的大小,对性能也会造成很大影响。原因是使用alpha-blend的面会造成overdraw的增加,这尤其对低性能设备的影响很大。不过没有购买Pro版,没有Occlusion Culling功能的话,就不必顾虑这一问题了,反正overdraw是必然的。

复杂的Per-pixel shader

Per-pixel shader即Fragment shader,顾名思义是要对每个渲染到屏幕上的像素做处理的shader,如果per-pixel shader比较复杂且需要处理的像素很多时,也就是使用该shader的面占屏幕面积很大时,对性能的影响甚至要超过alpha blending。因此复杂的per-pixel shader只适用于小物体。

下面是对几个Shader的逐一讲解:

Environment specular maps(Shader Virtual Gloss Per Vertex Additive)
Specular map通常都是利用贴图的alpha通道来定义物体表面的光滑程度(反光度),这个shader的特点是per-vertex计算反光度的,有着相当不错的效果的同时比per-pixel的shader性能要高得多。这个shader很适用于关卡环境等占很大区域的模型。

经过优化的动态角色光照和阴影(Light probes和BRDF Shader)
传统的Lightmaps无法支持动态物体,对此Unity提供了Light probes技术,预先把动态物体的光照信息保存在代理对象(即Light probes)中,运行时动态物体从距离最近的Probe中获取光照信息。

Unity本身还提供了一个效果非常棒的专为移动设备优化过的角色Shader,支持Diffuse、Specular和Normal maps,并通过一个特殊的脚本生成贴图用于模仿BRDF光照效果。最终产生的效果堪比次时代大作中的角色光影效果。

雾和体积光(Shader Blinking Godrays)
目前在移动设备上要开启真正的雾效基本不可行,ShadowGun的方案是通过简单的网格+透明贴图(称为雾面)来模拟雾效。在玩家靠近时,雾面逐渐变淡,同时fog plane的顶点也会移开(即使完全透明的alpha面也会消耗很多渲染时间)。

使用这个Shader的网格需要经过处理:

顶点的alpha值用于决定顶点是否可以移动(在例子中0为不可动,1为可动)。
顶点法线决定移动的方向
然后Shader通过计算与观察者的距离来控制雾面的淡入/淡出。
这个Shader还可以用来做体积光和其它一些alpha效果。

飞机坠毁的浓烟效果(Shader Scroll 2 Layers Sine Alpha-blended)
通过粒子产生浓烟的代价太高,所以ShadowGun中使用了网格+贴图动画来制作这个效果。通过混合两层贴图并让它们交错移动来产生动画效果。其中顶点alpha值用于让网格的边缘看起来比较柔和,同时使用顶点颜色来模拟从火焰到烟雾的过渡效果。

带动态效果的天空盒(Shader Scroll 2 Layers Multiplicative)
通过两张贴图的混合和移动产生云的动态效果。

旗帜和衣服的飘动效果(Shader Lightmap + Wind)
同样利用顶点alpha值决定哪些顶点可以移动,然后shader的参数用于调整摆动的方向和速度。

9.减少DrawCall

Draw Call Batching (绘制调用批处理)

To draw an object on the screen, the engine has to issue a draw call to the graphics API (OpenGL ES in the case of iOS). Every single draw call requires a significant amount of work on the part of the graphics API, causing significant performance overhead on the CPU side.
在屏幕上渲染物体,引擎需要发出一个绘制调用来访问图形API(iOS系统中为OpenGL ES)。
每个绘制调用需要进行大量的工作来访问图形API,从而导致了CPU方面显著的性能开销。

Unity combines a number of objects at runtime and draws them together with a single draw call. This operation is called “batching”. The more objects Unity can batch together, the better rendering performance you will get.
Unity在运行时可以将一些物体进行合并,从而用一个绘制调用来渲染他们。这一操作,我们称之为“批处理”。
一般来说,Unity批处理的物体越多,你就会得到越好的渲染性能。

Built-in batching support in Unity has significant benefit over simply combining geometry in the modeling tool (or using theCombineChildren script from the Standard Assets package). Batching in Unity happensafter visibility determination step. The engine does culling on each object individually, and the amount of rendered geometry is going to be the same as without batching. Combining geometry in the modeling tool, on the other hand, prevents effecient culling and results in much higher amount of geometry being rendered.
Unity中内建的批处理机制所达到的效果要明显强于使用几何建模工具(或使用Standard Assets包中的CombineChildren脚本)的批处理效果。
这是因为,Unity引擎的批处理操作是在物体的可视裁剪操作之后进行的。
Unity先对每个物体进行裁剪,然后再进行批处理,这样可以使渲染的几何总量在批处理前后保持不变。
但是,使用几何建模工具来拼合物体,会妨碍引擎对其进行有效的裁剪操作,从而导致引擎需要渲染更多的几何面片。

Materials
材质
Only objects sharing the same material can be batched together. Therefore, if you want to achieve good batching, you need to share as many materials among different objects as possible.
只有拥有相同材质的物体才可以进行批处理。
因此,如果你想要得到良好的批处理效果,你需要在程序中尽可能地复用材质和物体。

If you have two identical materials which differ only in textures, you can combine those textures into a single big texture - a process often calledtexture atlasing. Once textures are in the same atlas, you can use single material instead.
如果你的两个材质仅仅是纹理不同,那么你可以通过 纹理拼合 操作来将这两张纹理拼合成一张大的纹理。
一旦纹理拼合在一起,你就可以使用这个单一材质来替代之前的两个材质了。

If you need to access shared material properties from the scripts, then it is important to note that modifyingRenderer.material will create a copy of the material. Instead, you should useRenderer.sharedMaterial to keep material shared.
如果你需要通过脚本来访问复用材质属性,那么值得注意的是改变Renderer.material将会造成一份材质的拷贝。
因此,你应该使用Renderer.sharedMaterial来保证材质的共享状态。

Dynamic Batching
动态批处理
Unity can automatically batch moving objects into the same draw call if they share the same material.
如果动态物体共用着相同的材质,那么Unity会自动对这些物体进行批处理。

Dynamic batching is done automatically and does not require any additional effort on your side.
动态批处理操作是自动完成的,并不需要你进行额外的操作。

Tips:
提醒:
1、 Batching dynamic objects has certain overheadper vertex, so batching is applied only to meshes containing less than900 vertex attributes in total.
批处理动态物体需要在每个顶点上进行一定的开销,所以动态批处理仅支持小于900顶点的网格物体。

2、 If your shader is using Vertex Position, Normal and single UV, then you can batch up to 300 verts and if your shader is using Vertex Position, Normal, UV0, UV1 and
Tangent, then only 180 verts.
Please note: attribute count limit might be changed in future
如果你的着色器使用顶点位置,法线和UV值三种属性,那么你只能批处理300顶点以下的物体;
如果你的着色器需要使用顶点位置,法线,UV0,UV1和切向量,那你只
能批处理180顶点以下的物体。
请注意:属性数量的限制可能会在将来进行改变。

4、 Don’t use scale. Objects with scale (1,1,1) and (2,2,2) won’t batch.
不要使用缩放尺度(scale)。分别拥有缩放尺度(1,1,1)和(2,2,2)的两个物体将不会进行批处理。

5、 Uniformly scaled objects won’t be batched with non-uniformly scaled ones.
统一缩放尺度的物体不会与非统一缩放尺度的物体进行批处理。
Objects with scale (1,1,1) and (1,2,1) won’t be batched. On the other hand (1,2,1) and (1,3,1) will be.
使用缩放尺度(1,1,1)和 (1,2,1)的两个物体将不会进行批处理,但是使用缩放尺度(1,2,1)和(1,3,1)的两个物体将可以进行批处理。

6、 Using different material instances will cause batching to fail.
使用不同材质的实例化物体(instance)将会导致批处理失败。

7、 Objects with lightmaps have additional (hidden) material parameter: offset/scale in lightmap, so lightmapped objects won’t be batched (unless they point to same
portions of lightmap)
拥有lightmap的物体含有额外(隐藏)的材质属性,比如:lightmap的偏移和缩放系数等。所以,拥有lightmap的物体将不会进行批处理(除非他们指向lightmap的同一
部分)。

8、 Multi-pass shaders will break batching. E.g. Almost all unity shaders supports several lights in forward rendering, effectively doing additional pass for them
多通道的shader会妨碍批处理操作。比如,几乎unity中所有的着色器在前向渲染中都支持多个光源,并为它们有效地开辟多个通道。

9、 Using instances of a prefab automatically are using the same mesh and material.
预设体的实例会自动地使用相同的网格模型和材质。

Static Batching
静态批处理

Static batching, on the other hand, allows the engine to reduce draw calls for geometry of any size (provided it does not move and shares the same material). Static batching is significantly more efficient than dynamic batching. You should choose static batching as it will require less CPU power.
相对而言,静态批处理操作允许引擎对任意大小的几何物体进行批处理操作来降低绘制调用(只要这些物体不移动,并且拥有相同的材质)。因此,静态批处理比动态批处理更加有效,你应该尽量低使用它,因为它需要更少的CPU开销。

In order to take advantage of static batching, you need explicitly specify that certain objects are static and willnot move, rotate or scale in the game. To do so, you can mark objects as static using the Static checkbox in the Inspector:
为了更好地使用静态批处理,你需要明确指出哪些物体是静止的,并且在游戏中永远不会移动、旋转和缩放。想完成这一步,你只需要在检测器(Inspector)中将Static复选框打勾即可,如下图所示:

Using static batching will require additional memory for storing the combined geometry. If several objects shared the same geometry before static batching, then a copy of geometry will be created for each object, either in the Editor or at runtime. This might not always be a good idea - sometimes you will have to sacrifice rendering performance by avoiding static batching for some objects to keep a smaller memory footprint. For example, marking trees as static in a dense forest level can have serious memory impact.
使用静态批处理操作需要额外的内存开销来储存合并后的几何数据。在静态批处理之前,如果一些物体共用了同样的几何数据,那么引擎会在编辑以及运行状态对每个物体创建一个几何数据的备份。这并不总是一个好的想法,因为有时候,你将不得不牺牲一点渲染性能来防止一些物体的静态批处理,从而保持较少的内存开销。比如,将浓密森里中树设为Static,会导致严重的内存开销。

Static batching is only available in Unity iOS Advanced.
静态批处理目前只支持Unity iOS Advanced。

其他优化

优化工具

UWA Game Optimization Toolkit

文章

使用Unity开发安卓游戏 应该如何进行性能优化
http://gad.qq.com/article/detail/17252

编译性能优化

http://gad.qq.com/article/detail/27927
http://forum.china.unity3d.com/thread-13028-1-1.html