Содержание

WebGL2Fundamentals.org

Fix, Fork, Contribute

WebGL2 и альфа-канал

Я заметил, что некоторые разработчики OpenGL испытывают проблемы с тем, как WebGL обрабатывает альфа-канал в буфере кадров (т.е. в canvas), поэтому я подумал, что было бы полезно рассмотреть некоторые различия между WebGL и OpenGL, связанные с альфа-каналом.

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

WebGL композируется браузером с веб-страницей, и по умолчанию используется предварительно умноженный альфа-канал, так же как в тегах <img> с прозрачностью и 2D canvas тегах.

WebGL имеет несколько способов сделать это более похожим на OpenGL.

#1) Скажите WebGL, что вы хотите композицию с непредварительно умноженным альфа-каналом

gl = canvas.getContext("webgl2", {
  premultipliedAlpha: false  // Запросить непредварительно умноженный альфа-канал
});

По умолчанию это true.

Конечно, результат все равно будет композироваться со страницей с любым цветом фона, который окажется под canvas (цвет фона canvas, цвет фона контейнера canvas, цвет фона страницы, содержимое за canvas, если у canvas z-index > 0, и т.д…) другими словами, цвет, который CSS определяет для этой области веб-страницы.

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

<canvas style="background: red;"><canvas>

Вы также можете установить его черным, что скроет любые проблемы с альфа-каналом.

#2) Скажите WebGL, что вы не хотите альфа-канал в буфере кадров

gl = canvas.getContext("webgl", { alpha: false }};

Это сделает его более похожим на OpenGL, поскольку буфер кадров будет содержать только RGB. Это, вероятно, лучший вариант, потому что хороший браузер может увидеть, что у вас нет альфа-канала, и фактически оптимизировать способ композиции WebGL. Конечно, это также означает, что в буфере кадров действительно не будет альфа-канала, поэтому если вы используете альфа-канал в буфере кадров для какой-то цели, это может не сработать для вас. Мало приложений, которые я знаю, используют альфа-канал в буфере кадров. Я думаю, что это должно было быть по умолчанию.

#3) Очистите альфа-канал в конце рендеринга

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

#4) Очистите альфа-канал один раз, затем не рендерите в него больше

// Во время инициализации. Очистите буфер кадров.
gl.clearColor(1,1,1,1);
gl.clear(gl.COLOR_BUFFER_BIT);

// Отключите рендеринг в альфа-канал
gl.colorMask(true, true, true, false);

Конечно, если вы рендерите в свои собственные framebuffer’ы, вам может понадобиться включить рендеринг в альфа-канал обратно, а затем отключить его снова, когда вы переключитесь на рендеринг в canvas.

#5) Обработка изображений

По умолчанию, если вы загружаете изображения с альфа-каналом в 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 преобразует их обратно в непредварительно умноженные.

#6) Использование уравнения смешивания, которое работает с предварительно умноженным альфа-каналом.

Почти все приложения OpenGL, которые я писал или над которыми работал, используют

gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);

Это работает для текстур с непредварительно умноженным альфа-каналом.

Если вы действительно хотите работать с текстурами с предварительно умноженным альфа-каналом, то вероятно вам нужно

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

Это методы, о которых я знаю. Если вы знаете больше, пожалуйста, опубликуйте их ниже.

Есть предложения или замечания? Создайте issue на GitHub.
comments powered by Disqus