一、遮挡剔除技术
在实际的开发过程中,每个场景往往都伴随着大量的对象,其中相当一部分对象是不在摄像机拍摄范围内的,进行这部分对象的绘制是不需要的。
因此有了遮罩剔除技术,使不被拍摄到的点或面部送入渲染关系进行绘制。

二、批处理技术
如果多个对象使用同一个材质,Unity3D会一次性地将同一材质的对象的绘制信息绘制给GPU,即进行批处理。这极大地减少了CPU与CPU交互所耗费的资源。
同一个材质下,但是由于缩放比例不一致,同样不能进行批处理操作。
拥有Lightmap的对象由于多出了一个光照烘焙的材质,也不能进行批处理
接受阴影的对象也是不会被进行批处理操作的。含有多个Pass着色器的对象相似,不能被批处理
以上都是动态批处理。在进行IOS平台的开发时,Unity还提供了静态批处理,静态批处理比动态批处理更节约资源。为了实现静态批处理,在实际开发过程中需要对场景中禁止的对象选中Static复选框。
批处理是一项用空间换时间的操作,其过程会耗费大量的内存,在内存宝贵的情况下要谨慎使用批处理。
三、移动的平台优化技巧
与PC平台相比,移动设备的硬件性能普遍比较差,这就迫使移动平台的开发人员开发出资源消耗更低的程序。
1、在实际建模的过程中,要注意控制模型顶点的数量,不要在场景中使用含有大量顶点的模型。
2、在代码开发过程中,要避免在Update这一类不断调用的方法中使用GetComponent、Find、FindWithTag等API,这些API会在场景中或者资源中搜索对象,该操作会耗费大量的资源,尽可能在Start或Awake方法中声明并初始化需要的对象。
3、在进行数据方面的计算时,不要使用复杂的数字函数,同时可以使用资源消耗更少的整数型类型计算,而非浮点数的计算。在一些精度要求比较小的地方,可以整数类型代替浮点型,这对节约硬件资源有很大的作用
4、避免使用GUILayout
5、可以选择Edit---->Project Settings---->Quality 打开画面质量调整窗口,通过调整各个值设置垂直同步等参数,从而进行资源的合理分配,防止太多的资源被绘制所占用
6、尽可能用几个规则形状的碰撞器组合代替整个网格碰撞器
7、协同程序Corouttines是Unity3D利用C#中迭代器机制包装的一个特殊脚本攻击,它模仿了线程进行工作。当需要写一些只工作一段时间的代码,可以使用协同程序完成,协同程序在其任务完成后便不再占用任何资源。
8、静态物体减少使用实时光照,因为这会大大增加光照部分的计算时间。可以使用静态光照或者将静态物体进行烘焙,直接使用烘焙后的光照网格数据
9、使用拾取时,最直观的方式是用UI结合OnMouseDown方法进行判断,但是应用于移动平台身上这个方式是不可取的,取而代之的是利用射线进行判断。从摄像机出发,到手指在屏幕上的位置为反向发射射线,射线先触碰到的GameObject则是要被拾取的对象。
10、当在移动端使用Shader时,也要注意一些情况
尽量改变UV数值类型,由float改成half
改变灯光颜色计算中的数值类型,由float4类型改为fixed4类型
关闭渲染附加通道或者直接指定渲染
共享UV
11、检测脚本代码时一定要检查物理交互相关的代码,此列代码在移动端最好不要轻易使用,但是也有例外
动态刚体数量越少越好
尽量将Collision Detection Mode 设置为 Discrete
调整Fixed Timestep 值的带下
12、当使用音频或者视频时,要对文件进行如下处理
尽可能使用短片段的音频或者视频,这个样可以降低对CPU的消耗。如果必须用到长音频或者视频时,要对文件进行压缩,降低可执行文件的代销
13、尽可能降低Drawcall数量,Drawcall数量可以反映当前程序的执行效率。有效的手段为减少模型的Mesh、减少使用透明的材质数量,尽可能使用更多的静态光照、优化着色器代码,提高执行效率
四、代码优化
1、缓存组件查询
当通过GetComponent获取一个组件,Unity必须从游戏物体里查找目标组件。如果是在Update方法中进行查找,就会影响运行速度。可以设置一个私有变量去存储该组件。
private Transform m_transfrom;
void Start()
{
m_transfrom = this.transform;
}
// Update is called once per frame
void Update()
{
m_transfrom.Translate(new Vector3(1, 0, 0)*Time.deltaTime);
}
2、 使用内建数组
虽然ArrayList和Array使用起来容易、方便,但是与内建数组相比,两者的速度还是有很大的差异。内建数组直接嵌入struct数据类型并存入第一缓冲区里,该数组不需要其他类型信息或者其他资源,因此用作缓存遍历更加快捷
private Vector3[] positions;//声明静态向量
private void Start()
{
positions = new Vector3[100];//创建向量数组
for (int i = 0; i < positions.Length; i++)
{
positions[i] = Vector3.zero;//为每个向量赋值
}
}
3、尽量少调用函数
最简单且最有效的优化就是做最少的工作。Unity中的Update函数的每一帧都在运行,所以减少Update函数中的工作量可以大幅度提高运行效率。可以通过协程(Coroutine)或者加入标志位来减少Update函数的工作量。
示例:使用标志位控制Update执行
public class OptimizedUpdate : MonoBehaviour
{
private bool isProcessing = false;
void Update()
{
// 只有标志位为true时才执行耗时操作
if (isProcessing)
{
PerformHeavyCalculation();
}
}
void PerformHeavyCalculation()
{
// 模拟耗时计算
for (int i = 0; i < 1000; i++)
{
// 复杂计算逻辑
}
}
// 外部控制何时开始处理
public void StartProcessing()
{
isProcessing = true;
}
public void StopProcessing()
{
isProcessing = false;
}
}
示例:使用协程替代频繁的Update检查
public class CoroutineExample : MonoBehaviour
{
void Start()
{
// 启动协程,每2秒执行一次,而不是每帧都检查
StartCoroutine(PeriodicCheck());
}
IEnumerator PeriodicCheck()
{
while (true)
{
CheckCondition();
yield return new WaitForSeconds(2f); // 每2秒检查一次
}
}
void CheckCondition()
{
// 需要定期检查的逻辑
if (ShouldDoSomething())
{
DoSomething();
}
}
bool ShouldDoSomething()
{
// 判断条件
return true;
}
void DoSomething()
{
// 执行操作
}
}
其他优化技巧:
- 使用Time.deltaTime进行频率控制:如果某些操作不需要每帧执行,可以使用时间间隔来控制执行频率。
- 将多个Update合并:如果多个脚本都有Update逻辑,考虑将它们合并到一个管理类中。
- 使用事件驱动:用事件通知代替每帧的状态检查。
809

被折叠的 条评论
为什么被折叠?



