让我们以最简单的情况为例,用alpha=0.5
渲染两个重叠的透明矩形,一个红色和一个绿色。假定绘制顺序是从后到前,即先绘制距离摄像机较远的矩形。
在实际情况下,无论哪个矩形碰巧位于前面,重叠的颜色都应相同,即RGBA = [0.5, 0.5, 0.0, 0.5]
。
但是,实际上,假设我们正在混合权重SRC_ALPHA
和ONE_MINUS_SRC_ALPHA
,则重叠的颜色由前矩形的颜色决定,如下图所示:
我相信这是因为第一个矩形与背景色混合,然后第二个矩形与结果色混合。按照这种逻辑,假设背景为白色,则两种情况下的重叠颜色为:
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中实现呢?
答案 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值将被忽略。
作为奖励,此混合功能与绘制形状的顺序无关(假设您已锁定深度缓冲区或禁用了深度测试)。