4
$\begingroup$

I've written an implementation of the sphere tracing algorithm in OpenGL 4+. As an experiment/toy project, I'm re-implementing it using the OpenGL 4.3 compute shader, but I'm having trouble with the whole local/global invocation ID thing. The basic idea is to use the compute shader to calculate the image and output it in a texture, then use a trivial program to copy it onto the framebuffer.

This is the compute shader I'm using:

#version 430 core

layout (binding = 0, rgba32f) writeonly uniform image2D output_image;
layout (local_size_x = 16, local_size_y = 16, local_size_z = 1) in;

void main()
{
    ivec2 coord = ivec2(gl_GlobalInvocationID.xy);
    imageStore(output_image, coord, vec4(0.0, 0.0, 1.0, 1.0));
}

This is how I initialize the texture:

GLuint offscreen_texture;
glGenTextures(1, &offscreen_texture);

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, offscreen_texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, WINDOW_WIDTH, WINDOW_HEIGHT, 0, GL_RGBA, GL_FLOAT, nullptr);
glBindImageTexture(0, offscreen_texture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F);

And these are the trivial vertex shader I'm using:

#version 430 core

void main()
{
    const vec4 verts[4] = vec4[4](vec4(-1.0, -1.0, 0.5, 1.0),
                                  vec4( 1.0, -1.0, 0.5, 1.0),
                                  vec4(-1.0,  1.0, 0.5, 1.0),
                                  vec4( 1.0,  1.0, 0.5, 1.0));

    gl_Position = verts[gl_VertexID];
}

And fragment:

#version 430 core

layout (location = 0) out vec4 color_out;
layout(binding = 0) uniform sampler2D source_image;

void main()
{
    color_out = texture(source_image, gl_FragCoord.xy);
}

And this is the render code:

compute_program.use();
glDispatchCompute(WINDOW_WIDTH / 16, WINDOW_HEIGHT / 16, 1);
glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);

copy_program.use();
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

Up to this point everything works correctly and I see my screen completely blue instead of the usual clear color.

Things start to break down when I try to use the Invocation ID to generate actual data (like the rays from the camera). I tried to switch to a compute shader like:

#version 430 core

layout (binding = 0, rgba32f) writeonly uniform image2D output_image;
layout (local_size_x = 16, local_size_y = 16, local_size_z = 1) in;

void main()
{
    ivec2 coord = ivec2(gl_GlobalInvocationID.xy);
    imageStore(output_image, coord, vec4(0.0, 0.0, coord.x / 1280.0, 1.0));
}

which uses the global ID to generate the blue tint of the pixel. As I understand from the OpenGL Suberbible book and the OpenGL wiki, I should be able to use the global ID as screen space coordinates (it's pretty easy to do the math using local IDs and work groups IDs and confirm that), much like gl_FragCoord, and this is confirmed by the previous trivial compute shader which paint every pixel.

I would expect a sort of horizontal gradient going from black to blue as an output of this compute shader, but instead everything turns black. I've tried several combination of "painting" based on the local/global IDs of the threads, but I haven't got any luck no matter what.

Did I misunderstand the way the whole threads ID work? What is the correct way to use them/map them to screen space coordinates like gl_FragCoord?

EDIT: Just to add, I've tested this with both my integrated Intel HD 5100 and my discrete Nvidia 765M GPUs and the result is the same, so there is clearly something wrong on my side.

$\endgroup$
5
$\begingroup$

The problem is actually in your fragment shader:

color_out = texture(source_image, gl_FragCoord.xy);

The texture() function accepts normalized coordinates which range from 0.0 to 1.0. The gl_FragCoord built in contains window coordinates which range from (0.0, 0.0) to (window width, window height).

To fix this, change the fragment shader to this:

color_out = texture(source_image, gl_FragCoord.xy / vec2(1280.0, 720.0));

That is assuming your window is 1280x720, change as necessary.

$\endgroup$
  • $\begingroup$ Wow, i want to die now :( I even said i wanted gl_GlobalInvocationID to behave like gl_FragCoord, which uses uses window coordinates. This was one of the most stupid error ever. You saved my day and my sanity. $\endgroup$ – Matteo Bertello Oct 20 '15 at 21:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.