C++ 如何在opengl上为两个重叠对象设置混合函数
嗨,我需要画一个圆角矩形。 我按照上图的步骤进行操作。我首先画了绿色的长方形。然后我画了两个黑色的长方形,然后在边上画了圆圈,使角变圆。现在我做了这件事后得到的是下图 可以看出,角圆与矩形重叠部分的透明度较低。但当不与矩形重叠时,透明度更高。矩形的alpha设置为0.5f。圆也有0.5fα。这就是为什么重叠部分为白色,非重叠部分为透明。我希望重叠部分具有与矩形相同的透明度,这样就看不到重叠的圆形部分。我的混合函数是C++ 如何在opengl上为两个重叠对象设置混合函数,c++,opengl-es,alphablending,opengl-es-1.1,C++,Opengl Es,Alphablending,Opengl Es 1.1,嗨,我需要画一个圆角矩形。 我按照上图的步骤进行操作。我首先画了绿色的长方形。然后我画了两个黑色的长方形,然后在边上画了圆圈,使角变圆。现在我做了这件事后得到的是下图 可以看出,角圆与矩形重叠部分的透明度较低。但当不与矩形重叠时,透明度更高。矩形的alpha设置为0.5f。圆也有0.5fα。这就是为什么重叠部分为白色,非重叠部分为透明。我希望重叠部分具有与矩形相同的透明度,这样就看不到重叠的圆形部分。我的混合函数是glBlendFunc(GL_SRC_ALPHA,GL_ONE_减去_SRC_
glBlendFunc(GL_SRC_ALPHA,GL_ONE_减去_SRC_ALPHA)代码>我试图在中更详细地理解混合函数。但我什么都不懂。
我的代码在下面
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glViewport(0, 0, (int) screenWidth, (int) screenHeight);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrthof(0.0f, (double)screenWidth / screenHeight, 0.0f, 1.0f, -1.0f, 1.0f);
glEnable(GL_TEXTURE_2D);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnable(GL_COLOR_MATERIAL);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_TEXTURE_2D);
glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_DST_ALPHA);
glEnableClientState(GL_COLOR_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, bubbleMiddleRectStartCoord);
glColorPointer(4, GL_FLOAT, 0, rectColor);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glVertexPointer(3, GL_FLOAT, 0, bubbleTopRectStartCoord);
glColorPointer(4, GL_FLOAT, 0, rectColor);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glVertexPointer(3, GL_FLOAT, 0, bubbleBottomRectStartCoord);
glColorPointer(4, GL_FLOAT, 0, rectColor);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
//smooth edge of the bubble rectangle
drawCircle(triangleAmount,bubbleEdgeRadius,bubbleMiddleRectStartCoord->upperLeft.x+bubbleEdgeRadius,bubbleMiddleRectStartCoord->upperLeft.y,255,255,255,128);
drawCircle(triangleAmount,bubbleEdgeRadius,bubbleMiddleRectStartCoord->lowerLeft.x+bubbleEdgeRadius,bubbleMiddleRectStartCoord->lowerLeft.y,255,255,255,128);
drawCircle(triangleAmount,bubbleEdgeRadius,bubbleMiddleRectStartCoord->upperRight.x-bubbleEdgeRadius,bubbleMiddleRectStartCoord->upperRight.y,255,255,255,128);
drawCircle(triangleAmount,bubbleEdgeRadius,bubbleMiddleRectStartCoord->lowerRight.x-bubbleEdgeRadius,bubbleMiddleRectStartCoord->lowerRight.y,255,255,255,128);
glDisableClientState(GL_COLOR_ARRAY);
glEnable(GL_TEXTURE_2D);
glDisable(GL_BLEND);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_COLOR_MATERIAL);
glDisable(GL_TEXTURE_2D);
swapBuffers();
rectColor
有值
GLfloat rectColor[]=
{
1.0f,1.0f,1.0f,0.5,
1.0f,1.0f,1.0f,0.5,
1.0f,1.0f,1.0f,0.5,
1.0f,1.0f,1.0f,0.5
};
drawCircle函数为圆生成点并绘制它。该函数的绘图部分是
glVertexPointer(2, GL_FLOAT, 0, vertices);
glColorPointer(4, GL_UNSIGNED_BYTE, 0, color);
glDrawArrays(GL_TRIANGLE_FAN, 0, triangleAmount+2);
有人能帮我解决这个问题吗?谢谢
编辑:这是使用这两个混合函数后的效果。
我知道你要做什么,看到你的结果,你可能只需要在绘制遮罩(3个矩形和4个圆)时禁用混合,然后使用glBlendFunc(GL_DST_ALPHA,GL_ZERO)
。不过,只有在场景中没有绘制任何内容时,此操作才会起作用
为了解释你在那里做了什么,你正在用.5 alpha绘制一个白色并将其混合。
在开始时考虑像素颜色“目的地”是(0,0,0,0),传入的“源”总是在你的情况下(1,1,1,5)。假设源颜色为“S”,目标颜色为“D”,而组件为(r、g、b、a),因此源alpha为“S.a”,您在混合函数中编写的是:
output = S*S.a + D*(1.0-S.a) =
(1,1,1,.5)*.5 + (0,0,0,0)*(1.0-.5) =
(.5, .5, .5, .25) + (0,0,0,0) =
(.5, .5, .5, .25)
因此,当您在已绘制的矩形上绘制圆时:
output = S*S.a + D*(1.0-S.a) =
(1,1,1,.5)*.5 + (.5, .5, .5, .25)*(1.0-.5) =
(.5, .5, .5, .25) + (.25, .25, .25, .125) =
(.75, .75, .75, .375)
导致阿尔法差异。因此,我希望您能够理解混合函数中的两个参数的含义:第一个参数告诉您使用什么因子来乘以源(传入)颜色,第二个参数告诉您如何乘以目标颜色。最后,它们被汇总在一起
因此,对于您的情况,您希望在绘制这些基本体的任何地方强制alpha通道为某个值。要实现这一点,您需要S*1.0+D*.0
,其参数为glBlendFunc(GL\u ONE,GL\u ZERO)
,尽管这与禁用混合相同。只有编写此原语才能生成一个透明度为.5
的白色(灰色)圆形矩形,而其余的都是完全透明的。现在,在此之后,您需要设置混合函数,以将输入颜色与目标alpha相乘glBlendFunc(GL_DST_alpha,GL_ZERO)
编辑:
到现在为止,我还没有完全理解你想要实现什么。正如我上面提到的,如果您已经绘制了一些场景,这将不起作用
要用一些复杂对象覆盖现有场景(在本例中,对象在某些部分上重叠),使用模具缓冲区将是最安全的。创建它很像深度缓冲器,但是你可以把它看作另一个颜色通道,很容易画出来,然后再使用它,所以你可能需要在某个时间点看它。
在您的情况下,可以安全地说这是您的主缓冲区,用于显示。在这种情况下,您可以使用alpha通道:
要仅绘制到alpha通道,必须设置glColorMask(GL\u FALSE,GL\u FALSE,GL\u FALSE,GL\u TRUE)
,完成后,将所有参数设置为TRUE
要清除alpha通道,您必须绘制一个带有所需alpha颜色的全屏矩形(我建议您使用(1,1,1,1)
),并仅绘制到alpha通道
要绘制遮罩(3个矩形和4个圆),请使用glBlendFunc(GL_ONE,GL_ZERO)
和颜色(1,1,1-desiredAlpha)
要绘制圆形标签,请使用glBlendFunc(GL_ONE_减去DST_ALPHA,GL_DST_ALPHA)
因此,程序将是:
//your background is drawn, time to overly labels
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE);
glColor(1.0f, 1.0f, 1.0f, 1.0f);
//draw fullscreen rect
glBlendFunc(GL_ONE, GL_ZERO);
glColor(1.0f, 1.0f, 1.0f, 1.0f-.5f);
//draw 3 rects and 4 circles
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_DST_ALPHA);
//draw the label as a normal rect (the rounded parts will be trimmed because of alpha channel)
您可以在for
循环中对所有标签重复该操作
我知道事情有点复杂,但你想做的事情并不像看上去那么容易。我向您介绍了这个解决方案,因为这样您可以更改最少的代码,通常我建议使用模具缓冲区(已经提到)或FBO(帧缓冲区对象)。FBO系统将创建另一个帧缓冲区并向其附加纹理,将整个标签对象绘制到该缓冲区,然后使用绑定的纹理将其绘制到主屏幕。您好,谢谢您的解释。很好:)但我对最后一段有点困惑。我理解为什么我需要做glBlendFunc(GL\u ONE,GL\u ZERO)
。我知道我需要在绘制矩形之后和绘制圆之前编写glBlendFunc(GL\u ONE,GL\u ZERO)
。因此,矩形通常以0.5 alpha绘制,但绘制圆时,矩形的alpha不会产生任何影响。还有为什么我需要做glBlendFunc(GL_DST_ALPHA,GL_ZERO)
?我应该把它放在哪里?谢谢。但是我想我遗漏了一些东西,因为这样做之后,圆圈就没有透明度了。但矩形是透明的。我把glBlendFunc(GL\u ONE,GL\u ZERO)
放在我画矩形之后和画圆之前。在画完之后,我又把这个glBlendFunc(GL_SRC_ALPHA,GL_ONE_减去SRC_ALPHA)
。谢谢。不用了,你可以用(GL_ONE,GL_ZERO)来画矩形和圆形,然后用(GL_DST_ALPHA,GL_ZERO)来画图像。第一个混合模式不会对重叠产生影响,因为目标值不存在