与WebGL中的HTML背景混合 [英] Blending with HTML background in WebGL
问题描述
我将平面颜色和纹理绘制到WebGL画布中。我的颜色和纹理具有不同的alpha值,我希望它们能够正确混合。我想要有透明的背景(它们应该与HTML内容混合,在canvas下)。
在WebGL中,我使用
gl.clearColor(0,0,0,0);
gl.blendFunc(gl.SRC_ALPHA,gl.ONE_MINUS_SRC_ALPHA);
gl.enable(gl.BLEND);
当HTML背景为黑色时,它可以正常工作。但是当我将JPG图案设置为背景时,我绘制了黑色三角形(alpha = 1)和白色三角形(alpha = 0.5),我可以看到三角形相互交叉的背景图案。这是正确的行为吗?
我之前的回答实际上是不正确的。 是您所描述的预期结果。
gl.blendFunc(gl.SRC_ALPHA,gl.ONE_MINUS_SRC_ALPHA)
表示生成的字母是
A_final = A_s * A_s +(1 - A_s)* A_d
在您的示例中,在绘制黑色三角形(alpha = 1)后, framebuffer将会有一个字节
1 * 1 +(1 - 1)* 0 == 1 + 0 == 1
所以它会完全不透明。接下来,绘制白色三角形(带alpha = .5)后,两个三角形相交处的像素将具有
.5 * .5 +(1 - .5)* 1 == .25 + .5 == .75
这意味着最终的颜色将被视为部分透明,并且当它与页面合成时,页面背景将显示出来。
在常规的OpenGL中,这是一个不常见的问题,因为内容通常是针对空白背景进行合成的。但是,当您绘制到FBO时它会出现,但必须将结果与上下文中的其他内容进行合成。有一些方法可以解决这个问题。
一种方法是让你的alpha与 gl.ONE
, gl.ONE_MINUS_SRC_ALPHA
所以你得到
A_final = A_s +(1 - A_s)* A_d
这就是你通常需要的alpha混合。但是,您希望您的颜色仍与 gl.SRC_ALPHA
, gl.ONE_MINUS_SRC_ALPHA
混合。您可以使用 gl.blendFuncSeparate 代替 gl.blendFunc
分别设置颜色混合和alpha混合功能。在这种情况下,您可以调用
$ pre $ gl $ B $ );
另一种选择是利用预乘alpha的颜色( WebGL实际上已经假定您正在使用,例如,从纹理中抽取颜色时)。如果绘制第二个三角形,其alpha值已经与颜色相乘(因此半透明白色三角形将 gl_FragColor
设置为 vec4(.5, .5,.5,.5)
),那么你可以使用混合模式
gl .blendFunc(gl.ONE,gl.ONE_MINUS_SRC_ALPHA)
并且它将按照您想要的颜色因为(如上所述),WebGL已经假定你的颜色是预乘(例如 vec4(1,1,1,.5)
超出色域,渲染输出未定义,驱动程序/ GPU可输出任何想要的疯狂颜色)。在常规的OpenGL示例中看到 gl.blendFunc(gl.SRC_ALPHA,gl.ONE_MINUS_SRC_ALPHA)
会更常见,这会导致一些混淆。
I am drawing flat colors and textures into WebGL canvas. My colors and textures have varying alpha values and I want them to be blended correctly. I want to have transparent background (they should be blended with HTML content, which is under canvas).
In WebGL, I use
gl.clearColor(0, 0, 0, 0);
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
gl.enable(gl.BLEND);
It works correctly, when HTML background is black. But when I set a JPG pattern as a background of , I draw black triangle (alpha=1) and white triangle (alpha=0.5), I can see the background pattern in place where triangles intersect each other. Is this correct behavior?
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.
这篇关于与WebGL中的HTML背景混合的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!