干货!为什么需要纹理过滤?
扫描二维码
随时随地手机看文章
在计算机图形学中,纹理过滤或者说纹理平滑是在纹理采样中使采样结果更加合理,以减少各种人为产生的穿帮现象的技术。纹理过滤分为放大过滤和缩小过滤两种类型。对应于这两种类型,纹理过滤可以是通过对稀疏纹理插值进行填充的重构过滤(需要放大)或者是需要的纹理尺寸低于纹理本身的尺寸时(需要缩小)的一种抗锯齿过滤。
简单来讲,纹理过滤就是用来描述在不同形状、大小、角度和缩放比的情况下如何应用纹理。根据使用的过滤算法的不同,会得到不同等级的模糊、细节程度、空域锯齿、时域锯齿和块状结果。根据使用环境的不同,过滤可能是在软件或者专用硬件中完成,也可能是在软件和专用硬件中共同完成。对用大多数常见的可交互图形应用,现代的纹理过滤是使用专用的硬件进行完成。这些硬件通过内存缓冲和预提取技术优化了内存读写,并且实现了多种可供用户和开发者选择的过滤算法。
有多种纹理过滤方法,不同的方法在计算复杂度、内存带宽和图像质量上分别有不同的权衡。
什么是纹理过滤器?
纹理过滤器是一种用于计算图像纹理的算法,它通过对图像进行计算和处理,可以在游戏中减少纹理锯齿、失真和模糊等问题。纹理过滤器主要分为几种类型,包括最邻近、双线性、三线性和各向异性过滤器等等。
纹理过滤器对游戏的影响:
1. 提高画质
纹理过滤器可以有效地减少游戏中出现的锯齿和模糊等问题,使得游戏图像更加清晰细腻,从而提高游戏的画质。
2. 增强稳定性
通过使用纹理过滤器,可以在游戏中减少图像的闪烁和失真现象,从而增强游戏的稳定性。
3. 减少GPU的使用
使用纹理过滤器可以有效地减少GPU的负担,提高游戏的运行效率和性能表现。
为什么需要纹理过滤?
对于任意的3D表面在纹理映射过程中,需要进行纹理查找来找到屏幕上的一个像素对应于纹理上的哪个位置。纹理映射的过程会根据目标点离相机的远近,占用屏幕上不同大小的范围的像素,例如一个三角面在距离相机20m时占用100个屏幕像素,当三角面离相机更远时会看起来更小,此时可能占用20个屏幕像素,但是在两种情况下这个三角面使用的纹理贴图的大小是不变的。换句话说,由于纹理化表面可以相对于观察者处于任意距离和朝向,因此一个像素通常不直接对应于一个纹理像素。必须应用某种形式的滤波来确定像素的最佳颜色。滤波不足或不正确将在图像中显示为伪像(图像中的错误),例如“阻塞”,锯齿状或闪烁。
屏幕的一个像素与它在对应的纹素之间可以存在不同类型的对应关系。这取决于纹理化表面相对于观察者的位置,并且在每种情况下都需要不同形式的过滤。给定映射到世界中的正方形表面的正方形纹理,在某个观看距离处,一个屏幕像素的大小与一个纹理像素完全相同。当观察者靠近时,纹素(纹理上一个颜色点)大小大于屏幕像素,需要适当放大 - 这一过程称为纹理放大。更远时,每个纹素大小小于一个像素,因此一个像素覆盖多个纹素。在这种情况下,必须通过纹理缩小来基于所覆盖的纹理元素拾取适当的颜色。图形API如OpenGL允许程序员为缩小和放大过滤设置不同的过滤方案。
注意,即使在像素和纹素是完全相同的大小的情况下,一个像素也不一定完全匹配一个纹素。它们可能未对齐或发生旋转,一个像素可能覆盖多达四个相邻纹素的部分。因此,仍然需要某种形式的过滤。
Mipmapping是一种标准技术,用于保存纹理缩小过程中所需的一些过滤工作。它对缓存一致性也非常有益- 没有它,从远距离纹理采样期间的存储器访问模式将表现出极差的局部性,即使没有执行滤波也会对性能产生不利影响。
在纹理放大时,需要为任何像素查找的纹素的数量总是四个或更少; 然而,在缩小时,随着纹理多边形移动得更远,潜在地整个纹理可能落入单个像素中。这将需要阅读所有它的纹素和它们的值组合以正确地确定像素颜色,这是一个非常昂贵的操作。Mipmapping通过预先过滤纹理并将其以较小的尺寸存储到单个像素来避免这种情况。随着纹理表面移动得更远,应用的纹理切换到预过滤的较小尺寸。mipmap的不同大小被称为“级别”,级别0是最大的级别(最接近观看者),并且随着距离增加,对应要增加mipmap等级。
过滤方法
下面列出了几种最常见的过滤方法,按照顺序,越靠后的运算开销越大,但采样结果效果也更好。
最近点插值法(Nearest-neighbor interpolation )
最近点插值法是最简单的纹理过滤方法 — 使用最接近采样点纹素作为采样结果的颜色。简单的代价就是会产生很多人为现象 - 在放大观察时会有明显色块(马赛克),而缩小时会有闪烁和锯齿现象。这种方法在放大的情况下非常快,但是在缩小时开销却极高,因为屏幕上相邻的像素点,可能对应于纹理上距离很远的两个点,而这会破坏纹理采样时的内存连续性,导致L1或者L2缓存的命中率极低,使得纹理采样性能大大降低。
最近点插值+mipmap的方式
这种方式在最近点插值的基础上,引入了mipmap,当距离相机很近时,使用miplevel0,此时和最近点插值完全一样。当距离下相机很远时,使用更高的miplevel等级,此时使用最近点插值采样更小尺寸的纹理。因此可以缓解缩小时的闪烁和锯齿现象,并且能够充分利用纹理采样时的内存连续性,使得纹理采样性能提高。但是在纹理放大时,不能解决产生的色块现象。
加了mipmap之后可以看到噪点消失,但是远处纹理明显模糊,而且不同mipmap过渡处有明显分界,而近处的纹理有明显锯齿
线性过滤+mipmap
OpenGL和其他图形API提供在单独的mipmap层级的贴图上进行最近点采样,但是会对两个相邻的mipmap等级的采样结果进行插值,作为最终结果。该方法很少使用
双线性过滤(Bilinear filtering)
双线性过滤对于锯齿问题会有一个很明显的提升。该方法中,采样目标点附近的4个纹素,并且根据权重(距离中心点的距离)进行加权平均。这种方法使得放大纹理时的色块现象得以消失,因为此时两个相邻像素之间是平滑过度的。当缩小纹理时可以结合mipmap进行使用,尽管当缩小很多时,依然会有和最近点过滤方法一样的锯齿和闪烁现象,但是对于大部分合理的缩小比例,可以作为一种开销较少的有硬件加速的纹理超采样方案。
相比最近点采样,可以看到近处纹理空间的锯齿明显消失,但是不同mipmap等级间的分界依然明显
三线性过滤(Trilinear filtering)
三线性过滤是对双线性过滤中当纹理距离相机的距离刚好处于两个mipmap等级的交界处时的明显的一个过渡现象的解决方案。通过对两个相邻的mipmap等级的纹理进行双线性过滤采样,并对两个采样结果线性插值得到最终的颜色。这样当纹理到相机的距离逐渐增加时,可以得到平滑的一个过渡,而不是突兀的变化。当然,对于足够近的纹理,因为使用miplevel0这个等级,因此和双线性过滤完全一致。
三线性过滤解决了mipmap过渡中的分界问题,但是对角方向上的纹理依然很奇怪,并且异常模糊
各向异性过滤(Anisotropic filtering)
到目前为止我们讨论的都是各向同性过滤方法,也就是说在纹理采样时,不考虑纹理的xy轴与屏幕的xy轴的角度,认为在任何角度时采样结果都是应该一致的(各向同性)。事实上,各向异性过滤是当前消费级显卡中的最高质量的过滤方法。各向同性方案只使用了正方形的mipmap来应用于双线性或三线性纹理过滤(各向同性是指在所有方向上都相同,用来描述所有的mipmap贴图都是方形而不是在某一个轴向上有压缩的长方形或者其他形状)。
当一个物体的表面和相机有很大的夹角时,纹理在屏幕上的对应填充区域就不是方形的。例如一个地板,距离相机远的地方,填充区域的宽高是不对等的,此时方形的纹理贴图就不是很合适了,此时就会导致模糊或者闪烁或者两者皆有。各向异性过滤通过采样一个非方形纹理解决了这个问题。
使用各向异性过滤之后,纹理清晰度得到了很大的提升
上图三线性过滤和各向异性过滤的区别,可以看到远处的地面明显清晰很多。
其他纹理过滤方法
其他纹理过滤方法,因为硬件支持不广泛,很多算法中使用的是软件实现,因此Unity引擎默认没有支持,不再详述。