Best way to filter for a bloom effect

Started by
10 comments, last by pachesantiago 11 years, 6 months ago
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?
Advertisement
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.

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?
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
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.
(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.

(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

if((0.2126*sample.r) + (0.7152*sample.g) + (0.0722*sample.b) > level)
{
// just do nothing...
}
else
{
discard;
}
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.
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 [font=courier new,courier,monospace]if[/font] statements removed by using the [font=courier new,courier,monospace]step[/font] 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;

This topic is closed to new replies.

Advertisement