Advertisement

Bloom shader in a 2D game

Started by July 23, 2018 11:13 AM
5 comments, last by fgnm 6 years, 6 months ago

Hello, I'm trying to make a bloom effect in my 2D game made with LibGDX. I've a problem with the shader side, in short the glow effect should be go off the bounds of the texture, if I have a texture 40x40 the shader should cover 60x60 for example. This image explain better the problem I have: dtdd15B.png, as you can see the bloom effect is cut when the texture ends.

I suppose that I should modify the default vertex shader to get what I need but I'm not very familiar with GLSL programmig so I ask if someone could help me.

Vertex:


#ifdef GL_ES
    precision highp float;
    precision highp int;
#endif

attribute vec4 a_position;
attribute vec4 a_color;
attribute vec2 a_texCoord0;

uniform mat4 u_projTrans;

varying vec4 v_color;
varying vec2 v_texCoords;

void main() {
    v_color = a_color;
    v_texCoords = a_texCoord0;
    gl_Position = u_projTrans * a_position;
}

Fragment


#ifdef GL_ES
    precision highp float;
    precision highp int;
#endif

varying vec4 v_color;
varying vec2 v_texCoords;

uniform sampler2D u_texture;
uniform mat4 u_projTrans;

uniform float u_blurSize;
uniform float u_intensity;

void main() {
    vec4 sum = vec4(0);

    // blur in y (vertical)
    // take nine samples, with the distance blurSize between them
    sum += texture2D(u_texture, vec2(v_texCoords.x - 4.0*u_blurSize, v_texCoords.y)) * 0.05;
    sum += texture2D(u_texture, vec2(v_texCoords.x - 3.0*u_blurSize, v_texCoords.y)) * 0.09;
    sum += texture2D(u_texture, vec2(v_texCoords.x - 2.0*u_blurSize, v_texCoords.y)) * 0.12;
    sum += texture2D(u_texture, vec2(v_texCoords.x - u_blurSize, v_texCoords.y)) * 0.15;
    sum += texture2D(u_texture, vec2(v_texCoords.x, v_texCoords.y)) * 0.16;
    sum += texture2D(u_texture, vec2(v_texCoords.x + u_blurSize, v_texCoords.y)) * 0.15;
    sum += texture2D(u_texture, vec2(v_texCoords.x + 2.0*u_blurSize, v_texCoords.y)) * 0.12;
    sum += texture2D(u_texture, vec2(v_texCoords.x + 3.0*u_blurSize, v_texCoords.y)) * 0.09;
    sum += texture2D(u_texture, vec2(v_texCoords.x + 4.0*u_blurSize, v_texCoords.y)) * 0.05;

    // blur in y (vertical)
    // take nine samples, with the distance blurSize between them
    sum += texture2D(u_texture, vec2(v_texCoords.x, v_texCoords.y - 4.0*u_blurSize)) * 0.05;
    sum += texture2D(u_texture, vec2(v_texCoords.x, v_texCoords.y - 3.0*u_blurSize)) * 0.09;
    sum += texture2D(u_texture, vec2(v_texCoords.x, v_texCoords.y - 2.0*u_blurSize)) * 0.12;
    sum += texture2D(u_texture, vec2(v_texCoords.x, v_texCoords.y - u_blurSize)) * 0.15;
    sum += texture2D(u_texture, vec2(v_texCoords.x, v_texCoords.y)) * 0.16;
    sum += texture2D(u_texture, vec2(v_texCoords.x, v_texCoords.y + u_blurSize)) * 0.15;
    sum += texture2D(u_texture, vec2(v_texCoords.x, v_texCoords.y + 2.0*u_blurSize)) * 0.12;
    sum += texture2D(u_texture, vec2(v_texCoords.x, v_texCoords.y + 3.0*u_blurSize)) * 0.09;
    sum += texture2D(u_texture, vec2(v_texCoords.x, v_texCoords.y + 4.0*u_blurSize)) * 0.05;

    gl_FragColor = sum * u_intensity + texture2D(u_texture, v_texCoords);
}

 

Bloom shaders are usually done in screenspace as a post-processing shader (on all the pixels of the screen).

If you really need to do it on a per-material basis (I can't think of a reason why though), you could add extra empty space around the banana to make room for the blooming when you sample the 2d texture. I wouldn't recommend this approach, since you need to adjust all your assets this way if you need to bloom everything.

Advertisement
4 minutes ago, btower said:

Bloom shaders are usually done in screenspace as a post-processing shader (on all the pixels of the screen).

If you really need to do it on a per-material basis (I can't think of a reason why though), you could add extra empty space around the banana to make room for the blooming when you sample the 2d texture. I wouldn't recommend this approach, since you need to adjust all your assets this way if you need to bloom everything.

Yes, I need this effect on many other objects but not on the whole screen, and I would't really change all my assets with extra padding.. So which kind of approach you suggest to have a glow/bloom effect just on some actors on the screen?

Quote

Yes, I need this effect on many other objects but not on the whole screen, and I would't really change all my assets with extra padding.. So which kind of approach you suggest to have a glow/bloom effect just on some actors on the screen?

You could render glowing objects to a separate render target, apply bloom on it then merge it with the main render target.

Bloom as a fragment shader will only work for fragments that are actually rasterized.  If the mesh being rendered is cut off right around the sprite then none of those pixels are rasterized so they never make it to the fragment shader.  It's hard to tell what's going on in your screenshot, but it looks like that's part of it.

One thing I've done is just apply bloom in the GIMP and use a separate sprite.  If I only need bloom on a few things it's often easier to have a glowing variant of that sprite than try to have a shader do the work.

Edit: Also, 18 dependent texture samples per fragment might be a bit expensive.

1 minute ago, gaxio said:

Bloom as a fragment shader will only work for fragments that are actually rasterized.  If the mesh being rendered is cut off right around the sprite then none of those pixels are rasterized so they never make it to the fragment shader.  It's hard to tell what's going on in your screenshot, but it looks like that's part of it.

One thing I've done is just apply bloom in the GIMP and use a separate sprite.  If I only need bloom on a few things it's often easier to have a glowing variant of that sprite than try to have a shader do the work.

Edit: Also, 18 dependent texture samples per fragment might be a bit expensive.

I understand, glowing variant sprite seems to be the better solution under many points of view. I liked the idea of being able to control brightness and other parameters at run-time with a shader, but you are making me think that maybe it's too much for the kind of the game I'm making..

This topic is closed to new replies.

Advertisement