采样全屏纹理的最佳方式

时间:2014-04-16 15:04:53

标签: opengl glsl

在片段着色器中对全屏纹理进行采样的最佳方法是什么,例如延迟渲染器中的g-buffer,或后处理着色器中的场景纹理?

目前我使用以下两种方式:

  • 将屏幕尺寸作为制服传递给着色器,并从gl_FragCoord计算(u,v):

    vec2 texCoord = gl_FragCoord.xy / vScreenSize;
    vec3 c = texture( tex, texCoord ).rgb;
    

    似乎不理想,因为需要分割并为着色器提供屏幕尺寸很麻烦。

  • gl_FragCoord.xy转换为ivec并使用texelFetch

    vec3 c = texelFetch( tex, ivec2(gl_FragCoord.xy), 0 ).rgb;
    

    也不理想,因为需要从float转换为int

那么还有更好的方法吗?我真的只想在我的像素着色器绘制的确切点处对缓冲区进行采样。


//编辑:


好的,根据来自顶点着色器的插值纹理坐标的建议,我设法找出以下代码:

顶点着色器:

#version 150

uniform mat4 im_ModelViewProjectionMatrix;

in vec3 iv_Vertex;
noperspective out vec2 vVertCoord;

void main( void )
{
    gl_Position = im_ModelViewProjectionMatrix * vec4(iv_Vertex, 1.0);
    vVertCoord = (gl_Position.xy / gl_Position.w) * (0.5) + vec2(0.5);
}

我基本上使用透视分割从剪辑空间位置计算归一化设备坐标(NDC),然后将NDC(范围从[-1,1])映射到区间[0,1]。这适用于全屏四边形(即使没有透视分割,因为坐标非常简单)。我需要在延迟渲染器中绘制为光几何的任意几何体有一些问题。在顶点着色器中,我输出vVertCoord作为red = x和green = y的颜色:

#version 150

noperspective in vec2 vVertCoord;
out vec4 colorOut;

void main( void )
{
    colorOut = vec4(vVertCoord.x, vVertCoord.y, 0, 1);
}

这是当我在一个点光球内,一切看起来都很好(黑线是故意渲染)时的结果:

All fine

但是,如果我靠近光几何,这就是结果:

Not ok

左上角的红色补丁在那里做什么?您不希望在禁用调试颜色的情况下以真实颜色查看结果,因为它看起来像是一个lsd-trip,当您移动相机时一切都会变形。这种精确度是否相关?请注意,当我在像素着色器中使用gl_FragCoord时,一切都很好。

1 个答案:

答案 0 :(得分:2)

如果您只是从顶点着色器传入插值顶点坐标,则不必进行任何特殊数学运算。

例如,如果您正在绘制一个覆盖屏幕的简单单位正方形,那么您可以然后接收全屏纹理,您可以这样做:

vertex shader pseudocode:
layout(position = 0) in vec3 in_vertex;
out vec3 out_vertex;
void main()
{
    //Do your matrix multiplications to your in_vertex to get its final position...
    out_vertex = in_vertex;
}

然后,您的顶点着色器将正确插入in_vertex,使其位于范围x:0 ... 1,y:0 ... 1(只要您正在绘制单位正方形)并将其传递给你的片段着色器。然后,您的片段着色器将使用它:

fragment shader pseudocode:
in vec3 out_vertex;
uniform sampler2D tex;
void main()
{
    gl_fragcolor = texture(tex,vec2(out_vertex.x,out_vertex.y));
}

只要你注意out_vertex只会在0 ... 1的范围内,就不需要其他数学运算。为了扩展这个例子,想象一下我们的方块:

(0,1)+-----------+(1,1) | | | | | | | | | | (0,0)+-----------+(0,1)

我们想在确切的中心对这一点进行抽样:

(0,1)+-----------+(1,1) | | | | | * | | | | | (0,0)+-----------+(0,1)

我们的顶点着色器将自动从其他4个位置插入该位置,并将以下vec3传递给片段着色器:

out_vertex = vec3(0.5,0.5,0);

然后可以使用它来成功地对纹理进行采样