用Premultiplied Alpha读出一个FBO

Mar*_*usM 2 javascript opengl webgl

我正在使用此问题的答案中描述的方法将画笔笔划绘制到帧缓冲对象:

opengl - 与之前的framebuffer内容混合

这种方法正确地alpha - 将不同的OpenGL绘图操作混合到一个FBO中,并确保alpha保持正确.

它用

glBlendFuncSeparate(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA,GL_ONE,GL_ONE_MINUS_SRC_ALPHA);

将OpenGL绘图操作(在我的情况下是画笔描边)混合到FBO中并使用

glBlendFunc(GL_ONE,GL_ONE_MINUS_SRC_ALPHA);

将最终的FBO(在我的情况下是类似Photoshop的图层)绘制回屏幕,删除方法中使用的预乘alpha.当FBO blit到屏幕时,这对我来说很好.

但是,当我想读出FBO的内容时,我无法摆脱预乘的alpha.即我用的时候

glBlendFunc(GL_ONE,GL_ONE_MINUS_SRC_ALPHA);

要将图层绘制到另一个FBO中,而不是使用glReadPixel()来读出此FBO的内容,内容仍然是预乘的.

换句话说,当我将FBO绘制到屏幕上时,混合并移除前置.alpha工作,当做同样的事情和绘制到FBO时,它失败了.

当我读出FBO时,这是产生(错误)的图像:

在此输入图像描述

这是将图层直接绘制到屏幕时的正确结果:

在此输入图像描述

谢谢你的帮助.

gma*_*man 5

我不确定你的意思是"摆脱预乘alpha".如果你想让图片无法预乘,那么你必须在JavaScript或者着色器中手动对它进行多次预乘.

gl_FragCoord = vec4(color.a > 0. ? color.rgb / color.a : vec3(0), color.a);
Run Code Online (Sandbox Code Playgroud)

绘制到画布时它起作用的原因是因为默认情况下画布需要预乘alpha.用ONE渲染,ONE_MINUS_SRC_ALPHA用预乘alpha绘制并保持结果预乘

例:

Un-premultiplied    Red = 0.7  Alpha = 0.2

    convert to premultiplied   Red = Red * Alpha

Premultiplied       Red = 0.14 Alpha = 0.2

    blend with ONE,ONE_MINUS_SRC_ALPHA

                    DstRed = 0.0  DstAlpha = 0.0

    newPixelRed    = Red(0.14) * ONE + DstRed(0.0) * (1 - Alpha(0.2))
    newPixelRed    = 0.14 +            0.0 * 0.8
    newPixelRed    = 0.14

    newPixelAlpha  = Alpha(0.2) * ONE + DstAlpha(0.0) * (1 - Alpha(0.2))
    newPixelAlpha  = 0.2 + 0.0 * 0.8
    newPixelAlpha  = 0.2
Run Code Online (Sandbox Code Playgroud)

所以newPixelRed,newPixelAlpha区域正是你画之前的区域.

newPixelRed回到其未经过倍增的状态的唯一方法是除以alpha

newPixelRed = Red(0.14) / Alpha(0.2)
newPixelRed = 0.14 / 0.2
newPixelRed = 0.7            <- The original red before it was premultiplied
Run Code Online (Sandbox Code Playgroud)

您只能在着色器或JavaScript中执行此操作.单独混合不会这样做.