Destination blending in multisample pbuffer

I have a multisample pbuffer with destination alpha. I clear it to colour (1, 0, 0, 0), and draw a triangle of colour (0, 0, 1, 1) covering half of a square viewport (i.e. one edge is at 45 degrees).

I am a surprised by the colour of the antialiased pixels along the 45 degree edge.
I would expect them to be (0, 0, 1, n).
But in fact they are (1-n, 0, n, n), so I see a nasty purple line down the edge of my nice blue triangle.

It is as if the destination alpha value is being ignored.

Does anyone know if this is the correct behaviour, or if there is a way to fix it?
Normal semi-transparent fragments blend fine; if I blend (0, 0, 1, 0.5) onto (1, 0, 0, 0) in a non-multisample pbuffer, I get (0, 0, 1, 0.5). I expected the same results from anti-aliased fragments.

I am using a GeForce FX 5200 with the latest (71.89) driver on WinXP. I get the same results using Direct3D.


Anyone seen this problem before?
Has anyone ever used a multisample pbuffer with destination alpha?

Not sure what that has to do with destination alpha. What’s your blending mode?
Of course you will get mixed colors on polygon edges which have a coverage between 0 and 1.
Imagine 2x2 fragments building one pixel which gives you four steps from red to blue in your case depending on how many fragments are covered by the drawn triangle.

The destination is cleared to zero alpha, so IMHO the destination colour (red) should be ignored when blending.
This happens correctly when drawing semi-transparent triangles, so my question is: Why does it not happen with multisampling?

I still don’t think there is a problem.
The rendering might be what you expect, inside the multisample buffer’s fragments!
But the pixels are averaged from those and mixing two red and two blue fragments gives a purple pixel.
Does it vanish if you glDisable(GL_MULTISAMPLE)?
Alpha == 0.5 is a single special case, try others too.

The line does vanish if I turn multisample off.
Blending works fine with any alpha value, not just 0.5.
Here is an enlarged screenshot after blending the contents of my pbuffer onto a white background. Note that the transparent red background colour is only visible in the anti-aliased pixels.
Does that help explain my problem?

Thanks for trying to help.

OK, after further tests, I can see that blending does not work correctly either. It shows the same problem as multisampling.
The problem (described here ) seems to be that OpenGL does not pre-multiply and post-divide by alpha when blending.
Thanks anyway,

Be careful here, for OpenGL blend functions premultiplication is not required, the blendfunction does this, that’s what the GL_SRC_ALPHA does to incomming fragments.

If producing a premultiplied image in the destination buffer with multisampling is a requirement then just draw it against a black background, but the source term for alpha after you read back this image and use it as source would become GL_ONE because coverage against a black background has already effectively premultiplied. You still use destination multiplier as GL_ONE_MINUS_SRC_ALPHA.

Do this and you’re effectively compositing with premultiplied alpha.

I have a problem with sweeping statements like the ones made in your link without a context. They can be highly misleading, I’ve done lots of compositing in OpenGL and it absolutely is unambiguously supported (read on for details).

On multisample AA the issue is sample handling and summation in the pixels and there may well be a bug but it ‘should just work’, unless your algorithm is flawed IMHO.

Note that multisample actually solves the classic OpenGL premultiplication problem here, normally alpha fragments are multiplied by the source alpha value. The source alpha value is already multiplying source color. You write that to a destination buffer and what do you get? You get premultiplied color but alpha is squared, but this isn’t proper AA blended rendering anyway, you’d actually use a saturate alpha approach with a sort which would in fact work.

In multisampling this isn’t even a problem because you don’t have fragment alpha, you have coverage. Partial coverage when drawn against black simultaneously gives you premultiplied color and the alpha coverage because incomming alpha should be one (unless the surface is transparent in which case it still works).

But in anycase none of these issues is actually your problem, you’re just drawing a polygon and that has nothing to do with compositing and the more subtle issues.

So in summary that link is referring to a very specific issue with rendering AA images with blended alpha using some glBlendFunc modes for subsequent use in image compositing (specifically alpha multiplies itself), but that has absolutely nothing to do with the problem you are seeing.

(1, 0, 0, 0), and draw a triangle of colour (0, 0, 1, 1)
I would expect them to be (0, 0, 1, n).
But in fact they are (1-n, 0, n, n),

If n = coverage I would expect:

( d*(1-n)+sn, d(1-n)+sn, d(1-n)+sn, d(1-n)+s*n )

plugging in your colors

( 1*(1-n)+0n, 0(1-n)+0n, 0(1-n)+1n, 0(1-n)+1*n )

That rationalizes to:

(1-n, 0, n, n)

Your results are correct and should look intuitively correct, that’s what a polygon of that color should look like against that background with correct weighting.

Your nice blue triangle was drawn against a red background, purple (magenta) was the correct answer.

if I blend (0, 0, 1, 0.5) onto (1, 0, 0, 0) in a non-multisample pbuffer, I get (0, 0, 1, 0.5).


Bull**** :-), you get (0.5, 0, 0.5, 0.25).

P.S. note the difference between the multisample alpha n vs blended alpha n^2, that’s why multisample solves the compositing issue that was never your problem.

Thanks for your comments dorbie.
I think I have got it working now. I am using glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE_MINUS_DST_ALPHA, GL_ONE).
I am also post-dividing the destination rgb values by alpha.
This combination seems to give the results I want.