使用预乘 Alpha 读出 FBO
Reading out an FBO with Premultiplied Alpha
我正在使用这个问题的答案中描述的方法向帧缓冲区对象绘制笔触:
opengl - blending with previous contents of 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 传送到屏幕时,这对我来说效果很好。
但是,当我想读出FBO的内容时,我无法摆脱预乘的alpha。 IE。当我使用
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
将图层绘制到另一个FBO中,而不是使用glReadPixel()读出这个FBO的内容,内容仍然是预乘的。
换句话说,当我将 FBO 绘制到屏幕上时,混合并移除 prem。 alpha 工作,当做同样的事情并绘制到 FBO 时,它失败了。
这是我读出 FBO 时产生的(错误的)图像:
下面是将图层直接绘制到屏幕时的正确结果:
感谢您的帮助。
我不确定 "get rid of the premultiplied alpha" 是什么意思。如果您希望图片为 un-premultiplied,那么您必须在 JavaScript 或带有
之类的着色器中手动取消预乘
gl_FragCoord = vec4(color.a > 0. ? color.rgb / color.a : vec3(0), color.a);
当您绘制到 canvas 时它起作用的原因是因为默认情况下 canvas 需要预乘 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
因此 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
您只能在着色器或 JavaScript 中执行此操作。单独混合是不行的。
我正在使用这个问题的答案中描述的方法向帧缓冲区对象绘制笔触:
opengl - blending with previous contents of 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 传送到屏幕时,这对我来说效果很好。
但是,当我想读出FBO的内容时,我无法摆脱预乘的alpha。 IE。当我使用
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
将图层绘制到另一个FBO中,而不是使用glReadPixel()读出这个FBO的内容,内容仍然是预乘的。
换句话说,当我将 FBO 绘制到屏幕上时,混合并移除 prem。 alpha 工作,当做同样的事情并绘制到 FBO 时,它失败了。
这是我读出 FBO 时产生的(错误的)图像:
下面是将图层直接绘制到屏幕时的正确结果:
感谢您的帮助。
我不确定 "get rid of the premultiplied alpha" 是什么意思。如果您希望图片为 un-premultiplied,那么您必须在 JavaScript 或带有
之类的着色器中手动取消预乘gl_FragCoord = vec4(color.a > 0. ? color.rgb / color.a : vec3(0), color.a);
当您绘制到 canvas 时它起作用的原因是因为默认情况下 canvas 需要预乘 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
因此 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
您只能在着色器或 JavaScript 中执行此操作。单独混合是不行的。