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

Ste*_* Lu 5 opengl shader textures glsl

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

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

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

// 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;
}
Run Code Online (Sandbox Code Playgroud)

我在二维工作,所以我不关心这里的视角差异.我只是使用从[-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);
}
Run Code Online (Sandbox Code Playgroud)

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

对不起,我没有图片显示,但它很清楚,我的像素是关闭的(0.5,0.5):我避开我的对象薄,一个像素的红色边框,在他们的底部和左右两侧,弹出进出.这看起来很"短暂".赠品是它只出现在物体的底部和左侧.

请注意我有一条注释掉的行使用texelFetch:此方法有效,我不再显示我的红色碎片.但是我希望能够正确使用texture和标准化纹理坐标,因为我认为更多的硬件将支持它.也许真正的问题是,如果没有通过制服发送我的视口分辨率,是否可以做到这一点?必须有办法避免这种情况!

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

瞬态红色碎片表示纹理采样不匹配

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

Chr*_*ica 4

好吧,首先考虑放弃该f_sceneCoord变化并仅用gl_FragCoord / screenSize作纹理坐标(您的示例中已经有这个,但这-0.5是垃圾),并且screenSize是统一的(可能是预先划分的)。这应该几乎可以精确地工作,因为默认情况下gl_FragCoord位于像素中心(即i+0.5),并且 OpenGL 在纹素中心采样纹理时会返回精确的纹素值 ( (i+0.5)/textureSize)。

由于有限的精度等原因,这仍然可能会导致精确的纹素值(如果有)非常非常轻微的偏差。但话又说回来,无论如何,您可能希望GL_NEAREST对这种一对一的纹理到屏幕映射使用过滤模式。实际上,您现有的f_sceneCoord方法可能已经运作良好,只是那些被阻止的小舍入问题GL_NEAREST造成了您的人工制品。但话又说回来,你仍然不需要那个f_sceneCoord东西。

编辑:关于texelFetch. 我认为该功能是在 GLSL 1.30(~SM4/GL3/DX10 硬件、~GeForce 8)中引入的。但您正在使用的新语法已经需要此版本in/out(与旧语法相反varying/attribute)。因此,如果您不打算更改这些,假设texelFetch给定的绝对没有问题,并且可能会比完全绕过过滤texture(与旧版本相比,还需要 GLSL 1.30 texture2D)稍快一些。