glBlendFunc and fading frame buffer to color

Hello there.

I want to fade what i already have accumulated in my frame buffer to specific color.

For starters, simple fade to black.

So each frame i draw a quad big enough to fill the screen, with glColor4f(0.0f,0.0f,0.0f, fade ), where fade is set to a low value (0.001, for example), and i do not clear the frame buffer.

My understanding is that the blending is performed with the following formula:

result = sfactor * source + dfactor * destination

Where source is pixel RGB value of incoming data, destination is pixel RGB value of data present in framebuffer and sfactor and dfactor are defined in glBlendFunc( GLenum sfactor, GLenum dfactor ).

Since what i really want is to just reduce all pixel RGB values to 0, i thought i could just set glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_ALPHA), which would give me 0 * source + 0.999 * destination (i know the fading process would actually ‘slow down’ with such setting, but nevermind that for now).

Here are my init settigs:


  	glEnable(GL_BLEND);
        glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_ALPHA);
	glClearDepth(1.0f);
	glEnable(GL_DEPTH_TEST);
	glDepthFunc(GL_LEQUAL);						
	glDisable(GL_ALPHA_TEST);

Well, it doesnt work. The whole screen becomes black immediately. However, it kind of works with glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA). Kind of, because for pixel of RGB 255,255,255, for some odd reason it stops at 63,63,63. This confuses me even more. Why would GL_ONE matter, since the RGB values of source are all 0 anyway? And why does it stop at 63,63,63?

Thanks.

I would try a different approach to solve this problem :

  • copy framebuffer to texture or use FBO
  • draw it on a fullscreen quad, along with glColor value converging toward your “specific color”, or using a shader with a uniform updated each frame for the same effect.

Your incremental approach has quite a lot of problems related to accumulating color imprecision.

So theres no straightforward way to do this using a transparent quad and blending?

Be careful when using low float values for blending when using 8 bit per color channel. e.g. in your case if you have a white pixel (255) after blending you get 0.999*255 = 254.754 -> 255 after rounding back to 8 bit. So nothing will happen.

Would it be possible, if lights are present in the scene, to simply interpolate the light values to the desired color? Say you turn off diffuse and specular lighting and simply interpolate ambient to the desired color.

Yes, there is a straightforward way. Draw the entire scene as normal every frame, and then blend over your quad using GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA (and with depth write, depth test and texturing disabled) and increasing the value of fade by a time-based function.

OK, this will do the fade for you. Just stick it at the end of your normal render function, right before your swap buffers call. No need to make any other changes to your renderer, just supply the correct params and it will do the rest.

void RenderFadeBlend (bool bFading, int WindowWidth, int WindowHeight, float r, float g, float b, float frametime, float fadetime)
{
    static float fBlackAlpha = -1;

    if (bFading)
    {
        // begin a new fade if necessary
        if (fBlackAlpha < 0)
            fBlackAlpha = 0;
    }
    else
    {
        // if the previous fade has just ended don't fade at all
        if (fBlackAlpha < 0)
            return;
    }

    glEnable (GL_BLEND);
    glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glDisable (GL_DEPTH_TEST);
    glDisable (GL_TEXTURE_2D);

    glMatrixMode (GL_PROJECTION);
    glPushMatrix ();
    glLoadIdentity ();

    // when laying out a 2D view, sometimes "top-left is the origin" makes more sense.
    // it is the direction i read in, after all.  live with it, weenies.
    glOrtho (0, WindowWidth, WindowHeight, 0, -1, 1);

    glMatrixMode (GL_MODELVIEW);
    glPushMatrix ();
    glLoadIdentity ();

    glColor4f (r, g, b, fBlackAlpha);

    glBegin (GL_QUADS);

    glVertex3f (0, 0, 0);
    glVertex3f (WindowWidth, 0, 0);
    glVertex3f (WindowWidth, WindowHeight, 0);
    glVertex3f (0, WindowHeight, 0);

    glEnd ();

    glDisable (GL_BLEND);
    glEnable (GL_DEPTH_TEST);
    glEnable (GL_TEXTURE_2D);

    glMatrixMode (GL_PROJECTION);
    glPopMatrix ();

    glMatrixMode (GL_MODELVIEW);
    glPopMatrix ();

    // bring the fade up or down over a fadetime second period
    if (bFading)
        fBlackAlpha += (frametime / fadetime);
    else fBlackAlpha -= (frametime / fadetime);
}

It’s an exercise for the individual if you want to put it in a display list, use vertex arrays, pretty it up, make it more flexible, or whatever. The purpose of this code is to demonstrate an effect.