Смешивание с фоном HTML в WebGL

Я рисую плоские цвета и текстуры на холсте WebGL. Мои цвета и текстуры имеют разные альфа-значения, и я хочу, чтобы они правильно смешивались. Я хочу иметь прозрачный фон (они должны быть смешаны с содержимым HTML, которое находится под холстом).

В WebGL я использую

gl.clearColor(0, 0, 0, 0);
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
gl.enable(gl.BLEND);

Работает правильно, когда фон HTML черный. Но когда я устанавливаю шаблон JPG в качестве фона, я рисую черный треугольник (альфа = 1) и белый треугольник (альфа = 0,5), я вижу фоновый узор в том месте, где треугольники пересекаются. Это правильное поведение?


person Ivan Kuckir    schedule 17.07.2012    source источник


Ответы (1)


gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA) означает, что результирующая альфа

A_final = A_s * A_s + (1 - A_s) * A_d

В вашем примере после рисования черного треугольника (с альфа = 1) у нарисованного пикселя в буфере кадра будет альфа, равная

1 * 1 + (1 - 1) * 0 == 1 + 0 == 1

Так он будет полностью непрозрачным. Затем, после рисования белого треугольника (с альфа = 0,5), пиксель на пересечении двух треугольников будет иметь альфа

.5 * .5 + (1 - .5) * 1 == .25 + .5 == .75

Это означает, что окончательный цвет будет рассматриваться как частично прозрачный, и, когда он совмещен со страницей, будет виден фон страницы.

Это несколько необычная проблема в обычном OpenGL, поскольку контент обычно создается на пустом фоне. Однако это возникает, когда вы рисуете в FBO и должны объединять результаты с другим контентом в вашем контексте. Есть несколько способов справиться с этим.

Один из способов - смешать альфа-канал с gl.ONE, gl.ONE_MINUS_SRC_ALPHA, чтобы получить

A_final = A_s + (1 - A_s) * A_d

это то, что вы обычно хотите с альфа-смешиванием. Однако вы хотите, чтобы ваши цвета по-прежнему смешивались с gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA. Вместо gl.blendFunc для настройте функции смешивания цветов и альфа-смешивания отдельно. В этом случае вы бы позвонили

gl.BlendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA);

Другой вариант - использовать цвета с предварительно умноженным альфа-каналом (который на самом деле уже предполагает вы используете, например, при выборке цвета из текстуры). Если вы нарисуете второй треугольник с альфа-каналом, уже умноженным на цвет (таким образом, для полупрозрачного белого треугольника gl_FragColor будет установлено значение vec4(.5, .5, .5, .5)), вы можете использовать режим наложения.

gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA)

и он будет действовать так, как вы хотите, как для цвета, так и для альфа-канала.

Второй вариант - это то, что вы обычно видите в примерах WebGL, поскольку (как уже упоминалось), WebGL уже предполагает, что ваши цвета предварительно умножены (так что vec4(1., 1., 1., .5) выходит за пределы гаммы, вывод рендеринга не определен, а драйвер / графический процессор может выводить любые сумасшедшие цвет он хочет). Гораздо чаще встречается gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA) в обычных примерах OpenGL, что приводит к некоторой путанице.

person Brendan Kenny    schedule 18.07.2012
comment
Спасибо большое, вы молодцы! :) Решил использовать gl.blendFuncSeparate (). Я попытался использовать предварительное умножение альфы, но это выглядит странно, потому что мои текстуры не умножаются предварительно. Я использую gl.texImage2D (gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, bd.image); ? Как я могу поменять его на предварительно умноженный? - person Ivan Kuckir; 19.07.2012
comment
По умолчанию текстуры при загрузке не умножаются за вас. Чтобы браузер автоматически умножал цвета на альфа-канал при импорте текстуры, вам необходимо установить параметр текстуры перед вызовом texImage2D. Таким образом, вы должны позвонить gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true); до того, как texImage2D вызовет список, указанный выше. См. Примечание о параметрах хранения пикселей в спецификации WebGL: khronos.org/registry/ webgl / specs / latest / - person Brendan Kenny; 24.07.2012