OpenGL default pipeline alpha blending does not make any sense for the alpha component

ε祈祈猫儿з 提交于 2021-02-04 14:47:07

问题


Q : Is there a way to use the default pipeline to blend the Alpha component properly?

Problem : I'm drawing semi-transparent surfaces into a texture, then I want to blit that texture into the main frame back buffer. Normally when you use straightforward alpha blending for transparency or antialiasing, it is to blend color components into the back buffer ( which has no alpha channel by deafult ).

However, when blending into a texture that has an alpha component, the usual GL_SRC_ALPHA, GL_ONE_MINUS_DST_ALHPA does not blend the "alpha" component properly :

Notice the problematic zone over the death star at the edge of the red and blue circles; the alpha component is supposed to be completely opaque. Note that the RGB components are blendend as expected.

So I played around with different settings for the BlendFunc and the closest to what I want is by using GL_DST_ALPHA as my dst alpha scaling factor.

There is still a problem with this approach because blending two surfaces with 50% opacity should give a combined surface of 75% opacity. But using OpenGL default formulas, I get (0.5*0.5) + (0.5*0.5) = 0.5. More disturbing, if I have 2 surfaces with 40% opacity, I get a LESS opaque surface : (.4*.4)+(.4*.4) = 0.32.

The real formula ( 1 - ( 1 - srcAlpha ) * ( 1 - dstAlpha ) ) would imply that I could use a GL_FUNC_MULT instead of GL_FUNC_ADD in the blend equation for the alpha component. Unfortunately this does not exist.

So I gave up and tried to do a solution using a shader. This becomes complicated really fast if the texture you are rendering to is also the texture you read from. Especially if you render multiple semi-transparent surfaces.

I'm looking for alternative solutions I have not already tried. Any idea is welcome.

EDIT : I also tried GL_ONE as both src and dst scaling factor. this makes the alpha component way too opaque as 1*.5 + 1*.5 will give 1 as the resulting alpha. Makes me wonder if GL_ONE and GL_DST_ALPHA would give better results.

SOLVED : After knowing the answer ( see comments ), I found multiple references talking about the same solution :

https://www.opengl.org/discussion_boards/showthread.php/167554-FBO-and-blending

https://forum.openframeworks.cc/t/weird-problem-rendering-semi-transparent-image-to-fbo/2215/10

https://www.opengl.org/wiki/Blending

I feel stupid not finding those by myself

p.s. : I used Anders Riggelsen's blending tool for the images.


回答1:


A standard technique to do perfect blending is to use

glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);

with premultiplied textures (or colors, if you don't have textures).

Premultiplication basically means applying color.rgb *= color.a to the textures when you load them (or applying same equation to the final color in a shader).


You can achieve same result without premultiplication with following blend mode:

glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);

Keep in mind that both blending modes will produce premultiplied output.




回答2:


Yes, kind of.

Blending factors ONE_MINUS_DST_ALPHA, ONE may be used for blending alpha correctly. If you have glBlendFuncSeperate you can set different blend factors for color and alpha. Operation is add.

I say kind of because as I recall seperate blend func appeared late in the deprecated API.

Edit: after doing the math those blend factors are mathematically equivalent to HolyBlackCat answer.



来源:https://stackoverflow.com/questions/37532428/opengl-default-pipeline-alpha-blending-does-not-make-any-sense-for-the-alpha-com

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!