OpenGL 默认管道 alpha 混合对 alpha 组件没有任何意义

OpenGL default pipeline alpha blending does not make any sense for the alpha component

问:有没有办法使用默认管道正确混合 Alpha 组件?

问题: 我正在将半透明表面绘制到纹理中,然后我想将该纹理 blit 到主框架后台缓冲区中。通常,当您使用直接的 alpha 混合来实现透明度或抗锯齿时,就是将颜色分量混合到后台缓冲区(默认情况下没有 alpha 通道)。

但是,当混合到具有 alpha 分量的纹理时,通常的 GL_SRC_ALPHA、GL_ONE_MINUS_DST_ALHPA 不能正确混合“alpha”分量:

注意死星上方红色和蓝色圆圈边缘的问题区域; alpha 组件应该是完全不透明的。请注意,RGB 分量按预期混合。

所以我尝试了 BlendFunc 的不同设置,最接近我想要的是使用 GL_DST_ALPHA 作为我的 dst alpha 缩放因子。

这种方法仍然存在问题,因为混合两个不透明度为 50% 的表面应该会产生一个不透明度为 75% 的组合表面。但是使用 OpenGL 默认公式,我得到 (0.50.5) + (0.50.5) = 0.5。更令人不安的是,如果我有 2 个不透明度为 40% 的表面,我会得到一个不透明的表面:(.4*.4)+(.4*.4) = 0.32.

真正的公式 ( 1 - ( 1 - srcAlpha ) * ( 1 - dstAlpha ) ) 意味着我可以在 alpha 分量的混合方程中使用 GL_FUNC_MULT 而不是 GL_FUNC_ADD .不幸的是,这不存在。

所以我放弃了,尝试用着色器来解决。如果您要渲染的纹理也是您从中读取的纹理,那么这会变得非常复杂。特别是如果您渲染多个半透明表面。

我正在寻找尚未尝试过的替代解决方案。欢迎任何想法。

编辑: 我也尝试将 GL_ONE 作为 src 和 dst 比例因子。这使得 alpha 分量太不透明,因为 1*.5 + 1*.5 将给出 1 作为生成的 alpha。让我想知道 GL_ONE 和 GL_DST_ALPHA 是否会给出更好的结果。

p.s。 : 我使用 Anders Riggelsen 的图像混合工具。

完美混合的标准技术是使用

glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);

请注意,它需要对源和目标进行预乘,并产生预乘结果。

预乘基本上意味着对颜色执行color.rgb *= color.a。通常你在加载它们时将它应用到纹理,到你的着色器中的最终颜色。

推论:如果alpha == 1,预乘没有区别。


如果源未预乘,但目标是,请改用:

glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);

是的,有点。

混合因子ONE_MINUS_DST_ALPHA,ONE 可用于正确混合 alpha。如果你有 glBlendFuncSeperate,你可以为颜色和 alpha 设置不同的混合因子。操作是add.

我之所以这么说,是因为我记得单独的混合函数在已弃用的 API 中出现得很晚。

编辑:经过计算后,这些混合因子在数学上等同于 HolyBlackCat 的答案。