一、Batching技术:
在拥有网格并携带一种不同的材质时候才会形成一个独立的drawcall, 在通知GPU和切换材质shader纹理时候也是比较耗时的(特别是第一次CPU->GPU传递纹理数据)。
Batching 的主要目标是 合并物体的材质,只要他们使用相同的材质(纹理和shader),GPU就可以按完全相同的方式进行处理(批处理合并drawcall)。Batching处理技术的算法是:
检查所有要绘制物体的材质,把材质相同的游戏对象分成一组,这样就可以在一个drawcall中处理多个物体。
Unity在场景中先对物体进行可视化裁剪,然后进行批处理,这样可以使得渲染过程中几何总量在批处理前后保持不变。使用几何建模工具会妨碍引擎对其进行有效的裁剪,从而导致unity内部需要更多的几何面片。
静态批处理只要对游戏对象选择static即可,需要额外的内存来消耗存储合并后的几何数据。使用游戏对象创建了共享网格,那么会消耗过多的内存,通过去掉static可以减少内存使用。
动态游戏对象拥有相同的材质Unity会自动进行批处理,不需要任何设置。但是动态批处理是有限和有条件的。拥有位置,法线和uv的网格物体只能处理总共300个顶点的物体合并批处理,超过不支持。使用不同材质的实例化游戏对象不能进行批处理,拥有lightmap的游戏对象不能批处理,多个pass的shader材质会妨碍批处理,接受阴影的物体不会进行批处理。
二、UnityProfile 分析器使用:
可以查看CPU, 内存,GPU, 渲染,物理及音频占用情况(可以在左上角添加,可以在对应的页签左边点击X去掉),找到游戏的性能瓶颈。
1)window->Profile窗口 点击Record记录,点击Play按钮。
2)unity会记录运行的性能情况,点击时间轴上任何地方会在窗口底部会显示所选帧的详细信息。
3)上部会显示分析器控件,点击时间轴会暂停显示帧详细数据,Frame的上下是上一帧下一帧,current是当前最后一帧。点击Deep Profile是深度分析会分析所有脚本的函数调用容易卡死,Profile Editor是分析编辑器,Clear是清理。
每个视图都要注意下,分析出来的每个字段的含义,不懂就google下。
如:
CPU分析中:
Total是函数及其子函数所花费的时间,self是本函数消耗的时间。单击层次项目项,右边会显示出详细信息。GPU中也是一样。可以根据这些信息来优化游戏对象设置,启用的特性,优化脚本。
Memory分析中:GfxDriver是显卡驱动程序在纹理,渲染对象,着色器等渲染所需要的内存情况。
Detail模式下,Referenced from native code 对象是Unity自身代码的引用。
Scene Object 对象来自场景游戏对象。
Builtin Resources 对象来自于Unity内建资源。
分析器接口在代码中使用:
针对unity deep profile分析的局限性,可以使用
Profiler.BeginSample(name:string); // name是采样标签
Profiler.EndSample();
手动开启和关闭功能,会对BeginSample和EndSample之间的代码段进行分析。示例:
using UnityEngine;
using System.Collections;
/*samcen*/
public class ProfilerExample : MonoBehaviour {
private int sum = 0;
void Start()
{
Profiler.BeginSample ("MyProfiler");
for (int i = 0; i < 10; i++) {
sum += i;
print (sum);
}
Profiler.EndSample ();
}
}
将该脚本挂载到游戏对象中,就可以在Profile 开始帧的详细面板中看到分析结果(因为在Start中)。
不同设备连接到分析器:
IOS设备连接到分析器:
选中Build setting->development build->auto connect profile,然后在Profile分析视图中选择Active profile中选择设备,就可以分析了。
确保ios设备连接到了wifi, 确保mac 防火墙关闭了,或者保证54998~55511端口处于打开状态。
在unity中依次打开file->build & run。
就可以在unity分析器中分析游戏在ios中的运行情况了。
Android设备连接到分析器:
和ios类似,就是多了确保android设备关闭了手机数据,开启wifi, 和ios一样设置项目开启了auto connect profile, 在unity打开了profile窗口后,选择active profile选项打开分析器。
选择unity file->build & run, 在android设备上打开应用程序。android设备与主机计算器必须使用同一个子网。
三、Unity Frame debugger
通过帧分析,来分析每一帧的GPU, Draw call和渲染的纹理图像信息,以及深度缓存,模板缓存,多目标FBO的信息。
你也可以使用外部的工具调试渲染。打一个独立播放包,用
Visual Studio图形调试器
、
Intel GPA
、
RenderDoc
、
NVIDIA NSight
或
AMD GPU PerfStudio
运行,然后抓取渲染的一帧,并且逐步调试draw calls和其它渲染事件看看发生了什么。
四、优化建议
1.通用的优化建议:
1).FixedUpdate是用在物理引擎中,以固定间隔执行的。Update是每帧调用,间隔是不固定的。
尽量不要在其中写太多不需要重复调用的代码。
存在空的FixedUpdate, Update也要移除,避免每帧的函数调用开销。
2).Update, FixedUpdate中不要使用Find, FindObjectOfType, FindGameObjectsWithTag, GetCompoent()等耗时的函数。
3).Update, FixedUpdate中不要申请字符串,数组 等对堆内存资源的频繁申请和释放。
也不要在该热点函数中使用太多临时变量,如太多栈变量也是耗时的,特别注意堆变量。
4).上述1,2,3的操作可以放置到Awake, Start函数中。
代码不需要每帧执行,则用Coroutines来解决,如:
void Start()
{
InvokeRepeating("DoSomeThing", 1.5f, 1.0f);
}
5).在游戏切换关卡,或暂停时候,手动进行垃圾内存的回收。
Resource.UnloadUnuseAssets();
GC.Collect();的调用。
2.在移动设备中:
物理性能的优化:
1)对物理引擎的优化,在edit->project setting->time中,增加Fixed Timestep的数值,减少物理引擎帧计算间隔,降低CPU负荷。设置Maximum Allowed Timestep的数值为0.1,即每秒更新10次。
2)不使用网格碰撞体,wheel colliders车轮碰撞体,而是使用box,sphere形状的碰撞体,减少计算开销。
3)避免使用unity自带的Sphere等mesh组件,因为有太多的面片,需用从其它建模软件中导入3D模型替代。
4)需要控制场景中非休眠的刚体和碰撞体的数量,可以使用profile工具来确定活动的数量。
脚本的优化:
1)在Update函数中,减少GetCompoent调用,减少字符串,数组对堆内存资源的申请和释放。
2)尽量减少GUILayout的使用,因为需要额外的内存开销。通过将useGULayout为false, 用GUI手动布局可以替代掉。
3)不使用异常处理,如ios中,unity设置 project setting->player中异常选项中使用:
Fast and exceptions unsupported(不使用异常),而不是使用slow and safe(mono内部使用,支持异常)。
4)优化变量,尽量用Int而不是float; 尽量用简单的表达式,例如位运算;尽量不用复杂的数学函数。