Unity 性能优化
Unity之所以可以跨平台是应为unity里面有内置的mono虚拟机,我们所写的程序是运行在mono虚拟机上面,因为mono虚拟机可以跨平台所以我们开发的程序也是可以跨平台的。
Draw Call
简单来说Draw Call就是CPU对图形接口的调用,cpu通过调用图形库(DX,OpenGL)接口,命令GPU渲染,一次调用就是一次Draw Call。每调用一次Draw Call ,cpu就会做一次准备,调用的次数增多了之后,cpu就负载过多,GPU就会闲置。(比如说文件的复制,一个1000M的文件和1000个1M的文件同时复制,当然是前者比较快)
Stats面板参数:
FPS(帧数):越大越好
CPU(主线程,处理器计算速度):代表执行每帧所需的时间,越低越好
render thread(渲染线程,GPU渲染所需要的时间):越低越好
Batches(渲染批次):与DrawCall关联,代表渲染批次
Tris(三角面数):相机视野范围内的三角面数量
Verts(顶点数):相机视野范围内的顶点数量
SetPass calls:Unity中的Shader中包含很多Pass块,每当GPU即将去运行一个Pass块之前,就会产生一个“SetPass call”,在描述性能开销上更有说服力
资源优化的标准
unity动态模型 :
面数<3000
材质数<3
骨骼数<50
unity静态模型:
顶点数<500
Audio
长时间音乐(背景音乐)用mp3(压缩)
短时间音乐(音效)用WAV(未压缩,重复调用)
压缩方式
Decompress On Load:适用于小文件
Compressed in Memory:使用于大文件
Streaming:以流的形式便加载边播放(对CPU消耗较大一般不采用)
Texture贴图宽度<1024
shader减少复杂的数学运算,减少discard操作,减少if else的使用
模型优化:面片减少,模型网格合并
贴图优化:贴图合并
减少冗余资源和重复资源
1.Resource文件夹下的文件不管是否用到都会打包进去
2.不同目录下的相同文件都会被打包造成资源的重复和冗余
可以用uwa优化工具进行检查
层级细节LOD技术(一个物体,三种精细程度不同的模型,距离越近模型越精细)
此技术需要美工的配合,提供给程序多个不同三角面数的模型,在场景中新建一个空的游戏物体,并添加LOD Group组件,并将美工提供的三种不同精度的模型按照精度的大小依次拖入到LOD0、LOD1、LOD2中,此时,场景中渲染显示的模型会根据相机与模型的距离进行切换显示,具体的切换显示距离可拖动组件中的条形框大小进行自定义,这样便达到了近处渲染精模,远处渲染粗模甚至不渲染来减少GPU消耗的目的
遮挡剔除OcclusionCulling(只渲染视野内的物体,被遮挡和不在视野之内的物体不进行渲染)
选择需要遮挡剔除的物体,在Static里面选择Occluder Static,在菜单栏的Window中点击OcclusionCulling,然后点击Bake,然后指定Camera,再点击Bake就OK了。
光照贴图Lighting Map(渲染一张灯光贴图代替场景中的灯光)
选择场景中的游戏物体,选择Static中的LIghtmap Static。选择所有的光照,Light的Mode选择为Baked,然后点击Lighting Settings中的Bake进行烘焙,烘焙完之后,就可以关闭光照了。
对象池技术(当有游戏物体需要频繁的创建删除的时候,使用对象池技术,可以节约性能)
UGUI优化
上下两个相同深度的Mask是可以进行合批的,上下两个相同深度的Mask的子物体如果满足合批条件也是可以合批的(前提是他们不重叠)。不能合批的时候,每个Mask占两个draw call。
Rect Mask 2D不占draw call,Rect Mask 2D中的子物体之间可以进行合批,但是上下两个Rect Mask 2D
的子物体不能进行合批。
天空盒占五千个顶点,一千七百个三角面,在做2D游戏时,如果做纯色背景或者天空盒一直被挡住的时候,记得要把天空盒关了,因为天空盒也照样会被渲染,没有遮挡剔除的操作。
image中的Image Type选择Tiled平铺模式的时候,模型的顶点和三角面增加了十几倍甚至更多。优化的方法是使用Raw Image,选择贴图后,改变UV Rect就可以了,顶点数和三角面并没有增加。
Canvas下的Pixel Perfect用来矫正像素的,比如经常使用滚动视图时,但作用不大,尽量不开。
Text或者Image这些组件上有个Raycast Target,是负责射线检测的响应事件的,如果不需要进行鼠标点击的一些操作的话,要把Raycast Target取消勾选。
有些UI需要经常移动的,有些UI一直都不需要移动的,当你移动一个UI的时候,就会触发UI的ReBatch和ReBuild,UI的所有网格都要进行重新绘制,这是比较费性能的。解决办法是我们可以建多个Canvas,一个Canvas负责管理一直都不动的UI,一个Canvas负责管理偶尔会移动的UI,这样就实现了动静分离,网格重新绘制的时候就只是绘制动的那个Canvas下的所有UI,不移动的那个Canvas不会进行网格重绘,但是这样也有个缺点就动静Canvas之间的层级不好区分,那么最好的解决办法就是,我们只用一个Canvas就可以了,然后在需要移动的UI上添加一个Canvas组件就可以了,最好不要让太多UI都添加Canvas组件。
改变UI上的Color的颜色也会触发网格重绘,但是改变材质的颜色就不会触发网格重绘,所以解决办法就是新建一个Material,拖到UI上,Material的shader选择UI/Default,改变Material的颜色就可以了。
UI中调用SetActive()方法也会触发网格重构,解决办法是在需要隐藏或者显示的UI上添加Canvas Group组件,然后设置Alpha是0或者1就可以隐藏或者显示了,不会触发网格重构。
Text上的Best Fit尽量不要使用,虽然能够自适应字体大小,挺好用,但是代价挺高的,因为每种大小的字体都会被存在图集中,包括粗体字和斜体字等。
多个Button时,改变Button的z轴的值会打断合批,增加dc,而改变PosX和改变PosY不会打断合批。旋转x和y时,旋转0,180,360,540…等度数不会打断合批,其他度数均会打断合批,而旋转z的任意度数都不会打断合批。多个Image时,怎样改变位置和旋转都不会打断合批。
点击任意区域继续…
在游戏中,可能我们需要点击任意区域关闭显示或者继续其他的操作之类的,这时我们会新建一个Image,将UI填满整个屏幕,然后再添加点击事件,确实是这么做,但这么做有个什么弊端呢?就会会造成过多的overdraw,而一个Image是由Rect区域来控制触发响应事件的,由mesh来显示形状的,而产生overdraw就是由于mesh产生的,所以我们清除掉mesh就不会产生overdraw了。
新建一个在Canvas中的空物体,再添加一个自己新建的脚本挂载上去,代码如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class RaycastTest : Image
{
protected override void OnPopulateMesh(VertexHelper toFill)
{
toFill.Clear();
}
}