、先了解纹理过滤

        想要了解为什么要使用Mipmap,首先要知道纹理过滤是什么。

        当你在玩吃鸡的时候可能会发现一个现象,一个人在距离你5米的地方,可以观察到敌人的一举一动,包括身上的装备等等,但当你拿到98k时,你会蹲在远处狙击别人,这时不开镜的你看500米远处的敌人只能看到一个黑点,这其中远近看到的区别就有应用到纹理过滤

        游戏中A物体的游戏设计纹理贴图是400*400Texel(纹理像素)

        1.当你(摄像机)跟A物体的距离为0时,在你屏幕上显示的像素就是400*400,跟贴图的纹理像素大小相同,此时不需要做特殊处理

        2.假设你离A物体10米远时,屏幕显示的pix为200*200,当200*200的像素要显示400*400纹理像素的物体时,此时的一颗像素需要映射2*2的纹理像素,这个时候就有个问题了,这颗像素要显示什么颜色?只能用合适的算法在这2*2里的纹理像素中计算得出,在这里引用OpenGL中的邻近过滤和线性过滤:

        GL_NEAREST(也叫邻近过滤,Nearest Neighbor Filtering)是OpenGL默认的纹理过滤方式。当设置为GL_NEAREST的时候,OpenGL会选择中心点最接近纹理坐标的那个像素。下图中你可以看到四个像素,加号代表纹理坐标。左上角那个纹理像素的中心距离纹理坐标最近,所以它会被选择为样本颜色:

        GL_LINEAR(也叫线性过滤,(Bi)linear Filtering)它会基于纹理坐标附近的纹理像素,计算出一个插值,近似出这些纹理像素之间的颜色。一个纹理像素的中心距离纹理坐标越近,那么这个纹理像素的颜色对最终的样本颜色的贡献越大。下图中你可以看到返回的颜色是邻近像素的混合色:

        那么这两种纹理过滤方式有怎样的视觉效果呢?让我们看看在一个很大的物体上应用一张低分辨率的纹理会发生什么吧(纹理被放大了,每个纹理像素都能看到):

二、当距离很远的时候怎么算?

        此时的你来到远离市区500米的山上,想要狙击别人,你只能看到一个个很小的人影,在不开镜的情况下只能看到人的跑动。

        此时敌人在屏幕显示为20*20,400*400的纹理像素映射在20*20的像素内,一颗像素需要映射20*20的纹理像素,如果直接进行纹理过滤,那么在使用线性过滤的情况下,只会使用纹理坐标映射点的周围4颗纹理像素进行计算,那么其他的396颗纹理像素就没了参考价值,考虑极端情况下,如果纹理坐标映射点在人的头发,那么不就只是显示黑色了? ,那么在最终的显示效果上可能会产生锯齿或者摩尔纹,摩尔纹长这样:

        这视觉效果必须得改善,那我不能参考所有需要映射的纹理像素进行平均取色吗?可以,但是你的GPU允许你这么做吗,有兴趣可以做个实验,自己采样所有纹理像素进行纹理过滤,此时你如果远处的模型较多的情况下,

        使用原生的线性过滤:60FPS,渲染一个物体每颗像素的颜色需要计算4个纹理像素的插值。

        采样所有纹理像素进行纹理过滤:1FPS,渲染一个物体每颗像素的颜色需要采样计算400个纹理像素的插值。

        可以想象性能换质量的消耗实在太大,在如今的GPU算力下是施行不了的.

        那有办法不损耗算力,又可以提升显示质量吗?可以,使用Mipmap.

三、Mipmap概念

          想象一下,假设我们有一个包含着上千物体的大房间,每个物体上都有纹理。有些物体会很远,但其纹理会拥有与近处物体同样高的分辨率。由于远处的物体可能只产生很少的片段,OpenGL从高分辨率纹理中为这些片段获取正确的颜色值就很困难,因为它需要对一个跨过纹理很大部分的片段只拾取一个纹理颜色。在小物体上这会产生不真实的感觉,更不用说对它们使用高分辨率纹理浪费内存的问题了。

          OpenGL使用一种叫做多级渐远纹理(Mipmap)的概念来解决这个问题,它简单来说就是一系列的纹理图像,后一个纹理图像是前一个的二分之一。多级渐远纹理背后的理念很简单:距观察者的距离超过一定的阈值,OpenGL会使用不同的多级渐远纹理,即最适合物体的距离的那个。由于距离远,解析度不高也不会被用户注意到。同时,多级渐远纹理另一加分之处是它的性能非常好。

 四、Mipmap效果        

 

         上图是Mipmap的纹理,在储存上最大的为mipmap0,mipmap1的分辨率为mipmap0的一半,以此一直创建下去,直到纹理为一个像素时停止,在某些引擎中可以设置Mipmap的强弱,也就是Mipmap的创建次数。但一般直接拉到最强,因为越到后面创建的大小越小,占用的内存也就越小.

不使用Mipmap:

        在先前讲的1颗像素需要映射20*20的纹理像素时,显示效果失真,锯齿以及可能会产生摩尔纹,发生的原因是在纹理过滤时,一颗像素只采样了原本20*20纹理像素里2*2纹理像素的颜色进行线性插值,得到最终的颜色,其他的396颗纹理像素无用,浪费显存且取色不精确

使用Mipmap:

        Mipmap创建:预先创建原纹理大小2分之一的多级渐远纹理,在多级渐远纹理取色采样时,也会进行线性过滤,可以理解成预先创建每隔一定阈值(也就是每次映射像素为上一级别多级渐远纹理的2分之一的时候)并经过了线性过滤的纹理。

        使用Mipmap的渲染过程:20*20的像素需要映射400*400的纹理像素时,检测到一颗像素需要映射到纹理像素为20*20,在Mipmap纹理中里寻找最接近20*20纹理像素的多级渐远纹理,并使用此多级渐远纹理进行采样。

        此时采样用的多级渐远纹理的颜色也是从上一级的多级渐远纹理迭代采样插值计算而来,也就是一颗像素映射此多级渐远纹理间接插值计算了20*20的纹理像素的颜色,取色的效果当然比一颗像素直接映射原图20*20只采样了2*2的纹理像素颜色进行线性插值要好得多,使用Mipmap就避免了采样的纹理像素过少而失真,

        理论上点对点的映射最为精确,而如果最邻近的子纹理跟20*20无法点对点采样映射,还可以设置多级渐远纹理的过滤方式

过滤方式描述
GL_NEAREST_MIPMAP_NEAREST使用最邻近的多级渐远纹理来匹配像素大小,并使用邻近插值进行纹理采样
GL_LINEAR_MIPMAP_NEAREST使用最邻近的多级渐远纹理级别,并使用线性插值进行采样
GL_NEAREST_MIPMAP_LINEAR在两个最匹配像素大小的多级渐远纹理之间进行线性插值,使用邻近插值进行采样
GL_LINEAR_MIPMAP_LINEAR在两个邻近的多级渐远纹理之间使用线性插值,并使用线性插值进行采样

五、Mipmap的优点与缺点

  优点:

        1.质量高:避免了在远距离情况下的采样频率低和数据频率高造成的失真和摩尔纹,效果比无Mipmap好得多。

        2.性能好:避免了不使用Mipmap下距离远时采样频率低和数据频率高而照成texture cache命中率不高(相邻Pixel采样Texel时uv相差比较大)使性能下降。

  缺点:

         1.占用显存,可使用ue的纹理流缓存优化(IO换显存)。

六:UE4的纹理流缓存(多级渐变纹理的内存优化)

        UE4的纹理流缓存是动态的,在摄像机位置离物体远时,纹理流缓存会动态刷新目前位置的多级渐变纹理,所以在远的时候缓存区小,近的时候缓存区大,缓存的纹理大小随距离远近需求的纹理细节而改变.只有纹理细节大且多,占用显存过高的3A级别的游戏,才会使用纹理流缓存优化显存空间(IO换显存)。

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐