Как установить функцию смешивания на opengl для двух перекрывающихся объектов

Привет, мне нужно было нарисовать прямоугольник с круглым углом.
Процедура рисования круглого прямоугольника

Я следовал процедуре, описанной выше. Сначала я нарисовал зеленый прямоугольник. Затем я нарисовал два черных прямоугольника. И затем я нарисовал круги по краям, чтобы угол закруглился. Теперь, что я получаю после этого на рисунке ниже.

введите описание изображения здесь

Как можно видеть, угловые круги имеют меньшую прозрачность на участках, где они перекрываются с прямоугольниками. Но больше прозрачности, когда они не перекрываются с прямоугольниками. Прямоугольники имеют альфа-значение 0.5f. и у круга также есть 0.5f альфа. Вот почему он белый на перекрывающихся участках и прозрачный на неперекрывающихся участках. Я хочу, чтобы перекрывающиеся части имели ту же прозрачность, что и прямоугольник, чтобы перекрывающуюся часть круга не было видно. Моя функция наложения 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);

Может ли кто-нибудь помочь мне решить проблему? Благодарю.

РЕДАКТИРОВАТЬ: так выглядит после использования этих двух функций наложения.
введите описание изображения здесь

0

Решение

Я вижу, к чему вы клоните, и, видя свой результат, вам, вероятно, нужно только отключить смешивание, пока вы рисуете маску (3 прямоугольника и 4 круга), а затем использовать glBlendFunc(GL_DST_ALPHA, GL_ZERO), Хотя это будет работать только в том случае, если на сцене уже ничего не нарисовано.

Чтобы объяснить, что вы сделали, вы рисуете белый цвет с .5 альфа и смешиваете его.
Рассмотрим в начале, что цвет пикселя «destination» равен (0,0,0,0), а входящий «source» всегда в вашем случае (1,1,1, .5). Допустим, исходный цвет — «S», а назначение — «D», а компоненты — (r, g, b, a), поэтому исходная альфа — «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)

в результате альфа-разница. Поэтому из этого я надеюсь, что вы можете понять, что означают 2 параметра в функции смешивания: первый говорит, какой коэффициент использовать для умножения исходного (входящего) цвета, а второй — как умножить целевой цвет. В итоге они складываются вместе.

Так что для вашего случая вы хотели бы заставить альфа-канал принимать какое-то значение везде, где вы рисуете эти примитивы. Для этого вам понадобится S*1.0 + D*.0 и параметры для этого glBlendFunc(GL_ONE, GL_ZERO)хотя это то же самое, что просто отключить смесь. Только написание этого примитива приведет к получению белого (серого) скругленного прямоугольника с прозрачностью .5 в то время как все остальное полностью прозрачно. Теперь после этого вам нужно установить функцию смешивания, чтобы умножить ваш входящий цвет с целевым альфа glBlendFunc(GL_DST_ALPHA, GL_ZERO),

РЕДАКТИРОВАТЬ:

Я не совсем понял, чего ты хочешь достичь до сих пор. Как я упоминал выше, это не будет работать, если у вас уже нарисована сцена.

Чтобы наложить существующую сцену на некоторый сложный объект (в этом случае объект перекрывает себя на некоторых частях), было бы наиболее пуленепробиваемым использовать трафаретный буфер. Создание его очень похоже на буфер глубины, но вы можете рассматривать его как другой цветовой канал, его легко нарисовать, а затем использовать, так что вы можете захотеть посмотреть на него в какой-то момент.

В вашем случае, вероятно, можно с уверенностью сказать, что это ваш основной буфер и предназначен для отображения. В этом случае вы можете просто использовать альфа-канал:

Чтобы рисовать только на альфа-канал, вы должны установить glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE) и когда вы закончите, установите все параметры в true.

  1. Чтобы очистить альфа-канал, вы должны нарисовать полноэкранный прямоугольник с некоторым цветом с желаемым альфа (я предлагаю вам использовать (1,1,1,1)) и рисовать только на альфа-канал
  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 должна была бы создать еще один буфер кадра и прикрепить к нему текстуру, нарисовать на нем весь объект метки, а затем использовать связанную текстуру, чтобы нарисовать его на главном экране.

1

Другие решения

Других решений пока нет …