Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best way to sample a fullscreen texture

Tags:

opengl

glsl

What is the best way to sample fullscreen textures in a fragment shader, so for example the g-buffer in a deferred renderer, or the scene texture within a postprocess shader?

At the moment I use the following two ways:

  • Pass the screen size to the shader as a uniform and calculate (u,v) from gl_FragCoord:

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

    Does not seem to be ideal since a division is required and supplying the shader with the screen size is cumbersome.

  • Convert gl_FragCoord.xy into an ivec and use texelFetch:

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

    Also not ideal because the conversion from float to int is required.

So is there a better way? I really just want to sample a buffer at the exact point where my pixel shader is drawing.


// EDIT:


Ok, with the suggestions of interpolated texture-coordinates that come from the vertex shader I managed to figure out the following code:

Vertex shader:

#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);
}

I basically calculate normalized device coordinates (NDC) from the clip space position with the perspective division and then map the NDCs (that range from [-1,1]) into the interval [0,1]. This works great for fullscreen quads (even without the perspective division because coordinates are so simple). The arbitrary geometry I need to draw as light-geometry in my deferred renderer has some problems though. In the vertex shader I output vVertCoord as a color for red=x and green=y:

#version 150

noperspective in vec2 vVertCoord;
out vec4 colorOut;

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

This is the result when I am inside a point-light-sphere, everything looks fine (the black lines are rendered on purpose):

All fine

However, if I move closer to the light-geometry this is the result:

Not ok

What is that red patch in the top left corner doing there? You don't want to see the results in real-color with the debugging colors disabled because it looks like an lsd-trip, everything warps around when you move the camera. Is this precision related? Note that all is fine when I use gl_FragCoord in the pixel shader instead.

like image 759
Marius Avatar asked Apr 16 '14 15:04

Marius


1 Answers

You don't have to do any special math if you just pass in an interpolated vertex coordinate from your vertex shader.

For example, if you were drawing a simple unit square that covered your screen, you could just and would then recieve the full screen texture, you could just do something like this:

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;
}

Your vertex shader will then properly interpolate the in_vertex to be on the range x:0...1, y:0...1 (as long as you're drawing a unit square) and pass it to your fragment shader. Your fragment shader will then use it like so:

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

No other math is needed, as long as you take care that the out_vertex will only ever be in the range of 0...1. To extend this example a bit, imagine here is our square:

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

And we wanted to sample this point in the exact center:

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

Our vertex shader will automatically interpolate that position from the other 4 positions and pass the following vec3 to the fragment shader:

out_vertex = vec3(0.5,0.5,0);

Which can then be used to sample the texture successfully

like image 111
redsoxfantom Avatar answered Oct 29 '22 16:10

redsoxfantom