Blending with HTML background in WebGL

走远了吗. 提交于 2019-12-05 10:55:34

My earlier answer was actually incorrect. That is the expected result of what you describe.

gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA) means that the resulting alpha is

A_final = A_s * A_s + (1 - A_s) * A_d

In your example, after the black triangle (with alpha=1) is drawn, a drawn pixel in the framebuffer will have an alpha of

1 * 1 + (1 - 1) * 0 == 1 + 0 == 1

So it will be fully opaque. Next, after the white triangle (with alpha=.5) is drawn, a pixel in the intersection of the two triangles will have an alpha of

.5 * .5 + (1 - .5) * 1 == .25 + .5 == .75

That means the final color will be treated as partially transparent, and, when it is composited with the page, the page background will show through.

This is a somewhat uncommon problem in regular OpenGL, since content is usually composited against an empty background. It does come up when you draw to an FBO and have to composite the results with other content in your context, though. There are a few ways to deal with this.

One way is to have your alpha blend with gl.ONE, gl.ONE_MINUS_SRC_ALPHA so you get

A_final = A_s + (1 - A_s) * A_d

which is what you usually want with alpha blending. However, you want your colors to still blend with gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA. You can use gl.blendFuncSeparate instead of gl.blendFunc to set your color blending and alpha blending functions separately. In this case, you would call

gl.BlendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA);

Another option is to take advantage of colors with premultiplied alpha (which WebGL actually already assumes you are using, for instance, when sampling a color from a texture). If you draw the second triangle with the alpha already multiplied through the color (so a half transparent white triangle would have gl_FragColor set to vec4(.5, .5, .5, .5)), then you can use the blend mode

gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA)

and it will act as you want for both color and alpha.

The second option is what you'll commonly see in WebGL examples, since (as mentioned), WebGL already assumes your colors are premultiplied (so vec4(1., 1., 1., .5) is out of gamut, the rendering output is undefined, and the driver/GPU can output any crazy color it wants). It's far more common to see gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA) in regular OpenGL examples, which leads to some confusion.

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