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\$
5
  • \$\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\$ Commented Nov 23, 2022 at 16:47
  • \$\begingroup\$ Right. That sounds reasonable, I just am not sure how to go about it, yet. Your idea sounds great too. \$\endgroup\$ Commented Nov 23, 2022 at 16:54
  • \$\begingroup\$ The glow pass contains a black background with any pixels that are glowing, such as the pixels for the reaper's eyes, which are red. This is backed up into a globally-defined texture, at the end of the frame, using glCopyImageSubData. Upon the next frame, both the glow pass data and the last frame's glow pass data are passed into the compositing/post-processing shader, and then add them in the shader. I get one frame of tracers, and that's it. I'm not sure where I'm going wrong, or how to implement your suggestion. I'm still kind of a newb at OpenGL 4. \$\endgroup\$ Commented Nov 23, 2022 at 18:54
  • \$\begingroup\$ I have edited the post to include the new version of the source code. In it, I pass both the glow pass and last frame's glow pass into the shader, where they are added together. I thought that it would work, but it does not. \$\endgroup\$ Commented Nov 23, 2022 at 20:54
  • \$\begingroup\$ I'll edit it again. I am now using a compute shader. It is still not working. \$\endgroup\$ Commented Nov 24, 2022 at 16:58

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.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.