Unity3D研究院之给每个贴图指定不同mipmap减低纹理带宽

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<GameObject>(prefab).GetComponent<MeshRenderer>();

        t1 = mr.material.mainTexture as Texture2D;

        t1.requestedMipmapLevel = 5; //加载第5等级mipmap

        //t1.ClearRequestedMipmapLevel();可以清空加载mipmap的等级

        

    }

    void OnGUI()

    {

        GUILayout.Label("<size=50>desiredMipmapLevel" + t1.desiredMipmapLevel + "</size>");

        GUILayout.Label("<size=50>calculatedMipmapLevel" + t1.calculatedMipmapLevel + "</size>");

        GUILayout.Label("<size=50>loadedMipmapLevel" + t1.loadedMipmapLevel + "</size>");

        GUILayout.Label("<size=50>loadingMipmapLevel" + t1.loadingMipmapLevel + "</size>");

        GUILayout.Label("<size=50>minimumMipmapLevel" + t1.minimumMipmapLevel + "</size>");

        GUILayout.Label("<size=50>mipMapBias" + t1.mipMapBias + "</size>");

    }

如下图所示,我们可以看到贴图已经被加载到第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("<size=80>调整mipmap等级 +</size>"))

        {

            t1.mipMapBias += 1f; //更模糊

        }

        if (GUILayout.Button("<size=80>调整mipmap等级 -</size>"))

        {

            t1.mipMapBias -= 1f; //更清楚

        }

unity还提供了streaming controller组件, 需要绑定在摄像机上,其实就是对摄像机所看到的所有物体的mipmap做偏移和上面的用法类似。

 

我们既然能修改单个物体的贴图的mipmap能否统一修改所有呢?比如现在打开了一个半屏界面,可以将背景中的3D物体的贴图mipmap全部降低。因为UI并不会开mipmap所以即使降低也不会受影响。

1

2

3

4

5

6

7

8

9

        if (GUILayout.Button("<size=80>整体减低采样 -</size>"))

        {

            //0表示正常尺寸

            //1表示降低1/2

            //2表示降低1/4

            //3表示降低1/8

            //4表示降低1/16

            QualitySettings.masterTextureLimit = 4;

        }

在切回0级mipmap

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值