0

嗨,我需要画一个圆角矩形。 圆矩形绘制程序

我按照上图的过程。我首先画了绿色矩形。然后我画了两个黑色的矩形。然后我在边缘画了圆圈,使角变圆。现在我这样做后得到的如下图所示。

在此处输入图像描述

可以看出,角圆与矩形重叠的部分透明度较低。但不与矩形重叠时透明度更高。矩形的 alpha 设置为 0.5f。并且圆圈也有 0.5f alpha。所以这就是为什么它在重叠部分是白色的,在非重叠部分是透明的。我希望重叠部分具有与矩形相同的透明度,以便无法看到重叠的圆形部分。glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_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);

谁能帮我解决这个问题?谢谢。

编辑:这是使用这两个混合功能后的样子。 在此处输入图像描述

4

1 回答 1

1

我知道你要去哪里,看到你的结果,你可能只需要在绘制蒙版(3 个矩形和 4 个圆圈)时禁用混合,然后使用glBlendFunc(GL_DST_ALPHA, GL_ZERO). 虽然这只有在场景上没有任何东西的情况下才有效。

为了解释你在那里做了什么,你正在用 0.5 alpha 绘制白色并混合它。考虑一开始像素颜色“目标”是(0,0,0,0),而传入的“源”总是在你的情况下(1,1,1,.5)。假设源颜色为“S”,目标颜色为“D”,而组件为 (r,g,b,a),因此源 alpha 为“Sa”,您在混合函数中编写的是:

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差异。所以从这里我希望你能理解这两个参数在混合函数中的含义:第一个告诉使用什么因子来乘以源(传入)颜色,第二个告诉如何乘以目标颜色。最后将它们加在一起。

因此,对于您的情况,您希望在绘制这些图元的任何地方都将 alpha 通道强制为某个值。要实现这一点,您需要S*1.0 + D*.0的参数是glBlendFunc(GL_ONE, GL_ZERO),尽管这与禁用混合相同。只有编写这个基元会产生一个透明的白色(灰色)圆角矩形,.5而其余的都是完全透明的。现在,在此之后,您需要设置混合函数以将传入的颜色与目标 alpha 相乘glBlendFunc(GL_DST_ALPHA, GL_ZERO)

编辑:

到目前为止,我还没有完全理解您想要实现的目标。正如我上面提到的,如果您已经绘制了一些场景,这将不起作用。

要使用一些复杂的对象覆盖现有场景(在这种情况下,对象在某些部分上会重叠自身),使用模板缓冲区是最安全的。创建它很像深度缓冲区,但您可以将其视为另一个颜色通道,很容易绘制到它并稍后使用它,因此您可能想在某个时候查看它。

在您的情况下,可以肯定地说这是您的主要缓冲区并且用于显示。在这种情况下,您可以只使用 alpha 通道:

要仅绘制到 Alpha 通道,您必须设置glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE),完成后,将所有参数设置为 true。

  1. 要清除 alpha 通道,您必须使用具有所需 alpha 的某种颜色绘制全屏矩形(我建议您使用(1,1,1,1))并仅绘制到 alpha 通道
  2. 要绘制该蒙版(3 个矩形和 4 个圆圈),请使用glBlendFunc(GL_ONE, GL_ZERO)和颜色(1,1,1, 1-desiredAlpha)
  3. 要绘制圆形标签,请使用glBlendFunc(GL_ONE_MINUS_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 系统将创建另一个帧缓冲区并将纹理附加到它,将整个标签对象绘制到它,然后使用绑定的纹理将其绘制到主屏幕。

于 2013-05-22T13:31:57.063 回答