使用纹理地图集和相邻纹理像素泄漏的问题与线性纹理过滤的工作方式有关。
对于纹理中未在纹理像素中心进行精确采样的任何点,线性采样将对4个相邻纹理像素进行采样,并在您要求的位置计算值作为所有4个像素的加权平均值(基于与采样点的距离)样品。
这是一个很好的可视化问题:
由于不能GL_CLAMP_TO_EDGE
在纹理图集中使用类似的东西,因此需要在每个纹理的边缘周围创建边框纹理。这些边界纹素将防止来自图集中完全不同纹理的相邻样本通过上述加权插值来更改图像。
请注意,使用各向异性过滤时,可能需要增加边框的宽度。这是因为各向异性过滤将以极端角度增加样本邻域的大小。
为了说明通过在每个纹理的边缘周围使用边框来表示我的意思,请考虑OpenGL中可用的各种环绕模式。要特别注意CLAMP TO EDGE
。
尽管有一个名为“钳到边界”的模式,但实际上这并不是我们感兴趣的模式。该模式使您可以定义一种单色,以用作超出规范化[0.0]范围之外的任何纹理坐标的纹理边界-1.0]范围。
我们想要的是复制的行为CLAMP_TO_EDGE
,其中,(子)纹理的适当范围之外的任何纹理坐标都将沿其超出范围的方向接收最后一个texel中心的值。因为您几乎可以完全控制在Atlas系统中,纹理坐标只能在纹理过滤的加权平均步骤中(有效)纹理坐标引用纹理之外的位置。
GL_LINEAR
如上图所示,我们知道将对4个最近的邻居进行采样,因此我们只需要一个1-texel边框。如果使用各向异性过滤,则可能需要更宽的纹理像素边界,因为在某些条件下,它会增加样本邻域的大小。
这是一个纹理示例,可以更清楚地说明边框,但出于您的目的,您可以使边框宽1像素或2像素。
(注意:我指的边框不是图像所有四个边缘周围的黑色,而是棋盘格图案停止规则重复出现的区域)
如果您想知道,这就是为什么我不断提出各向异性过滤的原因。它会根据角度改变样品邻域的形状,并可能导致使用4个以上的纹理像素进行过滤:
http://www.arcsynthesis.org/gltut/Texturing/ParallelogramDiag.svg
使用的各向异性程度越大,处理包含4个以上纹理像素的样本邻域的可能性就越大。2纹素边框对于大多数各向异性过滤情况应该足够了。
最后但并非最不重要的是,这是如何构建打包的纹理图集,该纹理图集将GL_CLAMP_TO_EDGE
在存在GL_LINEAR
纹理滤镜的情况下复制行为:
(在黑色坐标中从X和Y减去1,我没有证明过要在发布前阅读图像。)
由于边界存储,在此图集中存储4 256x256纹理需要一个尺寸为516x516的纹理。根据在图集创建过程中如何以纹素数据填充边框,边框会采用颜色编码:
- 红色=在下方直接替换为texel
- 黄色=在上方直接替换为texel
- 绿色=在左侧直接替换为texel
- 蓝色=直接在右侧替换为texel
有效地在此压缩示例中,图集中的每个纹理都使用图集的258x258区域,但是您将生成映射到可见256x256区域的纹理坐标。仅在图集中纹理的边缘进行纹理过滤时,才使用边界纹理元素,并且它们的设计方式模仿GL_CLAMP_TO_EDGE
行为。
如果您想知道,可以使用类似的方法来实现其他类型的环绕模式- GL_REPEAT
可以通过交换纹理图集中的左/右和上/下边界纹理来实现,并且可以在模型中使用一些巧妙的纹理坐标数学来实现着色器。这有点复杂,所以暂时不用担心。由于您只处理精灵表,因此请限制为GL_CLAMP_TO_EDGE
:)
GL_NEAREST
还是GL_LINEAR
用于渲染纹理?