OpenGL奇异线线性滤波

OpenGL奇异线线性滤波,opengl,textures,filtering,Opengl,Textures,Filtering,我已经编写了以下着色器,用于测试OpenGL中线性过滤的工作原理 在这里,我们有一个5x1纹理飞溅到一个立方体的表面上(megenta区域只是背景的颜色) 纹理就是这个(非常小) 左上角对应于uv=(0,0),右上角对应于uv=(1,1)。 线性过滤已启用 着色器将v坐标垂直拆分为5行(从上到下): 连续采样。正常取样 如果u在[0,1]中,则为绿色,否则为红色。只是为了测试的目的 灰度中的u坐标 在texel的左侧进行采样 在纹理中心取样 问题是在3和4之间有一行闪烁的像素。闪烁通过改变相

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

在这里,我们有一个5x1纹理飞溅到一个立方体的表面上(megenta区域只是背景的颜色)

纹理就是这个(非常小)

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

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

  • 连续采样。正常取样
  • 如果u在[0,1]中,则为绿色,否则为红色。只是为了测试的目的
  • 灰度中的u坐标
  • 在texel的左侧进行采样
  • 在纹理中心取样
  • 问题是在
    3
    4
    之间有一行闪烁的像素。闪烁通过改变相机距离而改变,有时甚至可以使其消失。问题似乎出在处理第四行的着色器代码中

    // 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
    坐标不在纹理的任何边缘附近。

    在纹理提取过程中,代码依赖于未定义的值

    第8.9节纹理函数中的状态(重点):

    某些纹理函数(非“Lod”和非“Grad”版本)可能需要 隐式导数内未定义隐式导数 非均匀控制流和非片段着色器纹理获取

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

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

    现在,根据边缘在2x2像素四边形中的位置,可以得到正确的结果,也可以不得到。对于无法获得正确结果的情况,一种可能的结果可能是GL使用缩小过滤器,该过滤器在您的示例中是
    GL\u最近的

    将两个过滤器设置为
    GL\u 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;
    }
    
    在纹理提取期间,代码依赖于未定义的值

    第8.9节纹理函数中的状态(重点):

    某些纹理函数(非“Lod”和非“Grad”版本)可能需要 隐式导数内未定义隐式导数 非均匀控制流和非片段着色器纹理获取

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

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

    现在,根据边缘在2x2像素四边形中的位置,可以得到正确的结果,也可以不得到。对于无法获得正确结果的情况,一种可能的结果可能是GL使用缩小过滤器,该过滤器在您的示例中是
    GL\u最近的

    将两个过滤器设置为
    GL\u 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;
    }
    

    那么,纹理对象是如何设置的?不确定设置纹理对象是什么意思。您是指通过
    glTexParameter
    设置的内容吗?如果是这样,您可以在图像的左下角看到它们:线性过滤和钳制到边缘。那么,纹理对象是如何设置的?不确定设置纹理对象是什么意思。您是指通过
    glTexParameter
    设置的内容吗?如果是这样的话,你可以在图像的左下角看到它们:线性滤波和钳制到边缘。非常感谢!正如您所猜测的,打开最小线性过滤修复了闪烁。你的回答也提供了深刻的见解。还有一件事我很好奇。为什么在
    tc.y
    中添加任何数字也可以解决问题?我做了进一步的测试,没有添加常量零,而是添加了一个统一的设置为零(因此编译器无法通过删除该指令来优化代码)。其结果是,它还消除了闪烁!顺便说一句,我使用的是GLSL 330,但它似乎也适用。是的,