对渲染的FBO的纹理查找偏离了半个像素

时间:2012-01-16 03:49:19

标签: opengl glsl textures shader

我有一个通过FBO渲染到纹理的场景,我从片段着色器中对其进行采样,使用基元绘制区域而不是绘制全屏四边形:我只通过生成片段来节省资源I我需要。

为了测试这个,我发出与纹理渲染完全相同的几何体,这意味着生成的光栅化模式应该完全相同:当我的片段着色器使用变化的坐标查找其纹理时,它应该被赋予它与其给出的其他值完美匹配。

以下是我给片段着色器设置坐标以使用全屏纹理自动纹理几何体的方法:

// Vertex shader
uniform mat4 proj_modelview_mat;
out vec2 f_sceneCoord;
void main(void) {
    gl_Position = proj_modelview_mat * vec4(in_pos,0.0,1.0);
    f_sceneCoord = (gl_Position.xy + vec2(1,1)) * 0.5;
}

我在2D工作,所以我并不关心这里的视角。我只是使用从[-1,1]缩放回[0,1]的剪辑空间位置来设置sceneCoord值。

uniform sampler2D scene;
in vec2 f_sceneCoord;
//in vec4 gl_FragCoord;
in float f_alpha;   
out vec4 out_fragColor;
void main (void) {
    //vec4 color = texelFetch(scene,ivec2(gl_FragCoord.xy - vec2(0.5,0.5)),0);
    vec4 color = texture(scene,f_sceneCoord);
    if (color.a == f_alpha) {
        out_fragColor = vec4(color.rgb,1);
    } else
        out_fragColor = vec4(1,0,0,1);
}

注意如果我的alpha不匹配,我会吐出一个红色碎片。纹理渲染将每个渲染对象的alpha设置为特定索引,因此我知道什么与什么匹配。

抱歉,我没有要显示的图片,但很明显我的像素已被(0.5,0.5)关闭:我的物体周围的左下方有一个薄的,一个像素的红色边框,弹出进出。这看起来很“短暂”。赠品是它只出现在物体的底部和左侧。

注意我有一行注释使用texelFetch:这种方法有效,我不再让我的红色片段显示出来。但是我想用texture和规范化的纹理坐标使这个工作正常,因为我认为更多的硬件会支持它。也许真正的问题是,如果不通过制服发送我的视口分辨率,是否可以做到这一点?必须有办法避免这种情况!

更新:我尝试将纹理访问权移动了半个像素,四分之一像素,百分之一个像素,这一切都变得更糟,并在边缘产生了错误值的实线边框:看起来像我的{ {1}}技巧设置正确的值,但采样只是稍微偏离了一点点。这很奇怪......看到红色碎片?当物体处于运动状态时,它们会轻微地进出。这意味着我设置的alpha值与这些像素不完全匹配。

transient red fragments indicate a texture sampling mis-match

对于我来说,为我的实际应用程序获得alpha-index-check的像素完美精确度并不重要,但这种行为并不是我所期望的。

2 个答案:

答案 0 :(得分:4)

好吧,首先考虑放弃f_sceneCoord变化,只使用gl_FragCoord / screenSize作为纹理坐标(在您的示例中已经有了这个,但-0.5是垃圾),{{1制服(可能预先划分)。这应该几乎完全正常,因为默认情况下screenSize位于像素中心(意为gl_FragCoord),并且在纹素中心(i+0.5)处对纹理进行采样时,OpenGL会返回精确的纹素值。 / p>

由于有限精度等原因,这可能仍然会形成非常非常微小的偏差,形成精确的纹素值(如果有的话)。但话说回来,无论如何,您可能希望使用(i+0.5)/textureSize的过滤模式来实现这种一对一的纹理到屏幕映射。实际上,您现有的GL_NEAREST方法可能已经运行良好,只是f_sceneCoord阻止创建您的文物的那些小的舍入问题。但话说回来,你仍然不需要那个GL_NEAREST

编辑:关于f_sceneCoord的可移植性。我认为,这个功能是用GLSL 1.30(~SM4 / GL3 / DX10-硬件,~GeForce 8)引入的。但是,您使用的新texelFetch语法已经需要此版本(与旧in/out语法相反)。因此,如果您不打算更改这些,假设varying/attribute给定绝对没有问题,也可能比texelFetch略快(这也需要GLSL 1.30,与旧{{1}相反完全绕过过滤。

答案 1 :(得分:1)

如果你在完美的X中工作,Y [0,1]没有很好的舍入误差......但有时候 - 特别是如果使用极坐标,你可以考虑将计算出的坐标与纹理'网格'对齐。 ..

我用:

// align it to the nearest centered texel
curPt -= mod(curPt, (0.5 / vec2(imgW, imgH)));

就像一个魅力,我不再在屏幕边缘得到随机的舍入错误......