一、优化前提
1,unity安装包大,运行卡
内置了mono虚拟机
C#在mono虚拟机上运行,mono虚拟机是跨平台的
2,DrallCall 绘制调用,性能GPU,CPU,和GPU渲染相关
CPU对图形绘制接口的调用,CPU通过图形库接口,命令GPU进行渲染
DrallCall越大,性能消耗越大,造成游戏运行卡
CPU处理器,相当于我们的大脑,进行逻辑处理计算
GPU专门进行游戏的绘制,场景角色模型,每次绘制前会做很多准备工作
降低CPU对DrallCall的调用,drallcall多,CPU很对额外开销来准备
3,Profiler查看性能,在Window窗体中
4,统计面板,game模式下的stats
FPS每秒的帧数,帧数越大越流畅,超过30帧人眼感觉不到卡
CPU,每一帧消耗的时间,一秒等于1000毫秒
render thread 渲染由显卡决定的
Batches:批处理,
Verts:相机视野内顶点个数
Tris :相机视野内三角面个数
setpasscall:Shader中会包含很多Pass,GPU在运行pass之前,会产生一个SetPass
二、资源优化
1,资源优化标准
mesh 动态模型的面片数<3000, 材质<3,骨骼数<50,
静态模型:顶点数<500
长时音乐(背景音乐)压缩格式mp3
短时音乐 (音效) 非压缩格式wav,不用压缩,重复播放,解压
短音乐勾第一个,长音乐勾第二个
Texture 贴图的长宽小于1024
shader 减少复杂的运算,减少discard操作
2,模型优化,减少面数,贴图优化(贴图合并)
3,减少冗余资源和重复资源
A : Resource目录下的资源不管是否被引用,都会打包进安装包
不使用的资源不要放在Resource目录下
B : 不同目录下的相同资源文件,如果都被引用,都会打进包里
保证同一个资源文件在项目中只存放在一个目录位置
4,资源的检测与分析
UWA工具,优化安装包的大小,优化安装包的性能
三、GPU优化
场景渲染,光照处理,模型角色场景的渲染
1,层级细节LOD优化,越近看到的越精细, LOPGroup组件
2,遮挡剔除 occlusionculling,具体操作看sikiA计划优化的视频10课时
3、光照贴图,具体看siki优化11课时
光源多的时候,将多个光源投射的点提前计算出来,用贴图
选中所有游戏物体
4、Mesh合并
把几个模型合并成一个模型,把几个场景合并成一个大的模型,把模型放入场景中
void MeshCombine()
{
MeshFilter[] filters = GetComponentsInChildren<MeshFilter>();
//专门合并的一个类
CombineInstance[] combiners = new CombineInstance[filters.Length];
for(int i = 0; i < filters.Length; i++)
{
combiners[i].mesh = filters[i].sharedMesh;
//转换坐标
combiners[i].transform = filters[i].transform.localToWorldMatrix;
}
//合并后的mesh
Mesh finalMesh = new Mesh();
//合并
finalMesh.CombineMeshes(combiners);
GetComponent<MeshFilter>().sharedMesh = finalMesh;
}
四、CPU优化
1,数值运算,伤害,随机数,敌人AI,处理逻辑的
如果游戏中有许多小的物体,尽量把这些小物体合并成一个mesh,同时也减少了材质的数量
多个小物体CUP会做多次次准备
使用更少的材质,把多个贴图组合成一个大的贴图
合并物体的时候,这些物体要使用相同的材质才有效果
合并完mesh,如果使用的材质的数量没有减少,是没什么用的,mesh和贴图都要合并
2,对象池,需要频繁创建销毁的放对象池
减少实例化,销毁的过程,不用的时候禁用就可以;
//子弹的资源池
public class BulletPool : MonoBehaviour {
public int poolCount = 30;
public GameObject bulletPrefab;
private List<GameObject> bulletList = new List<GameObject>();
private void Start()
{
InitPool();
}
void InitPool()
{
for(int i = 0; i < poolCount; i++)
{
GameObject go = GameObject.Instantiate(bulletPrefab);
bulletList.Add(go);
go.SetActive(false);
go.transform.parent = this.transform;
}
}
public GameObject GetBullet()
{
foreach(GameObject go in bulletList)
{
if (go.activeInHierarchy == false)
{
go.SetActive(true);
return go;
}
}
return null;
}
}
//子弹的发射
public class Shoot : MonoBehaviour {
public GameObject bulletPrefab;
private BulletPool bulletPool;
// Use this for initialization
void Start () {
bulletPool = GetComponent<BulletPool>();
}
// Update is called once per frame
void Update () {
if (Input.GetMouseButtonDown(0))
{
//GameObject go = GameObject.Instantiate(bulletPrefab,transform.position,transform.rotation);
GameObject go = bulletPool.GetBullet();
go.transform.position = transform.position;
go.GetComponent<Rigidbody>().velocity = transform.forward * 50;
//Destroy(go, 3);
StartCoroutine(DestroyBullet(go));
}
}
IEnumerator DestroyBullet(GameObject go)
{
yield return new WaitForSeconds(3);
go.SetActive(false);
}
}
3,优化编译性能,提高编译速度
把框架类不需要频繁改动的代码放Plugins文件夹下,
只要Plugins下的代码不发生改变就不会重新编译firstPass.dll
改动代码后只会编译Editor和Plugin外的代码