🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

OpenGL 4 bloom / glow map

Started by
13 comments, last by taby 1 year, 7 months ago

Just to mention, the alternative for fast blurs using mips is a summed area table (SAT).
I can explain with 1D example of 8 pixels. Say we have brightness value per pixel:

0,0,0,3,2,1,0,0 

Next we do a prefix sum (adding the next value to the former sum):

0,0,0,3,5,6,6,6

Once we have this, we can look up an averaged range of any kernel size. Say we want the average from pixels 3 to 5, expecting an average of (0+3+2) / 3 pixels = 1.66:

0,0,[0,3,2],1,0,0 

We can get this by looking up the start and end points of our range:

0,0,0,3,5,6,6,6
    ^   ^  
range_size = 4-2 (looked up array indices)
range_sum = 5-0 (sums from the prefix sum array at those indices)

average = range_sum / range_size = 5 / 3 = 1.66

This also works with higher dimensions.
The downside is it only supports rectangular kernels, and weighting isn't possible. Mips method is much more flexible and usually preferred.
But good to know, especially because prefix sums can be calculated quickly with parallel algorithms (compute shaders).

Advertisement

I am trying this, but it refuses to accumulate:

   int count = 0;

   vec4 glowmap_blurred_colour = texture( glowmap_tex, ftexcoord) +  texture(last_frame_glowmap_tex, ftexcoord);
   count++;
   
   
    for( float d=0.0; d<pi_times_2; d+= pi_times_2/directions)
    {
		for(float i=1.0/quality; i<=1.0; i+=1.0/quality)
        {
            vec2 texcoords = ftexcoord + vec2(cos(d),sin(d))*radius*i;

            glowmap_blurred_colour += texture( glowmap_tex, texcoords) + texture(last_frame_glowmap_tex, texcoords);
           
            count++;
        }
    }
   

   glowmap_blurred_colour /= count;

taby said:
I am trying this, but it refuses to accumulate:

Meaning, result is the same as with ignoring last_frame_glowmap_tex? If so, likely something is wrong on API side with managing the textures.

But anyway, instead of sampling both textures in inner loop, you should add the two textures together before that.
Then you need to sample only one texture, and later you can extend such texture addition with making mips etc.

Aressera said:

taby said:
implement tracers

I guess you mean to do a temporal blur effect that smooths changes over time, so that lights leave trails in the image? Like this:

This can be implemented by having 2 “history” textures that are persistent across frames. You read from one, and write to the other, then switch on the next frame. On each frame, you want to do a linear combination mix() of the current history texture with the input image. The interpolation factor controls how fast or slow the response time is. This is also known as Exponential Smoothing.

OK, I have two history textures, but I'm not sure if I'm doing this right.

I generate the textures, which are global variables, so that they retain their data between frames:


	// to do: recreate these on window size change
	if (last_frame_glowmap_tex == 0)
	{
		glGenTextures(1, &last_frame_glowmap_tex);
		glBindTexture(GL_TEXTURE_2D, last_frame_glowmap_tex);
		glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA32F, win_x, win_y);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
	}

	if (last_frame_glowmap_tex2 == 0)
	{
		glGenTextures(1, &last_frame_glowmap_tex2);
		glBindTexture(GL_TEXTURE_2D, last_frame_glowmap_tex2);
		glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA32F, win_x, win_y);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
	}

I then pass the history texture into the shader:

	if (x % 2 == 0)
	{
		glActiveTexture(GL_TEXTURE5);
		glBindTexture(GL_TEXTURE_2D, last_frame_glowmap_tex);
		glUniform1i(glGetUniformLocation(tex_reflectance.get_program(), "last_frame_glowmap_tex"), 5);
	}
	else
	{
		glActiveTexture(GL_TEXTURE5);
		glBindTexture(GL_TEXTURE_2D, last_frame_glowmap_tex2);
		glUniform1i(glGetUniformLocation(tex_reflectance.get_program(), "last_frame_glowmap_tex"), 5);
	}

And then, when the passes have been rendered, I make the backup copy of the glow map:


	if (x % 2 == 0)
	{
		// Sort of works, for one frame. very frustrating
		glCopyImageSubData(glowmap_tex, GL_TEXTURE_2D, 0, 0, 0, 0,
			last_frame_glowmap_tex, GL_TEXTURE_2D, 0, 0, 0, 0,
			win_x, win_y, 1);
	}
	else
	{
		glCopyImageSubData(glowmap_tex, GL_TEXTURE_2D, 0, 0, 0, 0,
			last_frame_glowmap_tex2, GL_TEXTURE_2D, 0, 0, 0, 0,
			win_x, win_y, 1);
	}

I just can't seem to figure out what to do next.

The shader tries to accumulate, but it just doesn't work:

   int count = 0;

   vec4 glowmap_blurred_colour = texture( glowmap_tex, ftexcoord) + texture(last_frame_glowmap_tex, ftexcoord);
   count++;
   
   
    for( float d=0.0; d<pi_times_2; d+= pi_times_2/directions)
    {
		for(float i=1.0/quality; i<=1.0; i+=1.0/quality)
        {
            vec2 texcoords = ftexcoord + vec2(cos(d),sin(d))*radius*i;

            glowmap_blurred_colour += texture( glowmap_tex, texcoords) + texture(last_frame_glowmap_tex, texcoords);
           
            count++;
        }
    }
 

   glowmap_blurred_colour /= count;

This topic is closed to new replies.

Advertisement