纹理图像中的纹理单元和屏幕上的像素几乎从来不会形成一对一的对应关系。如果程序员足够细心,确实可以实现这个效果,但这需要在对几何图形进行纹理贴图时进行精心的计划,使出现在屏幕上的纹理单元和像素能够对齐(实际上在用OPenGL进行图像处理应用时,经常做这项工作)。因此,当纹理应用于几何图形表面时,纹理图像不是被拉伸就是被收缩。根据几何图形的方向,一个特定的纹理甚至可能会在贴到一些物体表面的同时就开始进行拉伸或收缩。
根据一个拉伸或收缩的纹理贴图计算颜色片段的过程称为纹理过滤(Texture Fililtering)。使用OPenGL的纹理参数函数,可以同时设置放大或缩小过滤器。这两种过滤器的参数名分别为:
GL_TEXTURE_MAG_FILTER // 纹理被拉伸时的过滤器
GL_TEXTURE_MIN_FILTER // 纹理被缩小时的过滤器
可以为它们从两种基本的纹理过滤器GL_NEAREST和GL_LINEAR中选择,它们分别对应最邻近过滤和线性过滤。确保总是为GL_TEXTURE_MIN_FILTER选择两种过滤器中的一种,因为默认的过滤器不适用于Mip贴图。
最邻近过滤是我们能够选择的最简单、最快速的过滤方法。纹理坐标总是根据纹理图像的纹理单元进行求值和绘图的。不管纹理坐标位于哪个纹理单元,这个纹理单元的颜色就作为这个片段的纹理颜色。GL_NEAREST(也叫邻近过滤,Nearest Neighbor Filtering)是OpenGL默认的纹理过滤方式。当设置为GL_NEAREST的时候,OpenGL会选择中心点最接近纹理坐标的那个像素。下图中你可以看到四个像素,加号代表纹理坐标。左上角那个纹理像素的中心距离纹理坐标最近,所以它会被选择为样本颜色:
最邻近过滤最显著的特征就是当纹理被拉伸到特别大时出现的大片斑驳像素(参见文末贴图)。为放大和缩小过滤器设置最邻近纹理过滤器(用于GL_TEXTURE_2D) 代码如下:
glTextParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTextParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
和最邻近过滤相比,线性过滤还需要更多工作,但它所实现的效果往往值得付出这些额外的开销。在当今高速硬件上,线性过滤带来的额外开销几乎可以忽略不计。
线性过滤并不是把最邻近的纹理单元应用到纹理坐标中,而是把这个纹理坐标作为的纹理单元的加权平均值应用到这个纹理坐标上(线性插值)。为了让这个插值的片段与纹理单元的颜色准确匹配,纹理坐标需要准确地落在纹理单元的中心。线性过滤最显著的特征就是当纹理本拉伸时出现的失真图像,但是和最邻近过滤模式下所呈现的斑驳状像素块相比,这种失真更接近真实,没有那种人工操作的 痕迹。 为放大和缩小过滤器设置线性纹理过滤器(用于GL_TEXTURE_2D) 代码如下:
glTextParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTextParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
GL_LINEAR(也叫线性过滤,(Bi)linear Filtering)它会基于纹理坐标附近的纹理像素,计算出一个插值,近似出这些纹理像素之间的颜色。一个纹理像素的中心距离纹理坐标越近,那么这个纹理像素的颜色对最终的样本颜色的贡献越大。下图中你可以看到返回的颜色是邻近像素的混合色:
那么这两种纹理过滤方式有怎样的视觉效果呢?让我们看看在一个很大的物体上应用一张低分辨率的纹理会发生什么吧(纹理被放大了,每个纹理像素都能看到):
可以看到,最邻近过滤器有明显的斑驳状。