Unity中纹理与Mipmap的进一步研究
在上一篇文章中我浅谈了一下Unity中的Mipmap和Texture Streaming技术,对于Mipmap而言我只介绍了它会占用更多内存。然而最近有个令我很困惑的问题,那就是Mipmap的优缺点。对于优点,网上很多博客都列举了两点:1、解决采样率不足问题,避免贴图出现噪声和摩尔纹 2、优化gpu带宽。对于前者我是理解的,因为更模糊的Mipmap中每个像素的采样空间更大;然而对于后者,网上的博客很少有给出具体原因的,并且文章中对于Mipmap图片究竟是增加了显存还是降低了显存都各执己见。先说我的观点吧,Mipmap确实能优化显存带宽,是通过纹素的连续性来实现的。使用Mipmap实际上会增加内存和显存,只有配合Texture Streaming才能降低内存和显存。
首先是第一点,先补充一个计算机知识,计算机中cpu/gpu对于不同的存储介质访问的速率是不一样的,遵循金字塔规律,即寄存器>L1、L2、L3Cache>内存/显存>磁盘>外设。那么想要提高显存带宽的话就得提高gpu L1、L2、L3Cache的命中率,如果命中率低的话就得在更慢一点的显存里取数据,单位时间内传输的数据量就更少了。另一个知识是cpu/gpu在取数据时通常不是一个字节一个字节取的,而是一块一块取的,为了利用局部性原理(相邻的数据有更大的机率在未来被使用)。此时,存储数据的连续性就很重要了。以gpu取纹理数据为例,假如没开Mipmap的话,对于远处的物体而言,相邻像素对应的纹素相隔会非常远,因为此时一个像素会对应一大块纹素,而开了Mipmap的话是更容易取到相邻纹素的。结合之前说的cpu/gpu在取数据时按块来取,一次性取一段连续的纹素数据,那么下一次来取纹素的时候大概率数据已经在Cache中了,不需要再在显存中访问了,以此达到优化gpu带宽的目的。
第二点,对于Mipmap实际上会增加内存和显存这个观点,先摆出官方文档。其中有两段话:
第一段话翻译一下是Unity在加载纹理时直接上传显存,而不会等到纹理被相机看见时再上传。第二段话意思是如果GPU显存满了,会卸载最近最少使用的Texture,并强制在下次需要渲染时CPU重传该纹理。我推测所谓卸载Texture应该是显存和内存进行数据交换,内存中当前需要渲染的Texture和显存中最近最少使用的Texture进行交换。
第一段话说明了Mipmap Texture是全部level被加载进显存的,内存应该只是分配了个buffer用来缓冲数据(Texture开了Read/Write的话还会额外在内存保存一份Texture数据,这里不讨论)。为啥是全部level呢,因为一是相机都没渲染,怎么知道要用到哪些level;二是就算相机开始渲染了,计算level也是在gpu中干的(参考上一篇文章),cpu并不知道要用哪些level。那既然不知道要用哪些level就只能全部加载了,于是得出结论Mipmap会增大显存。
第二段话根据我的推测显存、内存会进行Texture的交换,自然内存中也会有Texture的全部level,因此内存也是会增大的。
那为了避免显存、内存的增加就可以配套使用Texture Streaming技术动态的加载/卸载具体某个level的数据(参考上一篇文章)。
接下来谈一谈为什么有的文章说Mipmap会降低显存,给出的观点是远处的物体使用了尺寸更小的Texture(更模糊的Mipmap)进行渲染,因此显存中的Texture数据量降低了。问题在于gpu在渲染时不是动态从内存中加载某level数据到显存中再进行采样的,而是cpu提前把所有level的Mipmap都传到显存,采样时gpu再根据算出来的level,取该level纹理对应的纹素点数据(双线性插值会取4个纹素点数据,然后插值)。
PS:文章中很多观点是我在官方文档的基础上推测的,如果有错误还望指正!
参考链接:
Optimizing Graphics in Unity - Unity Learn
Mipmap详解(有无Mipmap区别、原理、优点、缺点、优化)
OpenGL-mipmap - 知乎 (zhihu.com)
Unity3D研究院之给每个贴图指定不同mipmap减低纹理带宽 一个mipmap的事能抠这么多篇文章这么多字,难道以前是写网文的? 承认是有点啰嗦,语句不够精炼[大笑]
页:
[1]