与WebGL中的HTML背景混合 [英] Blending with HTML background in WebGL

查看:200
本文介绍了与WebGL中的HTML背景混合的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我将平面颜色和纹理绘制到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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆