在OpenGL中与透明度混合时的背景色问题

时间:2019-08-14 08:09:07

标签: opengl transparency

让我们以最简单的情况为例,用alpha=0.5渲染两个重叠的透明矩形,一个红色和一个绿色。假定绘制顺序是从后到前,即先绘制距离摄像机较远的矩形。

在实际情况下,无论哪个矩形碰巧位于前面,重叠的颜色都应相同,即RGBA = [0.5, 0.5, 0.0, 0.5]

但是,实际上,假设我们正在混合权重SRC_ALPHAONE_MINUS_SRC_ALPHA,则重叠的颜色由前矩形的颜色决定,如下图所示:

enter image description here

我相信这是因为第一个矩形与背景色混合,然后第二个矩形与结果色混合。按照这种逻辑,假设背景为白色,则两种情况下的重叠颜色为:

Red on top: 0.5*(0.5*[1,1,1,0] + 0.5*[0,1,0,0.5]) + 0.5*[1,0,0,0.5] = [0.75, 0.50, 0.25, 0.375]
Green on top: 0.5*(0.5*[1,1,1,0] + 0.5*[1,0,0,0.5]) + 0.5*[0,1,0,0.5] = [0.50, 0.75, 0.25, 0.375]

解释了顶部颜色的优势。原则上,如果先混合所有对象,然后将结果颜色与背景颜色混合,则可以很容易地纠正此问题。

有没有办法在OpenGL中实现呢?

2 个答案:

答案 0 :(得分:1)

  

理想情况下,无论哪个矩形恰好位于前面,重叠的颜色都应相同

否,因为当您使用“ SourceAlpha,InvSourceAlpha”混合时,用于计算最终颜色的公式为:

destRGB = destRGB * (1-sourceAlpha) + sourceRGB * sourceAlpha

这将导致首先绘制的矩形的颜色乘以Alpha通道并添加到帧缓冲区。绘制第二个矩形时,帧缓冲区的内容(包括第一个矩形的颜色)将再次乘以第二个矩形的反向alpha通道。
第二个矩形的颜色仅乘以第二个矩形的alpha通道:

destRGB = (destRGB * (1-Alpha_1) + RGB_1 * Alpha_1) * (1-Alpha_2) +  RGB_2 * Alpha_2

destRGB = destRGB * (1-Alpha_1)*(1-Alpha_2) + RGB_1 * Alpha_1*(1-Alpha_2) + RGB_2 * Alpha_2

虽然RGB_2乘以Alpha_2,而RGB_1乘以Alpha_1 * (1-Alpha_2)
因此,如果帧缓冲区中的颜色被新(源)颜色的alpha通道修改,则结果取决于绘制顺序。


如果要获得与顺序无关的效果,则不得通过源片段的alpha通道修改帧缓冲区的颜色。例如:

destRGB = destRGB * 1 + sourceRGB * sourceAlpha

对于目标因子glBlendFunc,可以通过参数GL_ONE来实现:

glBlendFunc(GL_SRC_ALPHA, GL_ONE);

答案 1 :(得分:1)

绘制透明表面的顺序取决于批次。发生大多数问题是因为您正在使用深度测试并写入深度缓冲区(在这种情况下,结果不仅取决于前面的三角形,而且取决于首先绘制的三角形)。但是,如果您忽略深度而只想一个接一个地绘制三角形,那么除非您使用某些可交换混合功能,否则结果仍然取决于绘制三角形的顺序。

由于您一直在谈论彩色玻璃,因此以下是一种与彩色玻璃大致相同的选项:

glBlendFunc(GL_ZERO, GL_SRC_COLOR)

这实际上将目标的每个颜色通道乘以源的相应颜色通道。因此,如果您绘制一个颜色为(0.5, 1.0, 1.0)的三角形,则它将基本上将所绘制到的红色通道除以2。在黑色目标上绘制将使像素保持黑色,就像彩色玻璃一样。

要减少彩色玻璃的“不透明度”,您必须将颜色与(1.0, 1.0, 1.0)混合。 alpha值将被忽略。

作为奖励,此混合功能与绘制形状的顺序无关(假设您已锁定深度缓冲区或禁用了深度测试)。