推荐阅读:
Unity 优化(一) ------ 优化前了解以及方向
FPS:画面每秒传输帧数,,要避免动作不流畅的最低是30;值越大性能越好
CPU:计算每帧需要消耗的时间,值越低说明计算越快,值越小性能越好
Batches:将某些DrawCalls合并,数量为合并后DrawCall的数量。
Tris:三角面
Verts:顶点
SetPass call:Shader中Cpu每次运行Pass之前都会产生一个SetPass call。
Unity 优化(二) ------ 资源优化
长时间音乐使用Mp3格式(使用压缩格式),例如:背景音乐等
短时间音乐使用wav格式(不使用压缩格式),例如:音效
减少冗余资源和重复资源
A、Resources目录下的资源不管是否被引用,都会打包进安装包
不使用的资源不要放在Resources目录下
B、不同目录下的相同资源文件,如果都被引用,那么都会打包进资源包,造成冗余
保证同一个资源文件在项目中只存放在一个目录位置
资源优化:使用UWA工具
渲染优化(GPU)和代码优化(CPU)
GPU:包括场景渲染和灯光处理等
CPU:数值计算
LOD——层级
当模型离视野近时,显示比较精细的模型,离视野比较远时显示比较粗糙的模型。
实现方法:
新建一个空物体,添加LOD Group组件,将模型拖进精细度按下图提示拖进对应位置,可根据实际情况调节每个LOD的占比。
遮挡剔除
目的;降低DrawCall
原理:在摄像机视野内的物体显示,在视野外的物体不显示。
实现方法:
(1)在场景中创建很多物体(方便观察)。全选中—点击Static—Occluder Static
(2)点击Windows—Occlusion Culling
(3)选择指定相机用于遮挡剔除计算
光照贴图
目的:降低Batches
实现方法:
(1)搭建好场景,选中场景中所有需要被光照的物体—点击Static—LightmapStatic
(2)点击Windowa—Lighting—Settings
(3)选择需要被烘焙的光源,将模式选择烘焙模式
(4)Scene—取消勾选—Generate Lighting
(5)选择烘焙后,下方是烘焙进度
(6)选择所有被烘焙的光源,取消Light勾选
这时还能看见光照效果,这时因为使用烘焙,生成了光照贴图
注意:如果觉得光照强度过强,在(4)前可修改
Light组件中Indensity值,值越低,光照越暗
合并Mesh
要求合并的mesh使用相同的材质。
实现方法:
(1)创建一个空物体MeshCombine,并为其创建几个子物体,子物体层级任意
(2)新建脚本并挂在到(1)中的空物体MeshCombine上
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MeshCombine : MonoBehaviour {
// Use this for initialization
void Start () {
CombineMesh();
}
void CombineMesh()
{
MeshFilter[] filters = GetComponentsInChildren<MeshFilter>();//获取空物体下所有子物体的MeshFilter组件并保存为一个数组
CombineInstance[] combiners = new CombineInstance[filters.Length];//unity提供的一个类,用于处理合并的实例
//将filters的一些属性设置给combiners
for (int i = 0; i < combiners.Length; i++)
{
combiners[i].mesh = filters[i].sharedMesh;
combiners[i].transform = filters[i].transform.localToWorldMatrix;//这里的transform不是一个组件而是一个矩阵转换,用于世界座标与局部座标之间的转换
}
Mesh finalMesh = new Mesh();
finalMesh.CombineMeshes(combiners);//合并mesh
GetComponent<MeshFilter>().sharedMesh = finalMesh;//将合并后的Mesh赋值到父物体上
}
}
(3)为(1)中的空物体MeshCombine 添加两个组件:
MeshRender组件:负责渲染
MeshFilter组件:用于存放合并后的mesh
并未MeshRender组件选择一个需要的材质。
(4)游戏运行,会将MeshCombine下的所有子物体中的Mesh合并并赋值到MeshCombine物体上,因此场景中将会出现两个一模一样的mesh,这时在游戏运行时可直接删除其下的子物体,这时可明显看见Batches减少。
ObjectPool
对象池的使用可以说是非常常见。直接上代码:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ObjectPool : MonoBehaviour {
public int objCount=5;//对象池中该类对象初始生成的个数
public GameObject buttlePreb;//需要实例化的预制
private List<GameObject> poolList = new List<GameObject>();//存放对象
void Start () {
InitPool();
}
//初始化对象池
void InitPool()
{
for (int i = 0; i < objCount; i++)
{
GameObject go = Instantiate(buttlePreb);//实例化对象
poolList.Add(go);//将实例化的对象添加到对象次
go.SetActive(false);//设置为隐藏—即未被使用
}
}
//从对象池中取对象
public GameObject ShowObj()
{
foreach (GameObject go in poolList)
{
if (!go.activeInHierarchy)
{
go.SetActive(true);
return go;
}
}
return null;
}
//使用协程,使得对象生成后等待指定时间隐藏—即放回对象池
public IEnumerator HideObj(GameObject go)
{
yield return new WaitForSeconds(3);
go.SetActive(false);
}
}
使用对象池:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class startBuntle : MonoBehaviour {
private ObjectPool objPool;
void Start () {
objPool = GetComponent<ObjectPool>();
}
void Update () {
if (Input.GetKeyUp(KeyCode.K))
{
GameObject go = objPool.ShowObj();
if (go != null)
{
//对象次还有可用对象
go.GetComponent<Rigidbody>().velocity = transform.forward * 30;
StartCoroutine(objPool.HideObj(go));
}
}
}
}