12

I was using glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) for alpha composing as the document said (and actually same thing was said in the Direct3D document).

Everything was fine at first, until I downloaded the result from GPU and made it a PNG image. The result alpha component is wrong. Before drawing, I had cleared the frame buffer with opaque black colour. And after I drew something semi-transparent, the frame buffer became semi-transparent.

1 Answer 1

17

Well the reason is obvious. With glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA), we actually ignore the destination alpha channel and assume it always be 1. This is OK when we treat the frame buffer as something opaque.

But what if we need the correct alpha value? glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA) and make the source premultiplied (premultiplied texture/vertex color or multiply the alpha component with alpha components before setting it to gl_FragColor).

glBlendFunc can only multiply the original color components with one factor, but alpha compositing needs the destination be multiplied with both one_minus_src_alpha and dst_alpha. So it must be premultiplied. We can't do the premultiplication in the frame buffer, but as long as the source and destination are both premultipied, the result is premultipied. That is, we first clear the frame buffer with any premultiplied color (for example: 0.5, 0.5, 0.5, 0.5 for 50% transparent white instead of 1.0, 1.0, 1.0, 0.5), and draw premultipied fragments on it with glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA), and we will have correct alpha channel in the result. But remember to undo the premultiplication if it is not desired for the final result

Sign up to request clarification or add additional context in comments.

7 Comments

Another important thing to consider: does your framebuffer even have destination alpha bit-planes? This is not a common pixel format, believe it or not. Usually you get something like RGBx8 (x means ignored), Depth:Stencil (24:8) unless you explicitly ask for RGBA. You would think this would be obvious, but since destination alpha is not needed for general alpha blending, people often overlook this...
You can use glBlendFuncSeparate to specify separate blend functions for rgb and alpha, which will allow you to get correct alpha values for compositing without the requirement to use premultiplied alpha.
@rdb, I'm interested in an example with the glBlendFuncSeparate you mention. Could you provide a typical values for this method?
@mgouin For example: glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA)
@mgouin: If your texture and framebuffer are both premultiplied (or have no alpha channel) then use glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA). If your framebuffer is premultiplied (or has no alpha) but your texture is straight alpha, then use glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA) as @rdb said. However, you cannot have a framebuffer with straight alpha using the built-in GPU blending operations -- which is what this question was about.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.