В этом посте я расскажу о кратком введении в WebGL для всех, кто хочет начать работу с трехмерной веб-графикой. Я объясню, как работает конвейер рендеринга, и в качестве примера мы отрендерим простую графику.

Что такое WebGL

WebGL - это кроссплатформенный бесплатный API, используемый для создания трехмерной графики в веб-браузере. Основанный на OpenGL ES 2.0, WebGL использует язык затенения OpenGL, GLSL, и предлагает привычный стандарт OpenGL API.

Основные особенности WebGL следующие:

  • Кроссплатформенность и кроссбраузерность
  • 3D-ускорение на GPU
  • Собственный API с поддержкой GLSL
  • Работает внутри холста
  • Интеграция с DOM-интерфейсами

Как это работает

Для рендеринга графики нам нужно будет узнать, что такое конвейер рендеринга и как он работает.

Конвейер рендеринга - это последовательность этапов, которые WebGL выполняет при рендеринге 3D-графики. Эта модель рендеринга подходит правильно, поскольку графический процессор является высокопараллельным процессором: этапы конвейера выполняются одновременно в процессорах графического процессора.

На следующем изображении мы видим этапы конвейера рендеринга:

Выходные данные этапа используются в качестве входных данных для следующего этапа и т. Д. Этапы Вершинный шейдер и Фрагментный шейдер являются программируемыми, поэтому мы можем запрограммировать свои собственные.

Вершинный шейдер обрабатывает вершины нашей графики. На этом этапе мы должны предоставить поток с вершинами. Затем вершинный шейдер получает одну вершину из этого потока и генерирует одну вершину для выходного потока вершин. Должно быть отображение 1: 1 от входных вершин к выходным вершинам. Это этап, на котором мы можем применять преобразования вершин, такие как вращения, перемещения или масштабирование.

Фрагментный шейдер обрабатывает Фрагмент, сгенерированный на этапе Растеризация, в набор цветов и одно значение глубины. Это этап после растеризации примитива (на этапе растеризации геометрические примитивы преобразуются во фрагменты, относящиеся к области пикселей). Для каждой выборки пикселей, охватываемых примитивом, создается фрагмент. Каждый фрагмент имеет позицию Window Space, несколько других значений и содержит все интерполированные выходные значения для каждой вершины из последнего этапа Vertex Processing. Это этап, на котором мы можем применить цвета или текстуры к графике.

В следующем разделе мы увидим, как в качестве примера отрендерить простой треугольник. Для этого мы запрограммируем вершинный шейдер и шейдер Fragmend.

Отрисовка треугольника в WebGL

Как мы уже говорили, нам нужно будет определить холст для рендеринга нашей графики внутри него, поэтому мы создадим простой HTML-шаблон, подобный следующему:

Атрибуты width и height холста определяют размер области просмотра, но есть одно соображение, которое мы должны принять во внимание: WebGL ожидает, что все вершины, которые мы хотим сделать видимыми, будут в нормализованных координатах устройства после каждого запуска вершинного шейдера. То есть координаты x, y и z каждой вершины должны находиться между значениями -1.0 и 1.0; координаты вне этого диапазона не будут видны. Эти нормализованные координаты устройства и размер области просмотра затем передаются растеризатору для преобразования их в 2D-координаты / пиксели на вашем экране, поэтому мы должны позаботиться о том, чтобы учесть размер области просмотра и его соотношение сторон.

Мы будем использовать квадратный холст, чтобы упростить этот пример. Нам нужно будет определить три вершины, чтобы образовать треугольник, как мы можем видеть на следующем изображении:

В разделе скрипта мы сначала объявим массив вершин:

Мы должны пропустить z координату, так как мы рисуем в 2D.

Затем мы инициализируем контекст и сначала определим вершинный шейдер:

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

Теперь определим фрагментный шейдер:

Здесь мы используем униформу, которая содержит цвет фрагмента (униформы - это значения, которые остаются одинаковыми для всех вершин одного вызова отрисовки). Так же, как и вершинный шейдер, встроенная переменная gl_FragColor содержит выходной цвет шейдера. Как мы видим, преобразования цветов не производятся.

Наконец, мы скомпилируем эти шейдеры, чтобы GPU мог их запускать, и определим программу WebGL, присоединяющую к ней эти шейдеры:

После того, как мы определили и скомпилировали эти шейдеры, мы должны предоставить входные данные нашего треугольника.

Сначала мы создадим буфер массива и заполним его координатами вершин. Вершинный шейдер, который мы определили ранее, будет использовать этот буфер в качестве входных данных через атрибут position. Для этого мы создаем буфер с помощью метода gl.createBuffer и привязываем его как тип gl.ARRAY_BUFFER. Затем мы заполняем этот буфер данными с помощью метода gl.bufferData. Наконец, мы указываем атрибут позиции на буфер и привязываем его, вызывая методы gl.vertexAttribPointer и gl.enableVertexAttribArray соответственно:

Теперь мы определим цвет с помощью метода gl.uniform4f и передадим его во фрагментный шейдер через цветовую форму:

Обратите внимание, что цветовые координаты должны быть определены с использованием нормализованных координат устройства, поэтому мы вычисляем каждую координату по следующей формуле: RGBA normalized coordinate = RGBA coordinate / 255.

На данный момент у нас есть все, что нужно для рендеринга треугольника. Затем мы очищаем фон холста и визуализируем треугольник, вызывая метод gl.drawArrays:

Метод gl.drawArrays использует буфер ограниченного массива в качестве входных данных. В этом примере три вершины берутся из буфера, и для визуализации формы выбран режим gl.TRIANGLES. В WebGL доступны следующие формы:

Как видите, мы можем визуализировать каркас нашего треугольника, просто заменив режим значением gl.LINE_LOOP.

Наконец, мы видим треугольник, открывающий шаблон в веб-браузере. Примерно так :)

Подводя итоги

В настоящее время API WebGL доступен в большинстве веб-браузеров. Мы можем использовать его для рендеринга ускоренной 2D- и 3D-графики в наших веб-приложениях. Некоторые высокоуровневые библиотеки построены на основе WebGL API, что упрощает работу программиста. Однако интересно узнать о низкоуровневом API WebGL и о том, как работает конвейер рендеринга.

В будущих публикациях мы увидим, как визуализировать 3D-фигуры и как применять некоторые преобразования, такие как поворот или перевод. Также мы увидим, как применять текстуры, и рассмотрим некоторые интересные библиотеки, которые работают поверх WebGL.