Search code examples
openglglslblurtexture-mappingbloom

OpenGL GLSL bloom effect bleeds on edges


I have a framebuffer called "FBScene" that renders to a texture TexScene. I have a framebuffer called "FBBloom" that renders to a texture TexBloom. I have a framebuffer called "FBBloomTemp" that renders to a texture TexBloomTemp.

First I render all my blooming / glowing objects to FBBloom and thus into TexBloom. Then I play ping pong with FBBloom and FBBloomTemp, alternatingly blurring horizontally / vertically to get a nice bloom texture.

Then I pass the final "TexBloom" texture and the TexScene to a screen shader that draws a screen filling quad with both textures:

gl_FragColor = texture(TexBloom, uv) + texture(TexScene, uv);

The problem is: While blurring the images, the bloom effect bleeds into the opposite edges of the screen if the glowing object is too close to the screen border.

This is my blur shader:

vec4 color = vec4(0.0);
vec2 off1 = vec2(1.3333333333333333) * direction;
vec2 off1DivideByResolution =  off1 / resolution;
vec2 uvPlusOff1  = uv + off1DivideByResolution;
vec2 uvMinusOff1 = uv - off1DivideByResolution;


color += texture(image, uv) * 0.29411764705882354;
color += texture(image, uvPlusOff1) * 0.35294117647058826;
color += texture(image, uvMinusOff1) * 0.35294117647058826;
gl_FragColor = color;

I think I need to prevent uvPlusOff1 and uvMinusOff1 from beeing outside of the -1 and +1 uv range. But I don't know how to do that.

I tried to clamp the uv values at the gap in the code above with:

float px = clamp(uvPlusOff1.x, -1, 1);
float py = clamp(uvPlusOff1.y, -1, 1);
float mx = clamp(uvMinusOff1.x, -1, 1);
float my = clamp(uvMinusOff1.y, -1, 1);

uvPlusOff1 = vec2(px, py);
uvMinusOff1 = vec2(mx, my);

But it did not work as expected. Any help is highly appreciated.


Solution

  • Bleeding to the other side of the screen usually happens when the wrap-mode is set to GL_REPEAT. Set it to GL_CLAMP_TO_EDGE and it shouldn't happen anymore.

    Edit - To explain a little bit more why this happens in your case: A texture coordinate of [1,1] means the bottom-right corner of the bottom-right texel. When linear filtering is enabled, this location will read four pixels around that corner. In case of repeating textures, three of them are on other sides of the screen. If you want to prevent the problem manually, you have to clamp to the range [0 + 1/texture_size, 1 - 1/texture_size].

    I'm also not sure why you even clamp to [-1, 1], because texture coordinates usually range from [0, 1]. Negative values will be outside of the texture and are handled by the wrap mode.