0
\$\begingroup\$

We have implemented a glow map into our renderer. It basically uses a blur filter on the glow map pass. But, I cannot figure out how to do tracers in OpenGL. Someone suggested using a couple of textures that are saved between frames, ping-ponging them so to speak. However, I am stuck at the part where I need to implement it. My C++ code is:

glowmap_copier.use_program();

// create output temp texture, with texstorage
GLuint temp_tex;

glGenTextures(1, &temp_tex);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, temp_tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, win_x, win_y, 0, GL_RGBA, GL_FLOAT, NULL);
glBindImageTexture(0, temp_tex, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F);


glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, temp_tex);
glUniform1i(glGetUniformLocation(glowmap_copier.get_program(), "output_image"), 0);

// activate glow and last frame glow input textures
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, glowmap_tex);
glUniform1i(glGetUniformLocation(glowmap_copier.get_program(), "inputa_image"), 1);

glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, last_frame_glowmap_tex);
glUniform1i(glGetUniformLocation(glowmap_copier.get_program(), "inputb_image"), 2);

// call compute shader
glDispatchCompute((GLuint)win_x, (GLuint)win_y, 1);

// Wait for compute shader to finish
glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);

// copy from temp to last frame using glCopyImageSubData
glCopyImageSubData(temp_tex, GL_TEXTURE_2D, 0, 0, 0, 0,
    last_frame_glowmap_tex, GL_TEXTURE_2D, 0, 0, 0, 0,
    win_x, win_y, 1);

glDeleteTextures(1, &temp_tex);

and:

// OpenGL 4.3 introduces compute shaders
#version 430

layout(local_size_x = 1, local_size_y = 1) in;

layout(binding = 0, rgba32f) writeonly uniform image2D output_image;
layout(binding = 1, rgba32f) readonly uniform image2D inputa_image;
layout(binding = 2, rgba32f) readonly uniform image2D inputb_image;


void main()
{
    // Get global coordinates
    const ivec2 pixel_coords = ivec2(gl_GlobalInvocationID.xy);
    const vec4 output_pixel = imageLoad(inputa_image, pixel_coords) + imageLoad(inputb_image, pixel_coords);

    imageStore(output_image, pixel_coords, output_pixel);
}

An image of the glow effect is:

enter image description here

What I would like is to be able to accumulate the effect, and have it fade over time. Tracers, basically. Any ideas on how to do something like this in OpenGL 4? P.S. it seems that this problem is analogous to motion blur.

An example of the glow map is below. The glow map contains non-black data for the reaper's small eyes, as well as the 4 lights, and a small border around the game board. There is also an orange glowing thing, which represents the mouse location.

enter image description here

\$\endgroup\$
9
  • 1
    \$\begingroup\$ What you really need to know is: "How do I draw part of the previous frame in the current frame?". Right? If you solved that you would be able to solve your motion blur. \$\endgroup\$
    – user253751
    Nov 23, 2022 at 14:15
  • \$\begingroup\$ Well, that's the thing: I back up the glow pass at the end of every frame, and then I pass that backup into the shader on the next frame, and I try to accumulate them in the shader by adding them together. I get one frame of tracers, and that's it. Someone told me to do a ping-pong thing with two backups instead of one, but I tried that (not sure I implemented it correctly). \$\endgroup\$ Nov 23, 2022 at 16:47
  • 1
    \$\begingroup\$ The ping-pong thing is just a trick to skip the backup to make it run a bit faster. It's not essential. To make it persist for multiple frames, you probably want to render the backup into the glow pass so it gets backed up again and again and again. Render it at 98% brightness (for example) so it fades away after some time. Are you doing it? \$\endgroup\$
    – user253751
    Nov 23, 2022 at 16:50
  • 1
    \$\begingroup\$ What is the backup, currently? And what is the glow pass? \$\endgroup\$
    – user253751
    Nov 23, 2022 at 17:15
  • 1
    \$\begingroup\$ It looks to me like this is the shader that renders (something? doesn't really matter) onto the screen - not into the glowmap texture. So you are taking the last two glowmap textures and rendering them onto the screen. Of course this only takes the last two frames because that's what you told it. What I think you need to do is render the last frame's glowmap into this frame's glowmap so then it also gets rendered into the next frame's glowmap and so on. To make it fade away, you make it fade slightly every time you render it. \$\endgroup\$
    – user253751
    Nov 24, 2022 at 11:53

1 Answer 1

0
\$\begingroup\$

@user253751

We used a compute shader to combine the glow map and last frame's glow map. Works good.

glUseProgram(glowmap_copier.get_program());


// create output temp texture
GLuint temp_tex;

glGenTextures(1, &temp_tex);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, temp_tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, win_x, win_y, 0, GL_RGBA, GL_FLOAT, NULL);
glBindImageTexture(0, temp_tex, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F);
glUniform1i(glGetUniformLocation(glowmap_copier.get_program(), "output_image"), 0);


// activate glow and last frame glow input textures
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, glowmap_tex);
glBindImageTexture(1, glowmap_tex, 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA32F);
glUniform1i(glGetUniformLocation(glowmap_copier.get_program(), "inputa_image"), 1);

glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, last_frame_glowmap_tex);
glBindImageTexture(2, last_frame_glowmap_tex, 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA32F);
glUniform1i(glGetUniformLocation(glowmap_copier.get_program(), "inputb_image"), 2);

// call compute shader
glDispatchCompute(win_x, win_y, 1);

// Wait for compute shader to finish
glMemoryBarrier(GL_ALL_BARRIER_BITS);

// debug -- shows that it works
vector<float> output_pixels(win_x* win_y * 4);
glActiveTexture(GL_TEXTURE0);
glBindImageTexture(0, temp_tex, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F);


glCopyImageSubData(temp_tex, GL_TEXTURE_2D, 0, 0, 0, 0,
    last_frame_glowmap_tex, GL_TEXTURE_2D, 0, 0, 0, 0,
    win_x, win_y, 1);

// debug -- shows that it works
glActiveTexture(GL_TEXTURE0);
glBindImageTexture(0, last_frame_glowmap_tex, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F);




glDeleteTextures(1, &temp_tex);

and:

// OpenGL 4.3 introduces compute shaders
#version 430

layout(local_size_x = 1, local_size_y = 1) in;

layout(binding = 0, rgba32f) writeonly uniform image2D output_image;
layout(binding = 1, rgba32f) readonly uniform image2D inputa_image;
layout(binding = 2, rgba32f) readonly uniform image2D inputb_image;


void main()
{
    // Get global coordinates
    const ivec2 pixel_coords = ivec2(gl_GlobalInvocationID.xy);
    const vec3 output_pixel = imageLoad(inputa_image, pixel_coords).rgb + 0.5*imageLoad(inputb_image, pixel_coords).rgb;

    imageStore(output_image, pixel_coords, vec4(output_pixel, 1.0));
}

The result: enter image description here

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .