0
\$\begingroup\$

I am trying to implement controllable bloom. By controllable I mean bloom that can be requested even for non-bright pixels by adding the bloom value into a model's texture channel. To do this I need to somehow pass this value (the strength of the bloom for the current pixel) into the bloom post-processor. The most obvious choice would be storing it in the alpha channel, but I use alphablending for every model I draw so for me this is not an option. A quick and dirty solution is to use MRT, render to two textures and then recombine them into one which is a huge waste of memory and speed. Another solution could be to render the scene twice: once for the color and alpha components and second for the bloom components - that is the by-the-book method I find on every internet page. Even when rendering into a smaller RT this is still an overkill.

Another thing I thought about was using YCbCr encoding and then simply increasing Y to order bloom, but I always get a green-ish image after decoding (even if I encode-decode in the very same shader, line after line). Here is the encode-decode operations I did:

inline float3 RGBtoYCbCr(float3 color)
{
    float3 YCbCr;
    YCbCr.r = color.r*0.299f + color.g*0.587f + color.b*0.114f;
    YCbCr.g = 0.5f + (-color.r*0.168f - color.g*0.331f + color.b*0.5f);
    YCbCr.b = 0.5f + (color.r*0.5f - color.g*418 - color.b*0.081f);

    return YCbCr;
}

inline float3 YCbCrtoRGB(float3 color)
{
    float3 RGB;
    RGB.r = color.r+1.402*(color.b-0.5f);
    RGB.g = color.r-0.344*(color.g-0.5f)-0.714*(color.b-0.5f);
    RGB.b = color.r+1.772*(color.g-0.5f);

    return RGB;
}

float4 MainShader(...)
{   
    ...
    output.COLOR.rgb = saturate(output.COLOR.rgb);

    output.COLOR.rgb = RGBtoYCbCr(output.COLOR.rgb);
    output.COLOR.rgb = YCbCrtoRGB(output.COLOR.rgb);
}

So I wanted to ask if anyone knows a way to do it in one pass without MRT and (if possible) by still rendering an HDR image?

\$\endgroup\$
  • \$\begingroup\$ I'm confused - you say at the top you want to be able to request bloom even on non-bright pixels, but then you are talking about HDR rendering and applying bloom to bright pixels? Which is it? \$\endgroup\$ – Nathan Reed Nov 24 '13 at 21:26
  • 1
    \$\begingroup\$ Also, why are you so opposed to MRT? That's the usual way to do this sort of thing, e.g. in deferred shading. If you only need one channel from the second RT, then make it R8 format. MRT is pretty efficient, unless you're on a mobile device. \$\endgroup\$ – Nathan Reed Nov 24 '13 at 21:28
  • \$\begingroup\$ I ment that instead of having a brightness treshhold, I want to specify myself which pixels should end up in the about-to-be-blured texture and how bright they should be there (hense the value). I am curently switching to indexed forward renderer from deferred renderer so I am planning not to use MRT at all. Partially because I want to use MSAA, so no MRT is not an option. Maybe you know a good way to encode two variables into a floating point 16-bit channel? My attemts only resulted in precision loss usually due to the fact that I don't understand how floats work in textures. \$\endgroup\$ – cubrman Nov 25 '13 at 7:02
  • \$\begingroup\$ I guess you are using D3D9 then, since you say you can't use MSAA with MRT? FYI, in D3D10-11 you can combine them. In principle it should be possible to pack two 8-bit values in a 16-bit float, but it sounds pretty difficult, and I didn't find any working implementation with a little googling. With a 16-bit integer texture it would be a lot simpler, but I don't think D3D9 supports that (D3D10-11 do, though). \$\endgroup\$ – Nathan Reed Nov 25 '13 at 8:09
  • \$\begingroup\$ Ok ok I know how good D3D10-11 is, but yes I am stuck on D3D9, why? Because I am a complete newbie in graphics and programming in general, thw we are coding in XNA. And yes I know packing is simple with integer textures but indeed I want to avoid 16 bit integer textures as I personally saw how instead of using this texture the game used R10G10B10A2 when I launched it on an old GPU (I used it for lighting so it was clearly visible). I guess the worst case scenario for me would be to render the scene twise, but again I want to avoid it as our rendering code is quite iterleaved with updating... \$\endgroup\$ – cubrman Nov 25 '13 at 8:28
0
\$\begingroup\$

I have actually found a way to do it.

The thing is, alpha values are blended separately from colors and you can specify a different function for their blending. So what you can do, is set the blending function for alphas as BlendFunction.Max and only allow the highest alphas through. This will allow you to "mark" pixels for the glow pass with alphas equal to "1".The latter will obviously work for opaque objects, but in order for it to work for the translucent objects, you need to limit their output alpha values to the range 0 - 0.99f (or (0 - 254)/256 for RGBA32).

Translucent objects use their output alpha channels to specify the how much of their color must be blended with the underlying destination color. The maximum of 0.99f is pretty close to opaque, so you will be able to blend your bushes and smokes just like before, but, at the same time, if you will need to mark the pixel for the bloom pass - you will always be able to set output alpha to "1".

Now for the glow power. There is actually a way to control how much the pixel will glow when blurred by simply tweaking it's color. If you want it to shimmer white - make it gray, if you want it to be bright yellow - make it medium yellow! If you want to be even more creative - use FP16 textures and specify the glow power as a number between 1 and 2.

In the end of the day the only limitation I see in this approach is the fact that only fully opaque pixels will be able to glow, but if you think about it, it's not that big of a limitation :)

I've just checked it in the NSight profiler - rendering a huge polygon with translucent 2d ship with lots of opaque areas and some translucent pixels is no different GPU-time-vise for standard blending or MAX blending with alpha = min (alpha, 0.98f) and visually the colors behind the ship are visible only if you force yourself to see them.

enter image description here

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.