消除纹理贴图时的接缝
作者: 刘鹏
日期: 2011-12-13
本文分析了 Texture 贴图时产生接缝的原因,并给出了解决方案。

问题的提出

texture 贴图时,相邻tile会有接缝现象,如下图所示。

带接缝
带接缝

该图有左右两个 texture 组成,中间可看到明显的接缝。

原因及其解决办法

贴纹理时纹理图像中的单个纹理单元很少与最终屏幕图像中的单个像素形成一一 对应关系,这样就需要采样和过滤,glTexParameter 函数可设定很多过滤方式, 如 GL_NEAREST、GL_LINEAR等。若选择 GL_NEAREST,则使用靠近像素中心的那个纹理单元 ;若选择 GL_LINEAR,则对靠近像素中心的一块2x2纹理单元取加权平均值。当纹理坐标靠近 会纹理图像的边缘时,最临近的 2x2 纹理单元可能包含了纹理图像之外的内容,于是就出现了接缝现象。

在这种情况下,OpenGL 使用的纹理单元取决于当前生效的环绕模式以及纹理是否具有边框。 通过使用 Texture Wrapping Mode 中的 GL_CLAMP_TO_EDGE ,使纹理采样时忽略边界,可消除接缝。

Texture Wrapping Mode

在进行纹理帖图时,图象会出现在物体表面的(u,v)位置上,而这些值在[0.0,1.0]范围内。但是,如果超出这个值域,会发生什么情况呢?这由纹理的映射函数来决定。在OpenGL中,这类映射函数称为“Texture Wrapping Mode”;在D3D中,称为“Texture Addressing Mode”。常见的有下面几种:

  1. 重复(GL_REPEAT):图象在表面上重复出现。在算法上,忽略纹理坐标的整数部分,并将纹理图的拷贝粘贴在物体表面上。对于大多数复制纹理的使用,在纹理顶部的纹理单元应与底部的纹理单元相匹配,在纹理左侧的纹理单元也应与右侧的纹理单元相匹配。这样才能做到无缝连接。

 2. 截取(GL_CLAMP):将大于1.0的数值设置为1.0,将小于0.0的数值设置为0.0,即将超出[0.0,1.0]范围的数值截取到[0.0,1.0]范围内,这样会导致纹理边缘的重复。

 3. 镜像重复(GL_MIRRORED_REPEAT_ARB):图象在物体表面上不断重复,但是每次重复的时候对图象进行镜像或者反转。这样在纹理边缘处比较连贯。在OpenGL中通过ARB_texture_mirrored_repeat扩展来实现。

 4. 边界截取(CLAMP_TO_BORDER_ARB):在[0.0,1.0]范围外的参数值用单独定义的边界颜色或纹理边缘进行绘制。适合于绘制物体表面的贴花纸。在OpenGL中通过ARB_texture_border_clamp扩展来实现,CLAMP_TO_BORDER_ARB在所有mipmap层次上对纹理坐标进行截取,使nearest和linear过滤只返回边界纹理单元的颜色。

 5. 边缘截取(GL_CLAMP_TO_EDGE):总是忽略边界。处于纹理边缘或者靠近纹理边缘的纹理单元都用作纹理计算,但是不包括边界上的纹理单元。

在OpenGL1.2以前的版本中并未对最初的GL_CLAMP进行详细的说明。按照定义,在双线性插值过程中,在纹理边界以外的点是由纹理边缘像素和边界颜色各自一半混合形成的。在OpenGL1.2中,引入了GL_CLAMP_TO_EDGE,用来纠正这个问题。同时,GL_CLAMP_TO_BORDER_ARB则只对那些纹理边界上的边界点进行采样。但是,因为很多硬件并不支持边界处理,所以实现GL_CLAMP_TP_EDGE和GL_CLAMP的效果好象是一样的。新出现的硬件(如GeForce3)正确实现了GL_CLAMP,但是结果通常并不是所期望的。

代码实现


    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    //Fix texture seam
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);