在小 alpha 值上错误地在 OpenGL 中混合

Posted

技术标签:

【中文标题】在小 alpha 值上错误地在 OpenGL 中混合【英文标题】:Wrong blending in OpenGL on small alpha value 【发布时间】:2016-08-27 09:49:49 【问题描述】:

我从纹理中画了很多白色的卷边。但是当它在黄色圆圈上绘制时,包含一个小的 alpha 值(但不等于 0)的点混合错误,我在屏幕上得到一些较暗的像素(见截图,它被放大了)。哪个可能是问题? 在蓝色背景上一切正常。

【问题讨论】:

看起来像低 alpha 值的白色像素和 alpha 值为 0 的黑色像素之间的插值问题(箭头外部完全透明)。 可能是显卡驱动的问题? 不,这就是插值的工作原理。不确定如何图像编辑程序保存完全透明的像素,但如果我是对的,它只会将它们保存为黑色,因为它(通常)并不重要。不过那很糟糕。您应该在上传图片之前对其进行预处理,并将所有 alpha 值为 0 的像素设置为白色。 向您致以崇高的敬意。我在我的程序中渲染图像(来自 SVG)。它将是智能手机的应用程序,它将支持高 DPI。我只是在从 svg 绘制之前更改了图像的清晰颜色。它有效! 如果我将放大滤镜和缩小滤镜设置为最近也有帮助。 【参考方案1】:

正如@tklausi 在 cmets 中指出的那样,这个问题与纹理插值与传统 alpha 混合的结合有关。在从具有高 alpha 的值转换到 alpha=0 的“背景”时,您将获得一些 alpha > 0 且 RGB 与您的“背景”颜色混合的插值结果。

@tlkausi 的解决方案是将背景的 RGB 值更改为白色。但这将导致与以前相同的问题:如果您的实际图像具有深色,那么您将在其周围看到明亮的伪影。

正确的解决方案是重复实际边框像素的 RGB 颜色,这样插值将始终产生相同的颜色,只是具有较低的 alpha 值。

但是,有一个更好的解决方案:预乘 alpha。 不是在每个像素的纹理中存储 (R,G,B,a),而是存储 (aR,aG,aB,a)。混合时,不要使用a*source + (1-a) * background,而只需使用source + (1-a)*background。不同之处在于您现在有一个“中性元素”(0,0,0,0),并且对此进行插值不会造成任何问题。它非常适合过滤,也适用于 mipmapping 和其他技术。

一般来说,我会建议总是使用预乘 alpha 来支持“传统”的。预乘可以直接应用到图像文件中,也可以在纹理上传时进行,但它不会产生任何运行时成本。

有关预乘 alpha 的更多信息,请访问 in this MSDN blog article 或 over here at NVIDIA。

【讨论】:

以上是关于在小 alpha 值上错误地在 OpenGL 中混合的主要内容,如果未能解决你的问题,请参考以下文章

如何在 java/xuggler 中混音多个音频通道?

在 QGLFramebufferObject 上渲染时错误的 alpha 混合

OpenGL 3.3 - glDrawArrays 后的无效操作错误 (1282)

Libgdx/Opengl alpha blending(结果 alpha 被源 alpha 替换)

OpenGL 包装器中的 Alpha/纹理问题

OpenGL ES 1.1 - alpha 蒙版