• Create Account

## Best way to filter for a bloom effect

Old topic!

Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

11 replies to this topic

### #1ic0de  Members

Posted 11 October 2012 - 05:13 PM

So I have had a bloom effect implemented for some time but I just haven't been able to make it look right. I start my effect by filtering out the really bright parts then I do a two pass Gaussian blur and blend the blurred bright stuff with the original image. I have come to the conclusion that to make it look right I need to tweak how I decide what is bright so far I have two ways neither of which work well. My code is written in GLSL but this really applies to HLSL and cg as well. Anyway the first way goes like this:
if(sample.r > level)
{
sample.r = 1.0;
}
else
{
sample.r = 0.0;
}

if(sample.g > level)
{
sample.g = 1.0;
}
else
{
sample.g = 0.0;
}

if(sample.b > level)
{
sample.b = 1.0;
}
else
{
sample.b = 0.0;
}

The problem with this method is that It will always glow either red, green or blue. For example a bright purple would glow red.

Method 2:

if((0.2126*sample.r) + (0.7152*sample.g) + (0.0722*sample.b) > level)
{
sample.r = 1.0;
sample.g = 1.0;
sample.b = 1.0;
}
else
{
sample.r = 0.0;
sample.g = 0.0;
sample.b = 0.0;
}

This method works by determining the overall brightness (luminance?). But it never seems to glow any color but white.

So I developed two methods but neither seem to work right. Does anyone have any methods that they have used successfully? Or any suggestions on how to improve mine?

Edited by ic0de, 12 October 2012 - 05:59 AM.

you know you program too much when you start ending sentences with semicolons;

### #2luca-deltodesco  Members

Posted 12 October 2012 - 02:56 AM

Why are you multiplying the colour values by 2 in your second approach? That is probably why you're ending up with white glows since after saturation of the values you're likely ending up with white in most cases.

### #3ic0de  Members

Posted 12 October 2012 - 05:59 AM

Why are you multiplying the colour values by 2 in your second approach? That is probably why you're ending up with white glows since after saturation of the values you're likely ending up with white in most cases.

Sorry that's a typo I was just testing something and accidentally posted the wrong shader. I updated it in my post but obviously it will still set everything to white. How do you suggest I brighten it without making white?

you know you program too much when you start ending sentences with semicolons;

### #4bwhiting  Members

Posted 12 October 2012 - 07:52 AM

Don't set them all to 1 for a start.

You could multiply them by a small factor i.e. 1.2 to make them brighter but consider that if you are adding the result to the buffer then you would probably want to de-brighten (great wordage) them first.

I think in the past I have just run a threshold, then blur, then a multiply down, then composite with an add

### #5ic0de  Members

Posted 12 October 2012 - 01:31 PM

I figured it out on my own and I must say It looks beautiful (although the effect seems to be fighting with my ssao). Anyway here is my solution.
if((0.2126*sample.r) + (0.7152*sample.g) + (0.0722*sample.b) > level)
{
float brightenRatio = 1.0 / max(max(sample.r, sample.g), sample.b);
sample.r *= brightenRatio;
sample.g *= brightenRatio;
sample.b *= brightenRatio;
}
else
{
sample.r = 0.0;
sample.g = 0.0;
sample.b = 0.0;
}


The largest component ends up being 1.0 and the smaller components maintain the same ratio hence obtaining the same colour only brighter.

Edited by ic0de, 12 October 2012 - 01:32 PM.

you know you program too much when you start ending sentences with semicolons;

### #6kalle_h  Members

Posted 12 October 2012 - 03:45 PM

(0.2126*sample.r) + (0.7152*sample.g) + (0.0722*sample.b)

Could be.

const vec3 luminance = vec3(0.2126, 0.7152, 0.0722);
float brightness = dot(lumiance * sample.rgb);


Your method lose information. Everything over threshold just goes as bright. You allways can brighten up the blurred bloom texture values when you are compositing image. Then you dont lost information and you get much more variety for bloom.

One easy trick is just multiply the color with itself and using treshold or smoothstep.

### #7ic0de  Members

Posted 12 October 2012 - 04:56 PM

(0.2126*sample.r) + (0.7152*sample.g) + (0.0722*sample.b)

Could be.

const vec3 luminance = vec3(0.2126, 0.7152, 0.0722);
float brightness = dot(lumiance * sample.rgb);


Your method lose information. Everything over threshold just goes as bright. You allways can brighten up the blurred bloom texture values when you are compositing image. Then you dont lost information and you get much more variety for bloom.

One easy trick is just multiply the color with itself and using treshold or smoothstep.

Sorry I don't quite get what you're saying. Do you mean I use something like:
const vec3 luminance = vec3(0.2126, 0.7152, 0.0722);
float brightness = dot(lumiance * sample.rgb);

if(brightness > level)
{
// do the rest


Edited by ic0de, 12 October 2012 - 04:58 PM.

you know you program too much when you start ending sentences with semicolons;

### #8MrOMGWTF  Members

Posted 12 October 2012 - 11:48 PM


if((0.2126*sample.r) + (0.7152*sample.g) + (0.0722*sample.b) > level)

{

// just do nothing...

}

else

{

}



### #9MJP  Moderators

Posted 13 October 2012 - 03:03 PM

The "best way" in my opinion is not to use a threshold at all. A step function is ugly and will cause aliasing. A more natural approach is to just use a lower exposure for your bloom pass, which will naturally subdue to darker areas while allowing brighter areas to remain visible in the end result.

### #10Hodgman  Moderators

Posted 13 October 2012 - 08:36 PM

In the threshold pass on my last project, we used an offset an a multiplier, e.g.
output = max(0, input-threshold)*scale;
Originally I was only had the scale variable, but the artists wanted a bit of extra control as to completely stopping the effect.

As with MJP's suggestion above, this ensures that there's no sudden point where your bloom texture jumps from zero up to some bright value.

BTW you should try an adopt a much more branchless style of programming when writing shaders compared to CPU code.
e.g. your different versions can have their if statements removed by using the step function along with multiplication:
//1
sample.rgb = step(vec3(level), sample.rgb);
//2
sample.rgb = vec3(step(level, dot(sample.rgb, vec3(0.2126, 0.7152, 0.0722))));
//3
float brightenRatio = 1.0 / max(max(sample.r, sample.g), sample.b+0.00000001);
brightenRatio *= step( level, dot(sample.rgb, vec3(0.2126, 0.7152, 0.0722)) );
sample.rgb *= brightenRatio;

Edited by Hodgman, 13 October 2012 - 08:38 PM.

### #11pachesantiago  Members

Posted 15 October 2012 - 12:06 PM

hy. im using this to in my bloom shader. is simple and it works really well

float4 color = tex2D( srcTex, IN.uv );
color = (-color + (pow(tex2D( srcTex, IN.uv ),Power) * Scale) )/Bias;
return color;

here's a screenshot using scale = 1.83, power = 4 and bias = 0.27

PS: this is HLSL, but i think it should be really similar

### #12pachesantiago  Members

Posted 15 October 2012 - 12:09 PM

hy. im using this to in my bloom shader. is simple and it works really well


float4 color = tex2D( srcTex, IN.uv );
color = (-color + (pow(tex2D( srcTex, IN.uv ),Power) * Scale) )/Bias;
return color;

here's a screenshot using scale = 1.83, power = 4 and bias = 0.27

PS: this is HLSL, but i think it should be really similar

Sorry, didnt mention that the grayscale is another shader, is not part of the "bright pass"
Using colors:

Old topic!

Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.