GPU发热的元凶之一“带宽” 所以通常我们都会打开mipmap,如下图所示,在unity中可以拖动右上角的条来查看贴图每个等级的mipmap贴图。那么它的等级一共分成0级-9级, 0级表示最清楚,9级表示最模糊。 贴图分辨率是依次减半,如512 256 128 64 32 16 8 4 2 0
所以说如果带了mipmap的贴图在内存上就会多占33%左右,然而显存和纹理带宽就不一定了,如果摄像机离得比较远,就会采用更小的贴图渲染,贴图所占显存小了,那么对应纹理带宽也一并减小,从而性能就优化了。
也有团队为了减少内存,从而关闭了mipmap。这就会导致另一个问题,美术的贴图非常精细,在UI中近距离观察效果很好,可是一旦摄像机拉远,就会出现“噪点”很难看。 所以mipmap一定要打开。
总体来说mipmap是用内存换纹理带宽的一种优化方式。可是内存毕竟涨了33%,所以unity2018.2中提供了streaming流加载贴图mipmap,意思就是用到哪一级mipmap只加载这一级的,其他级的mipmap不加载。这将大量减少内存开销,如下图所示,unity提供了一个demo例子,内存大概减少25%-30%。
到这里大家应该都能很好理解流加载,其实本篇文章我想说的是利用流加载的特性来进一步优化纹理带宽。例如,
1.unity原本默认计算出需要加载第0级的mipmap贴图,我们能不能手动设置成别的级别mimap
2.比如打开非全屏界面,能不能强制将游戏里面所有3D物体的mipmap都降到最低
答案是可行的,有了这两个特性,我们就可以自己灵活控制mipmap按需加载了。
首先我们需要在unity中开启texture streaming,如下图所示,在Quality Setting面板中勾选Texture Streaming,请注意Max Level Reduction这个数值比较重要,它的意思就是mipmap最多可以减小几级,最大是7.默认是2,如果是2的话,那么代码里怎么设置最多只能减少2级.
Max Level Reduction代码中也可以动态修改。
1
2
//mipmap最多可以减少的等级, 默认是2 ,也可以在QualitySettings面板中设置
QualitySettings.streamingMipmapsMaxLevelReduction = 7;
还需要在Editor Settings中勾选 Enable Texture Streaming,我的测试中即使勾选在编辑器下也未必能有正确的结果,所以大家一定要打出包在真机中查看。
如下代码所示,首先实例化一个Prefab,并且调用requestedmipmaplevel来设置默认加载mipmap的等级。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void Start()
{
mr = Instantiate(prefab).GetComponent();
t1 = mr.material.mainTexture as Texture2D;
t1.requestedMipmapLevel = 5; //加载第5等级mipmap
//t1.ClearRequestedMipmapLevel();可以清空加载mipmap的等级
}
void OnGUI()
{
GUILayout.Label("desiredMipmapLevel" + t1.desiredMipmapLevel + "");
GUILayout.Label("calculatedMipmapLevel" + t1.calculatedMipmapLevel + "");
GUILayout.Label("loadedMipmapLevel" + t1.loadedMipmapLevel + "");
GUILayout.Label("loadingMipmapLevel" + t1.loadingMipmapLevel + "");
GUILayout.Label("minimumMipmapLevel" + t1.minimumMipmapLevel + "");
GUILayout.Label("mipMapBias" + t1.mipMapBias + "");
}
如下图所示,我们可以看到贴图已经被加载到第5级的mipmap了。此时你可能会有个疑问,如果摄像机拉远拉近是否会影响mipmap,答案是肯定的,只是摄像机拉到最近mipmap也只能5,但是摄像机如果拉远超过了5,那么就会自动适应6 、7级。
这里有几个数值的含义我需要解释一下,
calculatedMipmapLevel:表示当前摄像机与物体的距离计算出需要加载的mipmap等级。
desiredMipmapLevel:表示当前实际加载的mipmap等级,因为我们可能强制设置了加载等级,那么实际加载的可能就和calculatedMipmapLevel不一致了。
mipMapBias:表示加载加载mipmap等级的偏移量,比如原本加载的是0级的mipmap,由于mipMapBias设置了2,所以实际加载的就是2级,这个数值也可以设置成负数,比如原本需要加载2级mipmap,由于设置了-1,所以实际加载1级的mipmap,这样无疑就更浪费性能。
下面我们在代码里动态修改mipmap的等级。
1
2
3
4
5
6
7
8
if (GUILayout.Button("调整mipmap等级 +"))
{
t1.mipMapBias += 1f; //更模糊
}
if (GUILayout.Button("调整mipmap等级 -"))
{
t1.mipMapBias -= 1f; //更清楚
}
unity还提供了streaming controller组件, 需要绑定在摄像机上,其实就是对摄像机所看到的所有物体的mipmap做偏移和上面的用法类似。
我们既然能修改单个物体的贴图的mipmap能否统一修改所有呢?比如现在打开了一个半屏界面,可以将背景中的3D物体的贴图mipmap全部降低。因为UI并不会开mipmap所以即使降低也不会受影响。
1
2
3
4
5
6
7
8
9
if (GUILayout.Button("整体减低采样 -"))
{
//0表示正常尺寸
//1表示降低1/2
//2表示降低1/4
//3表示降低1/8
//4表示降低1/16
QualitySettings.masterTextureLimit = 4;
}
在切回0级mipmap