Advertisement Jump to content
Sign in to follow this  
Kdeon

Bloom not smooth

This topic is 1739 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hey guys,

 

Is there a way to make a smooth bloom ?

The more the radius is higher (X or Y), the less it will be smooth, it leave trails (looks like interlaced) as seen on the image (Y radius=13.37) :

 

2tdx.png

 

The blur shader looks like this (from qeffects-gl) :

static const char g_szVertexShader_BloomBlur[] =
"uniform vec4 Local0;\n"
"void main(void)\n"
"{\n"
"gl_TexCoord[0] = gl_MultiTexCoord0 + Local0;\n"
"gl_TexCoord[1] = gl_MultiTexCoord0 + Local0 * 2.0;\n"
"gl_TexCoord[2] = gl_MultiTexCoord0 - Local0;\n"
"gl_TexCoord[3] = gl_MultiTexCoord0 - Local0 * 2.0;\n"
"gl_Position = ftransform();\n"
"}\n";

static const char g_szFragmentShader_BloomBlur[] =
"#extension GL_ARB_texture_rectangle : enable\n"
"uniform sampler2DRect Texture0;\n"
"void main(void)\n"
"{\n"
"vec3 col1 = texture2DRect(Texture0, gl_TexCoord[0].xy).rgb;\n"
"vec3 col2 = texture2DRect(Texture0, gl_TexCoord[1].xy).rgb;\n"
"vec3 col3 = texture2DRect(Texture0, gl_TexCoord[2].xy).rgb;\n"
"vec3 col4 = texture2DRect(Texture0, gl_TexCoord[3].xy).rgb;\n"
"gl_FragColor.rgb = (col1 + col2 + col3 + col4) / 4.0;\n"
"gl_FragColor.a    = 1.0;\n"
"}\n";

Any ideas ?

 

Share this post


Link to post
Share on other sites
Advertisement

You don't have enough samples for the blur size you're using. Either add more samples to fill in the gaps, or lower the step size.

 

Tip: typical bloom isn't computed in a single pass, as it's too expensive to get a wide radius with decent performance and quality. Instead, you should perform a blur on a couple of downscaled images, starting with the highest resolution one and using that result in the next (lower resolution) pass as the source texture. Then you composite the results from every pass at the end and apply that to the image as bloom.

 

Something like:

 

  • Perform bloom threshold if needed (which you might be doing already).
  • Blur to the first texture (1/2 or 1/4 resolution).
  • Blur to the second texture, using the previous result as input (1/8 resolution).
  • Continue for the # of passes you want (this depends on the radius you want to achieve). Each pass is half the resolution of the last.
  • Take all the textures and add them together (if you want more accurate results, energy conservation can be applied).

Share this post


Link to post
Share on other sites

Well, I added more samples, the quality is a bit better.

The shader now look like this :

static const char g_szVertexShader_BloomBlur[] =
"#extension GL_ARB_texture_rectangle : enable\n"
"precision mediump float;\n"
"uniform vec4 Local0;\n"
"varying vec4 texCoord[16];\n"
"void main(void)\n"
"{\n"
"texCoord[0] = gl_MultiTexCoord0 + Local0;\n"
"texCoord[1] = gl_MultiTexCoord0 + Local0 * 1.250;\n"
"texCoord[2] = gl_MultiTexCoord0 + Local0 * 1.375;\n"
"texCoord[3] = gl_MultiTexCoord0 + Local0 * 1.500;\n"
"texCoord[4] = gl_MultiTexCoord0 + Local0 * 1.625;\n"
"texCoord[5] = gl_MultiTexCoord0 + Local0 * 1.750;\n"
"texCoord[6] = gl_MultiTexCoord0 + Local0 * 1.875;\n"
"texCoord[7] = gl_MultiTexCoord0 + Local0 * 2.000;\n"
"texCoord[8] = gl_MultiTexCoord0 - Local0;\n"
"texCoord[9] = gl_MultiTexCoord0 - Local0 * 1.250;\n"
"texCoord[10] = gl_MultiTexCoord0 - Local0 * 1.375;\n"
"texCoord[11] = gl_MultiTexCoord0 - Local0 * 1.500;\n"
"texCoord[12] = gl_MultiTexCoord0 - Local0 * 1.625;\n"
"texCoord[13] = gl_MultiTexCoord0 - Local0 * 1.750;\n"
"texCoord[14] = gl_MultiTexCoord0 - Local0 * 1.875;\n"
"texCoord[15] = gl_MultiTexCoord0 - Local0 * 2.000;\n"
"gl_Position = ftransform();\n"
"}\n";

static const char g_szFragmentShader_BloomBlur[] =
"#extension GL_ARB_texture_rectangle : enable\n"
"precision mediump float;\n"
"uniform sampler2DRect Texture0;\n"
"varying vec4 texCoord[16];\n"
"void main(void)\n"
"{\n"
"vec3 col1 = texture2DRect(Texture0, texCoord[0].xy).rgb;\n"
"vec3 col2 = texture2DRect(Texture0, texCoord[1].xy).rgb;\n"
"vec3 col3 = texture2DRect(Texture0, texCoord[2].xy).rgb;\n"
"vec3 col4 = texture2DRect(Texture0, texCoord[3].xy).rgb;\n"
"vec3 col5 = texture2DRect(Texture0, texCoord[4].xy).rgb;\n"
"vec3 col6 = texture2DRect(Texture0, texCoord[5].xy).rgb;\n"
"vec3 col7 = texture2DRect(Texture0, texCoord[6].xy).rgb;\n"
"vec3 col8 = texture2DRect(Texture0, texCoord[7].xy).rgb;\n"
"vec3 col9 = texture2DRect(Texture0, texCoord[8].xy).rgb;\n"
"vec3 col10 = texture2DRect(Texture0, texCoord[9].xy).rgb;\n"
"vec3 col11 = texture2DRect(Texture0, texCoord[10].xy).rgb;\n"
"vec3 col12 = texture2DRect(Texture0, texCoord[11].xy).rgb;\n"
"vec3 col13 = texture2DRect(Texture0, texCoord[12].xy).rgb;\n"
"vec3 col14 = texture2DRect(Texture0, texCoord[13].xy).rgb;\n"
"vec3 col15 = texture2DRect(Texture0, texCoord[14].xy).rgb;\n"
"vec3 col16 = texture2DRect(Texture0, texCoord[15].xy).rgb;\n"
"gl_FragColor.rgb = gl_FragColor.rgb / 16.0;"
"gl_FragColor.rgb = (col1 + col2 + col3 + col4 + col5 + col6 + col7 + col8 + col9 + col10 + col11 + col12 + col13 + col14 + col15 + col16) / 16.0;\n"
"gl_FragColor.a    = 1.0;\n"
"}\n";

The only thing is that I can't get past 16 arrays.

 

Your steps are similar to the one I have :

 

  • Make the screen darker
  • Blur the darkened texture to texture (setting a radius)
  • Render full screen (1/2 resolution)
  • Repeat # of times
  • Combine normal and blurred scenes (using glActiveTextureARB)
  • Render full screen

 

I'm not sure about enhancing the code. Do you have some examples ?

It's how it looks like from (rough) code :

    int screenWidth = m_3DViewport[2];
    int screenHeight = m_3DViewport[3];
    int blurTexWidth = m_3DViewport[2]>>1;
    int blurTexHeight = m_3DViewport[3]>>1;
 
DarkenShader->Bind();
DarkenShader->SetParameter4f( 0, m_varBloomDarkenPower, 0, 0, 0 );
RenderScaledFSQ( blurTexWidth, blurTexHeight, screenWidth, screenHeight );
 
blurshader->Bind();
 
for( i=0;i < m_varBloomNumSteps; i++ )
{
      blurShader->param4f..( 0, radius0, ... );
      renderFSQ( blurTexWidth, blurTexHeight );
      copysubimage2D( RECTANGLE_ARB, ..., WindowSize[y] - blurTexHeight, blurTexWidth, blurTexHeight );
 
      blurShader->param4f..( 0, radius1, ... );
      renderFSQ( blurTexWidth, blurTexHeight );
      copysubimage2D( RECTANGLE_ARB, ..., WindowSize[y] - blurTexHeight, blurTexWidth, blurTexHeight );
}
 
combineShader->Bind();
combineShader->param4..( 0, scale, 0, 0, 0 );
bindTex( RECTANGLEARB, screen );
activetexARB( GL_TEXTURE1_ARB );
bindtex( RECTANGLEARB, blurtex);
activetexARB( GL_TEXTURE0_ARB );
RenderFSQ( screenWidth, screenHeight );
 
combineShader->Unbind();

I'm not sure what newest games use to make a perfect high quality performances bloom :S

Edited by Kdeon

Share this post


Link to post
Share on other sites


The only thing is that I can't get past 16 arrays.

Do not transfer all the attributes from the vertex shader to the fragment shader. Do the (indirect) texture access directly in the fragment shader. Something like this:

fragment:
vec3 col = texture2DRect(Texture0, texCoord[0].xy).rgb;
col += texture2DRect(Texture0, texCoord[0].xy + Local0 * <xyz> ).rgb;
...
col += texture2DRect(Texture0, texCoord[0].xy + Local0 * <xyz> ).rgb;
col *= 1.0/16.0;
..

Further on, you should use a gaussian blur, therefor you need the right kernel size and (constant) weights. Take a look here to get the concept behind a gaussian blur filter.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!