【问题标题】:OpenGL weird line linear filteringOpenGL奇怪的线线性过滤
【发布时间】:2017-11-23 02:48:36
【问题描述】:

我编写了以下着色器,用于测试线性过滤在 OpenGL 中的工作原理。

这里我们将一个 5x1 的纹理喷到立方体的一个面上(megenta 区域只是背景的颜色)。

纹理就是这个(很小)。

左下角对应uv=(0, 0)右上角对应uv=(1, 1)。 启用线性过滤。

着色器将v 坐标垂直拆分为 5 行(从上到下):

  1. 连续采样。只需正常采样即可。
  2. 如果 u 在 [0, 1] 中则为绿色,否则为红色。仅用于测试目的。
  3. 灰度 u 坐标。
  4. 在纹素左侧采样。
  5. 在纹素中心采样。

问题是在34 之间有一行闪烁的一个像素。闪烁通过改变相机距离来改变,有时你甚至可以让它消失。问题似乎出在处理第四行的着色器代码中。

// sample at the left of the pixel
// the following line can fix the problem if I add any number different from 0
tc.y += 0.000000;  // replace by any number other than 0 and works fine
tc.x = floor(5 * tc.x) * 0.2;
c = texture(tex0, tc);

这对我来说看起来很奇怪,因为在该区域中,v 坐标不在纹理的任何边缘附近。

【问题讨论】:

  • 那么,纹理对象是如何设置的?
  • 不确定设置纹理对象是什么意思。你是指glTexParameter设置的东西吗?如果是这样,您可以在图像的左下角看到它们:线性过滤和钳制到边缘。

标签: opengl textures filtering


【解决方案1】:

您的代码在纹理提取期间依赖于未定义的值

第 8.9 节纹理函数中的GLSL 4.60 specification 状态(重点是我的):

某些纹理函数(非“Lod”和非“Grad”版本)可能需要 隐式导数。 隐式导数在其中未定义 非统一控制流和非片段着色器纹理提取。

虽然大多数人认为这些导数仅用于 mip 映射,但这是不正确的。还需要 LOD 因子来确定纹理是放大还是缩小(以及非 mipmapped 情况下的各向异性过滤,但这里不感兴趣)。

GPU 通常通过 2x2 像素四边形中相邻像素之间的有限差分来近似导数。 正在发生的事情是,在您的各种选项之间的边缘,您有非统一的控制流,您对一行进行纹理过滤,而在上面的一行中,您不这样做。有限差分将导致尝试访问上排纹理采样操作的纹理坐标,这根本不能保证已经计算过,因为该着色器调用没有主动执行该代码路径 - 这就是为什么规范将它们视为未定义。

现在,根据您的边缘在 2x2 像素四边形中的哪个位置,您会得到正确的结果,或者没有。对于您没有得到正确结果的情况,一种可能的结果可能是 GL 使用缩小过滤器,在您的示例中为 GL_NEAREST

将两个过滤器都设置为GL_LINEAR 可能会有所帮助。但是,这仍然不是正确的代码,因为根据规范,结果仍然是未定义的。

唯一正确的解决方案是将纹理采样移出非均匀控制流,例如

vec4 c1=texture(tex, tc); // sample directly at tc
vec4 c2=texture(tex, some_function_of(tc)); // sample somewhere else
vec4 c3=texture(tex, ...);

// select output color in some non-uniform way
if (foo) {
   c=c1;
} else if (bar) {
   c=c2;
} else {
   c=c3;
}

【讨论】:

  • 非常感谢!正如您所猜测的那样,打开最小线性过滤可以修复闪烁。您的回答也提供了深刻的见解。还有一件事我很好奇。为什么向tc.y 添加任何数字也可以解决问题?我进行了进一步的测试,而不是添加常量零,而是添加了一个我设置为零的制服(因此编译器无法通过删除该指令来优化该代码)。结果是它也消除了闪烁!
  • 顺便说一句,我使用的是 GLSL 330,但它似乎也适用。
  • 是的,它适用于迄今为止的每个 GLSL版本,并且在可预见的未来不太可能发生变化。
  • 我尝试在非统一控制流之外进行采样,效果也很好
  • "为什么向 tc.y 添加任何数字也可以解决问题?" undefined 是未定义的,它可以表示任何东西,包括“现在恰好存储在某些寄存器中的值”。如果您更改代码,这些值也会更改。修改从未解决问题,它只是隐藏了它。
猜你喜欢
  • 2020-06-25
  • 2012-06-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-05
  • 1970-01-01
  • 2017-09-08
相关资源
最近更新 更多