Мы уже рассказывали о том, как применить эффекты к изображениям при помощи canvas-фильтров и svg-фильтров. Давайте продолжим эту тему и рассмотрим webGl, как один из способов решать задачи фильтрации изображений в браузере.
WebGl — это браузерный API, наследующий принципы OpenGl и позволяющий использовать все прелести графического процессора (GPU) в браузере. Применимо к нашей задаче, основное достоинство WebGl — параллельная обработка всех пискелей изображения. В отличиие от Canvas, нам не нужно последовательно в цикле проходить по всему изображению и производить вычисления для каждого пикселя.
Дело в том, что у GPU (графического процессора), в отличие от CPU (центрального процессора), есть десятки тысяч ядер, которые могут работать параллельно.
Вот хорошее старое видео, наглядно поясняющее разницу в производительности между GPU и CPU.
разница в производительности между GPU и CPU.
Таким образом, используя WebGL для фильтрации изображений, мы отдаем каждый пиксель изображения отдельному ядру GPU, которое обрабатывает его по определенным нами законам. А законы эти описываются вот такими, на первый взгляд страшными кусками кода:
wtf?
precision mediump float;
varying vec2 position;
uniform sampler2D webcam;
void main() {
vec2 pos = position;
vec4 color = texture2D(webcam, pos);
color.rgb = 1.0 - color.rgb;
gl_FragColor = color;
}
Кто-нибудь знает, что это такое?
Правильно!
Это шейдер — кусок кода, соответствующий синтаксису GLSL (OpenGL Shading Language), который описывает алгоритм обработки каждого пикселя в GPU.
Шейдеры бывают:
- Векторными (Vertex Shaders) для работы с вершинами и полигонами в 3D.
- Пиксельными (Fragment Shaders) для работы с текстурами.
В рамках задачи фильтрации изображений нас будут интересовать только пиксельные шейдеры.
Не нужно бояться шейдеров.
Давайте избавимся от страха перед синтаксисом и уточним, что вышеописанный шейдер всего лишь инвертирует изображение. Вся его суть заключена в этой строчке:
color.rgb = 1.0 - color.rgb;
Весь остальной код — объявление переменных, описание источника изображения и значений на выходе.
Вот несколько особенностей языка GLSL:
- Все значения находятся в диапазоне 0..1
- GLSL позволяет получить доступ к компонентам векторов с помощью букв
x
,y
,z
,w
иr
,g
,b
,a
. Таким образом, для двумерного изображения (vec2) можно использоватьpos.x
,pos.y
. Для цвета (vec4) можно использоватьcolor.r
,color.g
,color.b
,color.a
- GLSL поддерживает сокращенные записи. Например,
color.rgb
(работа сразу с красным, зеленым и синим каналом),color.rа
(только красный канал и канал прозрачности) и т.д. Это просто приятный синтаксический сахар. Запись
color.rgb = 1 - color.rgb;
аналогична записи
color.r = 1 - color.r; color.g = 1 - color.g; color.b = 1 - color.b;
- Большинство функций GLSL может работать с несколькими типами входных параметров (float, vec2, vec3 и vec4).
- Отладка GLSL — нелегкая задача, однако JS консоль Chroma довольно подробно сообщает об ошибках и указывает на строку шейдера, которая вызывает проблему.
A куда этот шейдер писать?
Вот здесь я могу точно сказать: не изобретайте собственный велосипед. WebGl имеет довольно высокий порог вхождения. Он призван решать задачи, на порядок сложнее фильтрации 2D изображений. Вы потратите много драгоценного времени на настройку и установку сцены, прежде чем сумеете применить тот самый шейдер. Это чем-то похоже на убивание мухи из пулемета.
Гораздо проще и приятнее использовать готовые библиотеки для фильтрации изображеий на основе WebGL. Давайте рассмотрим некоторые из них
Библиотеки
GLFX
GLFX — готовая библиотека, работающая с шейдерами для фильтрации 2D изображений.
- Демо: evanw.github.io/glfx.js/demo/
- Исходники на гитхабе: github.com/evanw/glfx.js
- Документация: evanw.github.io/glfx.js/docs/
js
var canvas = fx.canvas();
// convert the image to a texture
var image = document.getElementById('image');
var texture = canvas.texture(image);
// apply the ink filter
canvas.draw(texture)
.sepia(0.34)
.brightnessContrast(0.5, -0.5)
.ink(0.25)
.update();
Достоинства библиотеки glfx:
- Красивый jQuery-подобный API с цепочками преобразований.
- Возможность расширять библиотеку своими шейдерами.
WebGLImageFilter
WebGLImageFilter — красивая библиотека для фильтрации 2D изображений на базе WebGl с множеством предустановленных шейдеров.
- Демо: phoboslab.org/log/2013/11/fast-image-filters-with-webgl
- Исходники на гитхабе: github.com/phoboslab/WebGLImageFilter
WebGLImageFilter прост в использовании:
js
var filter = new WebGLImageFilter();
filter.addFilter('hue', 180);
filter.addFilter('negative');
filter.addFilter('blur', 7);
var filteredImage = filter.apply(inputImage);
Достоинства библиотеки WebGLImageFilter:
- Красивый и понятный API.
- Множество предустановленных фильтров.
Достоинства фильтрации изображений с WebGL
- Очень, очень, очень быстро.
- Есть несколько хороших плагинов.
- Можно использовать готовые шейдеры написаные на языке GLSL для OpenGL за последние 14 лет (начиная c 2001 года)
- Возможно использовать для живых видео-стримов.
Недостатки фильтрации изображений с WebGL
- Для нестандартных операций порог входа достаточно высок.
- Неполная поддержка webgl браузерами (в особенности мобильными):
svg-filters поддержка браузерами
В заключение
Фильтрация изображений при помощи шейдеров составляет ооочень малую часть возможностей WebGl. Нужно сказать, что он решает эту задачу на все 100%.
Да, WebGl все еще слабо поддерживается браузерами. Однако, его можно и нужно начинать использовать при работе с графикой. Разве это не мечта — обладать всеми возможностями графической карты в веб-приложениях?
Добавить комментарий