Я заметил, что некоторые разработчики OpenGL испытывают проблемы с тем, как WebGL обрабатывает альфа-канал в буфере кадров (т.е. в canvas), поэтому я подумал, что было бы полезно рассмотреть некоторые различия между WebGL и OpenGL, связанные с альфа-каналом.
Самое большое различие между OpenGL и WebGL заключается в том, что OpenGL рендерит в буфер кадров, который не композируется ни с чем, или эффективно не композируется с чем-либо оконным менеджером ОС, поэтому не важно, какое у вас значение альфа.
WebGL композируется браузером с веб-страницей, и
по умолчанию используется предварительно умноженный альфа-канал, так же как в тегах <img>
с прозрачностью и 2D canvas тегах.
WebGL имеет несколько способов сделать это более похожим на OpenGL.
gl = canvas.getContext("webgl2", {
premultipliedAlpha: false // Запросить непредварительно умноженный альфа-канал
});
По умолчанию это true.
Конечно, результат все равно будет композироваться со страницей с любым цветом фона, который окажется под canvas (цвет фона canvas, цвет фона контейнера canvas, цвет фона страницы, содержимое за canvas, если у canvas z-index > 0, и т.д…) другими словами, цвет, который CSS определяет для этой области веб-страницы.
Очень хороший способ найти проблемы с альфа-каналом - установить фон canvas ярким цветом, например красным. Вы сразу увидите, что происходит.
<canvas style="background: red;"><canvas>
Вы также можете установить его черным, что скроет любые проблемы с альфа-каналом.
gl = canvas.getContext("webgl", { alpha: false }};
Это сделает его более похожим на OpenGL, поскольку буфер кадров будет содержать только RGB. Это, вероятно, лучший вариант, потому что хороший браузер может увидеть, что у вас нет альфа-канала, и фактически оптимизировать способ композиции WebGL. Конечно, это также означает, что в буфере кадров действительно не будет альфа-канала, поэтому если вы используете альфа-канал в буфере кадров для какой-то цели, это может не сработать для вас. Мало приложений, которые я знаю, используют альфа-канал в буфере кадров. Я думаю, что это должно было быть по умолчанию.
..
renderScene();
..
// Установите альфа-канал буфера кадров в 1.0, установив
// цвет очистки в 1
gl.clearColor(1, 1, 1, 1);
// Сказать WebGL воздействовать только на альфа-канал
gl.colorMask(false, false, false, true);
// очистить
gl.clear(gl.COLOR_BUFFER_BIT);
Очистка обычно очень быстрая, так как в большинстве оборудования есть специальный случай для этого. Я делал это во многих своих первых WebGL демо. Если бы я был умным, я бы переключился на метод #2 выше. Может быть, я сделаю это сразу после публикации этого. Кажется, что большинство WebGL библиотек должны по умолчанию использовать этот метод. Те немногие разработчики, которые действительно используют альфа-канал для эффектов композиции, могут запросить его. Остальные просто получат лучшую производительность и меньше сюрпризов.
// Во время инициализации. Очистите буфер кадров.
gl.clearColor(1,1,1,1);
gl.clear(gl.COLOR_BUFFER_BIT);
// Отключите рендеринг в альфа-канал
gl.colorMask(true, true, true, false);
Конечно, если вы рендерите в свои собственные framebuffer’ы, вам может понадобиться включить рендеринг в альфа-канал обратно, а затем отключить его снова, когда вы переключитесь на рендеринг в canvas.
По умолчанию, если вы загружаете изображения с альфа-каналом в WebGL, WebGL будет предоставлять значения такими, как они есть в файле, с цветовыми значениями, не предварительно умноженными. Это обычно то, к чему я привык для программ OpenGL, потому что это без потерь, тогда как предварительно умноженный - с потерями.
1, 0.5, 0.5, 0 // RGBA
Это возможное непредварительно умноженное значение, тогда как предварительно умноженное - это
невозможное значение, потому что a = 0
, что означает, что r
, g
, и b
должны
быть нулевыми.
При загрузке изображения вы можете заставить WebGL предварительно умножить альфа-канал, если хотите.
Вы делаете это, устанавливая UNPACK_PREMULTIPLY_ALPHA_WEBGL
в true, как здесь:
gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);
По умолчанию это непредварительно умноженный.
Имейте в виду, что большинство, если не все, реализации Canvas 2D работают с
предварительно умноженным альфа-каналом. Это означает, что когда вы передаете их в WebGL и
UNPACK_PREMULTIPLY_ALPHA_WEBGL
равно false, WebGL преобразует их обратно в непредварительно умноженные.
Почти все приложения OpenGL, которые я писал или над которыми работал, используют
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
Это работает для текстур с непредварительно умноженным альфа-каналом.
Если вы действительно хотите работать с текстурами с предварительно умноженным альфа-каналом, то вероятно вам нужно
gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
Это методы, о которых я знаю. Если вы знаете больше, пожалуйста, опубликуйте их ниже.