How to do normal blending?

I want to do normal blending with OpenGL, like the blending between layers in Photoshop for example, but it doesn’t seem possible with glBlendFunc.

glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) does not work as expected because if I start with a transparent buffer, render a solid primitive and then render a semi-transparent, the result is semi-transparent even if I did render something totally solid in between.

That’s just all wrong, and it does not work for me.

How can I do normal blending where the alpha value is calculated as 1 - (1-As)*(1-Ad) ?

I haven’t found a general solution to this problem which I consider to be a gaping flaw in the OpenGL standard, but I have found a workaround for my case, so I thought I would let anyone who are interested know …

I use glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
First I render a solid background, that covers most of the buffer, the edges are still transparent.
Then I render the semi-transparent primitives twice, first with the previously mentions blending and then with glBlendFunc(GL_ONE, GL_ONE), texture turned off and glColor4f(0.0, 0.0, 0.0, 1.0);

The solution does not seem very elegant and it seems suboptimal, but it works for me. However, this only works because all the semi-transparent primitives are rendered entirely inside the bounds of the solid background.

I fail to see how you managed to not make it work :

// init part
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);


// in main loop 
            glClearColor (0.0f, 0.0f, 0.0f, 0.0f);
            glClear (GL_COLOR_BUFFER_BIT);


           glPushMatrix ();

           glBegin (GL_TRIANGLES);
             glColor4f (1.0f, 1.0f, 0.5f, 1.0f);
               glVertex2f (0.0f, 1.0f);
               glVertex2f (0.87f, -0.5f);
               glVertex2f (-0.87f, -0.5f);

             glColor4f (0.0f, 1.0f, 0.5f, 0.5f);  
               glVertex2f (0.8f, 1.0f);
               glVertex2f (0.0f, 0.0f);
               glVertex2f (1.0f, 0.0f);
           glEnd ();

           glPopMatrix ();

 

Works perfectly for me.

Beware of the ‘OpenGL is not working’ … it can be right on super fancy new stuff with beta drivers or for features almost never used. Not on something like that.

Edit: I suppose you are using textures. best way to control transparency like in photoshop is to use :

// allow to easily change color with a single glColor call
glEnable(GL_COLOR_MATERIAL);

// multiply texture with base color
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

/////////// for each layer :
// change transparency, t in [O,1] range
glColor3f(1.0f,1.0f,1.0f,t);
//bind texture
//draw stuff
///////

Your code works in the same way that I explained.
------------ Screenshot -----------------

I know it won’t work because the blend function is by definition not usable for what I’m trying to do.

SRC_ALPHA, ONE_MINUS_SOURCE_ALPHA calculates the resulting alpha as AsSa+AdDa which in this case is, 0.50.5+1.0(1-0.5) = 0.75

I need the resulting alpha to be 1.0, like in photoshop blending, or window manager blending, but there is no suitable blending function for this. :frowning:

If I understand well, you want to separate rgb and alpha blending, there are extension to adress this (if supported by your hardware) : GL_EXT_blend_func_separate (and maybe GL_EXT_blend_equation_separate).

http://oss.sgi.com/projects/ogl-sample/registry/

By the way, how did you made the text appear behind… AH ! I see, when you say a transparent buffer, you mean some kind of overlaying GL drawing on top of desktop image. Am I right ?

Yes, I use OpenGL laid directly over the desktop, or directly in a transparent window, to be exact.

I’m not sure if I want to separate color and alpha blending, I’ll take a look at the link. I do want to use as few extensions as possible for maximum compatibility, though.

I think I’ll just stick to the work around that I found, since it seems to do the job well, in my case.

Edit: I looked at GL_EXT_blend_func_separate and with that I would almost be able to do what I want:

BlendFuncSeparateEXT(SRC_ALPHA, ONE_MINUS_SRC_ALPHA, SRC_ALPHA, ONE);

would have been nice. The alphas would have been additive instead of multiplicative which would be ideal, but I could have lived with that.

Thanks for helping out.