Учебники

WebGL — Краткое руководство

WebGL — Введение

Несколько лет назад Java-приложения — как комбинация апплетов и JOGL — использовались для обработки 3D-графики в Интернете посредством обращения к графическому процессору (GPU). Поскольку для запуска апплетов требуется JVM, стало трудно полагаться на апплеты Java. Несколько лет спустя люди перестали использовать Java-апплеты.

API Stage3D, предоставляемые Adobe (Flash, AIR), предлагают аппаратно-ускоренную архитектуру графического процессора. Используя эти технологии, программисты могут разрабатывать приложения с возможностями 2D и 3D в веб-браузерах, а также на платформах IOS и Android. Поскольку Flash был проприетарным программным обеспечением, он не использовался в качестве веб-стандарта.

В марте 2011 года был выпущен WebGL. Это openware, который может работать без JVM. Он полностью контролируется веб-браузером.

Новый выпуск HTML 5 имеет несколько функций для поддержки 3D-графики, таких как 2D Canvas, WebGL, SVG, 3D CSS-преобразования и SMIL. В этом уроке мы расскажем об основах WebGL.

Что такое OpenGL?

OpenGL (Open Graphics Library) — это кросс-языковой, кроссплатформенный API для 2D и 3D графики. Это коллекция команд. OpenGL4.5 — это последняя версия OpenGL. В следующей таблице приведен список технологий, связанных с OpenGL.

API Используемая технология
OpenGL ES Это библиотека для 2D и 3D графики во встроенных системах, включая консоли, телефоны, бытовые приборы и транспортные средства. OpenGL ES 3.1 — это его последняя версия. Поддерживается Группой Хронос www.khronos.org
JOGL Это Java-привязка для OpenGL. JOGL 4.5 является его последней версией и поддерживается jogamp.org.
WebGL Это привязка JavaScript для OpenGL. WebGL 1.0 является его последней версией и поддерживается группой khronos .
OpenGLSL OpenGL Shading Language . Это язык программирования, который является дополнением к OpenGL 2.0 и выше. Это часть базовой спецификации OpenGL 4.4. Это API, специально разработанный для встраиваемых систем, таких как те, что присутствуют на мобильных телефонах и планшетах.

Примечание. В WebGL мы используем GLSL для написания шейдеров.

Что такое WebGL?

WebGL (библиотека веб-графики) — это новый стандарт 3D-графики в Интернете. Он предназначен для визуализации 2D-графики и интерактивной 3D-графики. Он взят из библиотеки OpenGL ES 2.0, которая представляет собой низкоуровневый 3D API для телефонов и других мобильных устройств. WebGL обеспечивает аналогичную функциональность ES 2.0 (встраиваемые системы) и хорошо работает на современном оборудовании 3D-графики.

Это JavaScript API, который можно использовать с HTML5. Код WebGL написан в теге <canvas> HTML5. Это спецификация, которая позволяет интернет-браузерам получать доступ к графическим процессорам (GPU) на тех компьютерах, где они использовались.

Кто разработал WebGL

Американско-сербский инженер-программист по имени Владимир Вукичевич сделал фундаментную работу и возглавил создание WebGL

  • В 2007 году Владимир начал работать над прототипом OpenGL для элемента Canvas HTML-документа.

  • В марте 2011 года Kronos Group создала WebGL.

В 2007 году Владимир начал работать над прототипом OpenGL для элемента Canvas HTML-документа.

В марте 2011 года Kronos Group создала WebGL.

Rendering

Рендеринг — это процесс генерации изображения из модели с использованием компьютерных программ. В графике виртуальная сцена описывается с использованием такой информации, как геометрия, точка обзора, текстура, освещение и затенение, которая передается через программу рендеринга. Результатом этой программы рендеринга будет цифровое изображение.

Существует два типа рендеринга:

  • Программное обеспечение рендеринга — все расчеты рендеринга выполняются с помощью процессора.

  • Аппаратный рендеринг. Все графические вычисления выполняются графическим процессором (GPU).

Программное обеспечение рендеринга — все расчеты рендеринга выполняются с помощью процессора.

Аппаратный рендеринг. Все графические вычисления выполняются графическим процессором (GPU).

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

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

GPU

Согласно NVIDIA, GPU — это «однокристальный процессор с интегрированным преобразованием, освещением, настройкой / отсечкой треугольников и механизмами рендеринга, способный обрабатывать не менее 10 миллионов полигонов в секунду». В отличие от многоядерных процессоров с несколькими ядрами, оптимизированными для последовательной обработки, графический процессор состоит из тысяч меньших ядер, которые эффективно обрабатывают параллельные рабочие нагрузки. Следовательно, графический процессор ускоряет создание изображений в буфере кадров (часть оперативной памяти, которая содержит полные данные кадра), предназначенной для вывода на дисплей.

CPU и GPU

GPU Ускоренные вычисления

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

GPU Ускоренные вычисления

У GPU будет отдельная память, и он будет запускать несколько копий небольшой части кода за раз. Графический процессор обрабатывает все данные, которые находятся в его локальной памяти, а не в центральной памяти. Следовательно, данные, которые должны обрабатываться графическим процессором, должны быть загружены / скопированы в память графического процессора и затем обработаны.

В системах, имеющих вышеуказанную архитектуру, коммуникационные издержки между CPU и GPU должны быть уменьшены для достижения более быстрой обработки 3D-программ. Для этого нам нужно скопировать все данные и сохранить их на графическом процессоре, вместо того, чтобы повторно связываться с ним.

Поддерживаемые браузеры

В следующих таблицах показан список браузеров, поддерживающих WebGL.

Веб-браузеры

Название браузера Версия Служба поддержки
Я нтернет е xplorer 11 и выше Полная поддержка
Гугл Хром 39 и выше Полная поддержка
Сафари 8 Полная поддержка
Fire Fox 36 и выше Частичная поддержка
опера 27 и выше Частичная поддержка

Мобильные браузеры

Название браузера Версия Служба поддержки
Chrome для Android 42 Частичная поддержка
Android-браузер 40 Частичная поддержка
IOS Safari 8,3 Полная поддержка
опера мини 8 Не поддерживается
Blackberry Browser 10 Полная поддержка
IE мобильный 10 Частичная поддержка

Преимущества WebGL

Вот преимущества использования WebGL —

  • Программирование на JavaScript — приложения WebGL написаны на JavaScript. Используя эти приложения, вы можете напрямую взаимодействовать с другими элементами документа HTML. Вы также можете использовать другие библиотеки JavaScript (например, JQuery) и технологии HTML, чтобы обогатить приложение WebGL.

  • Расширение поддержки с мобильными браузерами — WebGL также поддерживает мобильные браузеры, такие как iOS Safari, Android Browser и Chrome для Android.

  • Открытый исходный код — WebGL является открытым исходным кодом. Вы можете получить доступ к исходному коду библиотеки и понять, как она работает и как она была разработана.

  • Нет необходимости в компиляции — JavaScript является компонентом полупрограммирования и полу-HTML. Для выполнения этого скрипта нет необходимости компилировать файл. Вместо этого вы можете напрямую открыть файл с помощью любого из браузеров и проверить результат. Поскольку приложения WebGL разрабатываются с использованием JavaScript, также нет необходимости компилировать приложения WebGL.

  • Автоматическое управление памятью — JavaScript поддерживает автоматическое управление памятью. Нет необходимости в ручном распределении памяти. WebGL наследует эту особенность JavaScript.

  • Простота настройки — поскольку WebGL интегрирован в HTML 5, дополнительная настройка не требуется. Чтобы написать приложение WebGL, все, что вам нужно, это текстовый редактор и веб-браузер.

Программирование на JavaScript — приложения WebGL написаны на JavaScript. Используя эти приложения, вы можете напрямую взаимодействовать с другими элементами документа HTML. Вы также можете использовать другие библиотеки JavaScript (например, JQuery) и технологии HTML, чтобы обогатить приложение WebGL.

Расширение поддержки с мобильными браузерами — WebGL также поддерживает мобильные браузеры, такие как iOS Safari, Android Browser и Chrome для Android.

Открытый исходный код — WebGL является открытым исходным кодом. Вы можете получить доступ к исходному коду библиотеки и понять, как она работает и как она была разработана.

Нет необходимости в компиляции — JavaScript является компонентом полупрограммирования и полу-HTML. Для выполнения этого скрипта нет необходимости компилировать файл. Вместо этого вы можете напрямую открыть файл с помощью любого из браузеров и проверить результат. Поскольку приложения WebGL разрабатываются с использованием JavaScript, также нет необходимости компилировать приложения WebGL.

Автоматическое управление памятью — JavaScript поддерживает автоматическое управление памятью. Нет необходимости в ручном распределении памяти. WebGL наследует эту особенность JavaScript.

Простота настройки — поскольку WebGL интегрирован в HTML 5, дополнительная настройка не требуется. Чтобы написать приложение WebGL, все, что вам нужно, это текстовый редактор и веб-браузер.

Настройка среды

Нет необходимости устанавливать другую среду для WebGL. Браузеры, поддерживающие WebGL, имеют свои собственные встроенные настройки для WebGL.

WebGL — Html5 Обзор холста

Для создания графических приложений в Интернете HTML-5 предоставляет богатый набор функций, таких как 2D Canvas, WebGL, SVG, 3D CSS-преобразования и SMIL. Для написания приложений WebGL мы используем существующий элемент canvas HTML-5. В этой главе дается обзор HTML-5 2D элемента canvas.

HTML5 Canvas

HTML-5 <canvas> предоставляет простой и мощный параметр для рисования графики с использованием JavaScript. Его можно использовать для рисования графиков, создания фото-композиций или создания простых (и не очень простых) анимаций.

Вот простой элемент <canvas>, имеющий только два определенных атрибута width и height плюс все основные атрибуты HTML-5, такие как id, name и class.

Синтаксис

Синтаксис тега HTML canvas приведен ниже. Вы должны упомянуть название холста внутри двойных кавычек («»).

<canvas id = "mycanvas" width = "100" height = "100"></canvas>

Атрибуты холста

У тега canvas есть три атрибута, а именно: id, ширина и высота.

  • Id — Id представляет идентификатор элемента холста в объектной модели документа (DOM) .

  • Ширина — Ширина представляет ширину холста.

  • Высота — Высота представляет высоту холста.

Id — Id представляет идентификатор элемента холста в объектной модели документа (DOM) .

Ширина — Ширина представляет ширину холста.

Высота — Высота представляет высоту холста.

Эти атрибуты определяют размер холста. Если программист не указывает их в теге canvas, тогда браузеры, такие как Firefox, Chrome и Web Kit, по умолчанию предоставляют элемент canvas размером 300 × 150.

Пример — создание холста

Следующий код показывает, как создать холст. Мы использовали CSS, чтобы придать холсту цветную рамку.

Live Demo

<html>
   <head>
      <style>
         #mycanvas{border:1px solid red;}
      </style>
   </head>
   <body>
      <canvas id = "mycanvas" width = "100" height = "100"></canvas>
   </body>
</html>

При выполнении приведенный выше код выдаст следующий вывод:

Контекст рендеринга

<Canvas> изначально пуст. Чтобы отобразить что-то на элементе canvas, мы должны использовать язык сценариев. Этот язык сценариев должен получить доступ к контексту рендеринга и использовать его.

Элемент canvas имеет метод DOM с именем getContext () , который используется для получения контекста рендеринга и его функций рисования. Этот метод принимает один параметр, тип контекста 2d .

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

Live Demo

<!DOCTYPE HTML>
<html>
   <body>
      <canvas id = "mycanvas" width = "600" height = "200"></canvas>

      <script>
         var canvas = document.getElementById('mycanvas');
         var context = canvas.getContext('2d');
			
         context.font = '20pt Calibri';
         context.fillStyle = 'green';
         context.fillText('Welcome to Tutorialspoint', 70, 70);
      </script>
   </body>
</html>

При выполнении приведенный выше код выдаст следующий вывод:

Более подробный пример HTML-5 2D Canvas можно найти по следующей ссылке HTML-5 Canvas .

WebGL Context

HTML5 Canvas также используется для написания приложений WebGL. Для создания контекста рендеринга WebGL в элементе canvas вы должны передать строчку экспериментальный-webgl вместо 2d в метод canvas.getContext () . Некоторые браузеры поддерживают только « webgl ».

Live Demo

<!DOCTYPE html>
<html>
   <canvas id = 'my_canvas'></canvas>
	
   <script>
      var canvas = document.getElementById('my_canvas');
      var gl = canvas.getContext('experimental-webgl');
      gl.clearColor(0.9,0.9,0.8,1);
      gl.clear(gl.COLOR_BUFFER_BIT);
   </script>
</html>

При выполнении приведенный выше код выдаст следующий вывод:

WebGL — Основы

WebGL — это в основном API-интерфейс растрирования низкого уровня, а не 3D-API. Чтобы нарисовать изображение с помощью WebGL, вы должны передать вектор, представляющий изображение. Затем он преобразует данный вектор в пиксельный формат с использованием OpenGL SL и отображает изображение на экране. Написание приложения WebGL включает в себя ряд шагов, которые мы объясним в этой главе.

WebGL — система координат

Как и в любой другой 3D-системе, в WebGL будут оси x, y и z, где ось z означает глубину . Координаты в WebGL ограничены (1, 1, 1) и (-1, -1, — 1). Это означает — если вы рассматриваете экран, проецирующий графику WebGL как куб, то один угол куба будет (1, 1, 1), а противоположный угол будет (-1, -1, -1). WebGL не будет отображать ничего, что нарисовано за этими границами.

Следующая диаграмма изображает систему координат WebGL. Ось Z обозначает глубину. Положительное значение z указывает, что объект находится рядом с экраном / средством просмотра, тогда как отрицательное значение z указывает, что объект находится вне экрана. Аналогично, положительное значение x указывает, что объект находится с правой стороны экрана, а отрицательное значение указывает, что объект находится с левой стороны. Аналогично, положительные и отрицательные значения y указывают, находится ли объект в верхней или нижней части экрана.

Система координат WebGL

WebGL Graphics

Получив контекст WebGL объекта canvas, вы можете начать рисовать графические элементы с помощью API WebGL в JavaScript.

Вот некоторые фундаментальные термины, которые вам необходимо знать перед началом работы с WebGL.

вершины

Обычно для рисования таких объектов, как многоугольник, мы отмечаем точки на плоскости и соединяем их, чтобы сформировать нужный многоугольник. Вершина — это точка, которая определяет соединение ребер трехмерного объекта. Он представлен тремя значениями с плавающей запятой, каждое из которых представляет оси x, y, z соответственно.

пример

В следующем примере мы рисуем треугольник со следующими вершинами — (0,5, 0,5), (-0,5, 0,5), (-0,5, -0,5).

Пример вершин

Примечание. Мы должны хранить эти вершины вручную, используя массивы JavaScript, и передавать их в конвейер рендеринга WebGL, используя буфер вершин.

индексы

В WebGL числовые значения используются для идентификации вершин. Эти числовые значения известны как индексы. Эти индексы используются для рисования сеток в WebGL.

индексы

Примечание. Как и вершины, мы храним индексы с помощью массивов JavaScript и передаем их в конвейер рендеринга WebGL с помощью буфера индекса.

Массивы

В отличие от OpenGL и JoGL, в WebGL нет предопределенных методов для прямой визуализации вершин. Мы должны хранить их вручную, используя массивы JavaScript.

пример

var vertices = [ 0.5, 0.5, 0.1,-0.5, 0.5,-0.5] 

Буферы

Буферы — это области памяти WebGL, в которых хранятся данные. Существуют различные буферы, а именно: буфер рисования, буфер кадров, буфер ветекса и буфер индекса. Буфер вершин и индексный буфер используются для описания и обработки геометрии модели.

Объекты буфера вершин хранят данные о вершинах, а объекты буфера индексов хранят данные об индексах. После сохранения вершин в массивах мы передаем их в графический конвейер WegGL, используя эти объекты Buffer.

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

меш

Для рисования 2D или 3D объектов API WebGL предоставляет два метода, а именно drawArrays () и drawElements () . Эти два метода принимают параметр с именем mode, с помощью которого вы можете выбрать объект, который хотите нарисовать. Параметры, предоставляемые этим полем, ограничены точками, линиями и треугольниками.

Чтобы нарисовать трехмерный объект, используя эти два метода, мы должны построить один или несколько примитивных полигонов, используя точки, линии или треугольники. После этого, используя эти примитивные многоугольники, мы можем сформировать сетку.

Трехмерный объект, нарисованный с использованием примитивных многоугольников, называется сеткой . WebGL предлагает несколько способов рисования трехмерных графических объектов, однако пользователи обычно предпочитают рисовать меш.

пример

В следующем примере вы можете заметить, что мы нарисовали квадрат, используя два треугольника → {1, 2, 3} и {4, 1, 3}.

Пример сетки

Шейдерные программы

Мы обычно используем треугольники для построения сеток. Поскольку в WebGL используются ускоренные вычисления на GPU, информация об этих треугольниках должна передаваться с CPU на GPU, что требует больших затрат на связь.

WebGL предоставляет решение для снижения накладных расходов на связь. Поскольку он использует ES SL (Embedded System Shader Language), который работает на GPU, мы пишем все необходимые программы для рисования графических элементов в клиентской системе с помощью шейдерных программ (программ, которые мы пишем с использованием OpenGL ES Shading Language / GLSL ).

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

Короче говоря, это фрагмент кода, который реализует алгоритмы для получения пикселей для меша. Мы обсудим больше о шейдерах в следующих главах. Существует два типа шейдеров — Vertex Shader и Fragment Shader.

Вершинный шейдер

Шейдер Vertext — это программный код, который вызывается для каждой вершины. Он используется для преобразования (перемещения) геометрии (например, треугольник) из одного места в другое. Он обрабатывает данные каждой вершины (данные для каждой вершины), такие как координаты вершины, нормали, цвета и координаты текстуры.

В коде вершинного шейдера ES GL программисты должны определить атрибуты для обработки данных. Эти атрибуты указывают на объект буфера вершин, написанный на JavaScript.

Следующие задачи могут быть выполнены с использованием вершинных шейдеров —

  • Преобразование вершин
  • Нормальное преобразование и нормализация
  • Генерация координат текстуры
  • Преобразование координат текстуры
  • Осветительные приборы
  • Применение цветного материала

Фрагментный шейдер (Pixel Shader)

Сетка состоит из нескольких треугольников, а поверхность каждого из треугольников называется фрагментом . Фрагментный шейдер — это код, который выполняется на всех пикселях каждого фрагмента. Он написан для расчета и заливки цвета на отдельных пикселях .

Следующие задачи могут быть выполнены с помощью шейдеров фрагментов —

  • Операции с интерполированными значениями
  • Доступ к текстуре
  • Нанесение текстур
  • Туман
  • Цветовая сумма

Фрагмент шейдера

Переменные OpenGL ES SL

Полной формой OpenGL ES SL является язык затенения OpenGL Embedded System. Для обработки данных в шейдерных программах ES SL предоставляет три типа переменных. Они заключаются в следующем —

  • Атрибуты — эти переменные содержат входные значения программы вершинного шейдера. Атрибуты указывают на объекты буфера вершин, которые содержат данные для каждой вершины. Каждый раз, когда вызывается вершинный шейдер, атрибуты указывают на VBO разных вершин.

  • Униформа — эти переменные содержат входные данные, общие для вершинных и фрагментных шейдеров, такие как положение света, координаты текстуры и цвет.

  • Изменения — эти переменные используются для передачи данных из вершинного шейдера в фрагментный шейдер.

Атрибуты — эти переменные содержат входные значения программы вершинного шейдера. Атрибуты указывают на объекты буфера вершин, которые содержат данные для каждой вершины. Каждый раз, когда вызывается вершинный шейдер, атрибуты указывают на VBO разных вершин.

Униформа — эти переменные содержат входные данные, общие для вершинных и фрагментных шейдеров, такие как положение света, координаты текстуры и цвет.

Изменения — эти переменные используются для передачи данных из вершинного шейдера в фрагментный шейдер.

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

WebGL — графический конвейер

Для рендеринга 3D-графики мы должны выполнить последовательность шагов. Эти шаги известны как графический конвейер или конвейер рендеринга . Следующая диаграмма изображает графический конвейер WebGL.

Графический конвейер

В следующих разделах мы обсудим один за другим роль каждого шага в конвейере.

JavaScript

При разработке приложений WebGL мы пишем код языка шейдеров для связи с графическим процессором. JavaScript используется для написания контрольного кода программы, который включает в себя следующие действия:

  • Инициализировать WebGL — JavaScript используется для инициализации контекста WebGL.

  • Создать массивы — мы создаем массивы JavaScript для хранения данных геометрии.

  • Буферные объекты — мы создаем буферные объекты (вершины и индексы), передавая массивы в качестве параметров.

  • Шейдеры — мы создаем, компилируем и связываем шейдеры, используя JavaScript.

  • Атрибуты — мы можем создавать атрибуты, включать их и связывать их с объектами буфера, используя JavaScript.

  • Униформа — Мы также можем связать униформу, используя JavaScript.

  • Матрица преобразования. Используя JavaScript, мы можем создать матрицу преобразования.

Инициализировать WebGL — JavaScript используется для инициализации контекста WebGL.

Создать массивы — мы создаем массивы JavaScript для хранения данных геометрии.

Буферные объекты — мы создаем буферные объекты (вершины и индексы), передавая массивы в качестве параметров.

Шейдеры — мы создаем, компилируем и связываем шейдеры, используя JavaScript.

Атрибуты — мы можем создавать атрибуты, включать их и связывать их с объектами буфера, используя JavaScript.

Униформа — Мы также можем связать униформу, используя JavaScript.

Матрица преобразования. Используя JavaScript, мы можем создать матрицу преобразования.

Сначала мы создаем данные для требуемой геометрии и передаем их шейдерам в виде буферов. Переменная атрибута языка шейдеров указывает на объекты буфера, которые передаются в качестве входных данных в вершинный шейдер.

Вершинный шейдер

Когда мы запускаем процесс рендеринга, вызывая методы drawElements () и drawArray () , вершинный шейдер выполняется для каждой вершины, предоставленной в объекте буфера вершин. Он вычисляет положение каждой вершины примитивного многоугольника и сохраняет ее в переменной gl_position . Он также вычисляет другие атрибуты, такие как цвет, координаты текстуры и вершины , которые обычно связаны с вершиной.

Примитивная Ассамблея

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

растеризации

На этапе растеризации определяются пиксели в конечном изображении примитива. У этого есть два шага —

  • Отбор — вначале определяется ориентация (передняя или задняя сторона?) Многоугольника. Все те треугольники с неправильной ориентацией, которые не видны в области обзора, отбрасываются. Этот процесс называется выбраковкой.

  • Отсечение — если треугольник частично находится за пределами области просмотра, то часть вне области просмотра удаляется. Этот процесс известен как отсечение.

Отбор — вначале определяется ориентация (передняя или задняя сторона?) Многоугольника. Все те треугольники с неправильной ориентацией, которые не видны в области обзора, отбрасываются. Этот процесс называется выбраковкой.

Отсечение — если треугольник частично находится за пределами области просмотра, то часть вне области просмотра удаляется. Этот процесс известен как отсечение.

Фрагмент шейдера

Фрагмент шейдера попадает

  • данные из вершинного шейдера в переменных переменных,
  • примитивы со стадии растеризации, а затем
  • вычисляет значения цвета для каждого пикселя между вершинами.

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

Фрагмент Операции

Операции фрагмента выполняются после определения цвета каждого пикселя в примитиве. Эти операции фрагмента могут включать следующее:

  • глубина
  • Смесь цветовых буферов
  • Смешение

Как только все фрагменты обработаны, 2D изображение формируется и отображается на экране. Буфер кадра является конечным пунктом назначения конвейера рендеринга.

Фрагмент Операции

Кадровый буфер

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

WebGL — пример приложения

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

Структура приложения WebGL

Код приложения WebGL представляет собой сочетание JavaScript и языка шейдеров OpenGL.

  • JavaScript необходим для связи с процессором
  • OpenGL Shader Language необходим для связи с GPU.

Структура приложения WebGL

Образец заявки

Теперь давайте возьмем простой пример, чтобы узнать, как использовать WebGL для рисования простого треугольника с 2D-координатами.

Live Demo

<!doctype html>
<html>
   <body>
      <canvas width = "300" height = "300" id = "my_Canvas"></canvas>
		
      <script>
         /* Step1: Prepare the canvas and get WebGL context */

         var canvas = document.getElementById('my_Canvas');
         var gl = canvas.getContext('experimental-webgl');

         /* Step2: Define the geometry and store it in buffer objects */

         var vertices = [-0.5, 0.5, -0.5, -0.5, 0.0, -0.5,];

         // Create a new buffer object
         var vertex_buffer = gl.createBuffer();

         // Bind an empty array buffer to it
         gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
         
         // Pass the vertices data to the buffer
         gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);

         // Unbind the buffer
         gl.bindBuffer(gl.ARRAY_BUFFER, null);

         /* Step3: Create and compile Shader programs */

         // Vertex shader source code
         var vertCode =
            'attribute vec2 coordinates;' + 
            'void main(void) {' + ' gl_Position = vec4(coordinates,0.0, 1.0);' + '}';

         //Create a vertex shader object
         var vertShader = gl.createShader(gl.VERTEX_SHADER);

         //Attach vertex shader source code
         gl.shaderSource(vertShader, vertCode);

         //Compile the vertex shader
         gl.compileShader(vertShader);

         //Fragment shader source code
         var fragCode = 'void main(void) {' + 'gl_FragColor = vec4(0.0, 0.0, 0.0, 0.1);' + '}';

         // Create fragment shader object
         var fragShader = gl.createShader(gl.FRAGMENT_SHADER);

         // Attach fragment shader source code
         gl.shaderSource(fragShader, fragCode);

         // Compile the fragment shader
         gl.compileShader(fragShader);

         // Create a shader program object to store combined shader program
         var shaderProgram = gl.createProgram();

         // Attach a vertex shader
         gl.attachShader(shaderProgram, vertShader); 
         
         // Attach a fragment shader
         gl.attachShader(shaderProgram, fragShader);

         // Link both programs
         gl.linkProgram(shaderProgram);

         // Use the combined shader program object
         gl.useProgram(shaderProgram);

         /* Step 4: Associate the shader programs to buffer objects */

         //Bind vertex buffer object
         gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);

         //Get the attribute location
         var coord = gl.getAttribLocation(shaderProgram, "coordinates");

         //point an attribute to the currently bound VBO
         gl.vertexAttribPointer(coord, 2, gl.FLOAT, false, 0, 0);

         //Enable the attribute
         gl.enableVertexAttribArray(coord);

         /* Step5: Drawing the required object (triangle) */

         // Clear the canvas
         gl.clearColor(0.5, 0.5, 0.5, 0.9);

         // Enable the depth test
         gl.enable(gl.DEPTH_TEST); 
         
         // Clear the color buffer bit
         gl.clear(gl.COLOR_BUFFER_BIT);

         // Set the view port
         gl.viewport(0,0,canvas.width,canvas.height);

         // Draw the triangle
         gl.drawArrays(gl.TRIANGLES, 0, 3);
      </script>
   </body>
</html>

Это даст следующий результат —

Если вы внимательно наблюдаете вышеуказанную программу, мы выполнили пять последовательных шагов, чтобы нарисовать простой треугольник с помощью WebGL. Шаги следующие:

Шаг 1 — Подготовьте холст и получите контекст рендеринга WebGL

Мы получаем текущий HTML-объект canvas и получаем его контекст рендеринга WebGL.

Шаг 2 — Определите геометрию и сохраните ее в буферных объектах

Мы определяем атрибуты геометрии, такие как вершины, индексы, цвет и т. Д., И сохраняем их в массивах JavaScript. Затем мы создаем один или несколько буферных объектов и передаем массивы, содержащие данные, в соответствующий буферный объект. В этом примере мы сохраняем вершины треугольника в массиве JavaScript и передаем этот массив объекту буфера вершин.

Шаг 3 — Создание и компиляция шейдерных программ

Мы пишем программы вершинного шейдера и фрагментного шейдера, компилируем их и создаем объединенную программу, связывая эти две программы.

Шаг 4 — Связать шейдерные программы с объектами буфера

Мы связываем объекты буфера и комбинированную шейдерную программу.

Шаг 5 — Рисуем нужный объект (треугольник)

Этот шаг включает в себя такие операции, как очистка цвета, очистка буфера, включение теста глубины, настройка порта просмотра и т. Д. Наконец, вам нужно нарисовать необходимые примитивы с помощью одного из методов — drawArrays () или drawElements () .

Все эти шаги объяснены далее в этом уроке.

WebGL — Контекст

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

  • Создать холст HTML-5
  • Получить идентификатор холста
  • Получить WebGL

Создание HTML-5 Canvas Element

В главе 5 мы обсуждали, как создать элемент холста HTML-5. В теле документа HTML-5 напишите холст, дайте ему имя и передайте его в качестве параметра идентификатору атрибута. Вы можете определить размеры холста, используя атрибуты width и height (необязательно).

пример

В следующем примере показано, как создать элемент canvas с размерами 500 × 500. Мы создали границу для холста, используя CSS для наглядности. Скопируйте и вставьте следующий код в файл с именем my_canvas.html .

Live Demo

<!DOCTYPE HTML>
<html>
   <head>
      <style>
         #mycanvas{border:1px solid blue;}
      </style>
   </head>
   <body>
      <canvas id = "mycanvas" width = "300" height = "300"></canvas>
   </body>
</html>

Это даст следующий результат —

Получить идентификатор холста

После создания холста вы должны получить контекст WebGL. Первое, что нужно сделать, чтобы получить контекст рисования WebGL, — это получить идентификатор текущего элемента canvas.

Идентификатор холста получается путем вызова метода getElementById () из DOM (объектной модели документа ) . Этот метод принимает строковое значение в качестве параметра, поэтому мы передаем ему имя текущего холста.

Например, если имя холста — my_canvas , то идентификатор холста получается, как показано ниже.

var canvas = document.getElementById('my_Canvas');

Получить контекст рисования WebGL

Чтобы получить объект WebGLRenderingContext (или объект контекста рисования WebGL, или просто контекст WebGL), вызовите метод getContext () текущего HTMLCanvasElement . Синтаксис getContext () выглядит следующим образом:

canvas.getContext(contextType, contextAttributes);

Передайте строки webgl или экспериментальный-webgl как contentType . Параметр contextAttributes является необязательным. (Продолжая этот шаг, убедитесь, что в вашем браузере реализована версия 1 WebGL (OpenGL ES 2.0)).

В следующем фрагменте кода показано, как получить контекст рендеринга WebGL. Здесь gl — ссылочная переменная для полученного объекта контекста.

var canvas = document.getElementById('my_Canvas');
var gl = canvas.getContext('experimental-webgl');

WebGLContextAttributes

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

Sr.No. Атрибуты и описание
1

Альфа

Если его значение равно true, он обеспечивает альфа-буфер для холста.

По умолчанию его значение равно true.

2

глубина

Если его значение равно true, вы получите буфер рисования, который содержит буфер глубины не менее 16 бит.

По умолчанию его значение равно true.

3

трафарет

Если его значение равно true, вы получите буфер рисования, который содержит буфер трафарета не менее 8 бит.

По умолчанию его значение равно false.

4

Сглаживание

Если его значение равно true, вы получите буфер рисования, который выполняет сглаживание.

По умолчанию его значение равно true.

5

premultipliedAlpha

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

По умолчанию его значение равно true.

6

preserveDrawingBuffer

Если его значение равно true, буферы не будут очищены и будут сохранять свои значения до тех пор, пока автор не очистит или не перезаписает их.

По умолчанию его значение равно false.

Альфа

Если его значение равно true, он обеспечивает альфа-буфер для холста.

По умолчанию его значение равно true.

глубина

Если его значение равно true, вы получите буфер рисования, который содержит буфер глубины не менее 16 бит.

По умолчанию его значение равно true.

трафарет

Если его значение равно true, вы получите буфер рисования, который содержит буфер трафарета не менее 8 бит.

По умолчанию его значение равно false.

Сглаживание

Если его значение равно true, вы получите буфер рисования, который выполняет сглаживание.

По умолчанию его значение равно true.

premultipliedAlpha

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

По умолчанию его значение равно true.

preserveDrawingBuffer

Если его значение равно true, буферы не будут очищены и будут сохранять свои значения до тех пор, пока автор не очистит или не перезаписает их.

По умолчанию его значение равно false.

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

var canvas = document.getElementById('canvas1');
var context = canvas.getContext('webgl', { antialias: false, stencil: true });

Во время создания WebGLRenderingContext создается буфер рисования. Объект Context управляет состоянием OpenGL и выполняет рендеринг в буфер чертежа.

WebGLRenderingContext

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

Sr.No. Атрибуты и описание
1

холст

Это ссылка на элемент canvas, который создал этот контекст.

2

drawingBufferWidth

Этот атрибут представляет фактическую ширину буфера рисования. Он может отличаться от атрибута ширины HTMLCanvasElement.

3

drawingBufferHeight

Этот атрибут представляет фактическую высоту буфера рисования. Он может отличаться от атрибута высоты объекта HTMLCanvasElement.

холст

Это ссылка на элемент canvas, который создал этот контекст.

drawingBufferWidth

Этот атрибут представляет фактическую ширину буфера рисования. Он может отличаться от атрибута ширины HTMLCanvasElement.

drawingBufferHeight

Этот атрибут представляет фактическую высоту буфера рисования. Он может отличаться от атрибута высоты объекта HTMLCanvasElement.

WebGL — геометрия

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

Примечание. Позже эти объекты буфера будут связаны с атрибутами программы шейдера (вершинный шейдер).

Определение необходимой геометрии

2D или 3D модель, нарисованная с использованием вершин, называется сеткой . Каждый фасет в сетке называется многоугольником, а многоугольник состоит из 3 или более вершин.

Чтобы нарисовать модели в контексте рендеринга WebGL, вы должны определить вершины и индексы, используя массивы JavaScript. Например, если мы хотим создать треугольник, который лежит на координатах {(5,5), (-5,5), (-5, -5)}, как показано на диаграмме, то вы можете создать массив для вершины как —

var vertices = [
   0.5,0.5,    //Vertex 1
   0.5,-0.5,   //Vertex 2
   -0.5,-0.5,  //Vertex 3
]; 

Геометрия

Точно так же вы можете создать массив для индексов. Индексы для вышеуказанных индексов треугольника будут [0, 1, 2] и могут быть определены как —

var indices = [ 0,1,2 ]

Для лучшего понимания индексов рассмотрим более сложные модели, такие как квадрат. Мы можем представить квадрат в виде набора из двух треугольников. Если (0,3,1) и (3,1,2) — это два треугольника, с помощью которых мы собираемся нарисовать квадрат, то индексы будут определены как —

var indices = [0,3,1,3,1,2];

Пример геометрии

Примечание

Для рисования примитивов WebGL предоставляет следующие два метода:

  • drawArrays () — при использовании этого метода мы передаем вершины примитива, используя массивы JavaScript.

  • drawElements () — при использовании этого метода мы передаем и вершины, и индексы примитива, используя массив JavaScript.

drawArrays () — при использовании этого метода мы передаем вершины примитива, используя массивы JavaScript.

drawElements () — при использовании этого метода мы передаем и вершины, и индексы примитива, используя массив JavaScript.

Буферные объекты

Буферный объект — это механизм, предоставляемый WebGL, который указывает область памяти, выделенную в системе. В этих буферных объектах вы можете хранить данные модели, которую вы хотите нарисовать, соответствующие вершинам, индексам, цвету и т. Д.

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

Для обработки геометрии существует два типа буферных объектов. Они —

  • Буферный объект вершины (VBO) — содержит данные для каждой вершины графической модели, которая будет отображаться. Мы используем объекты буфера вершин в WebGL для хранения и обработки данных о вершинах, таких как координаты вершин, нормали, цвета и координаты текстуры.

  • Индексные буферные объекты (IBO). Содержит индексы (индексные данные) графической модели, которая будет отображаться.

Буферный объект вершины (VBO) — содержит данные для каждой вершины графической модели, которая будет отображаться. Мы используем объекты буфера вершин в WebGL для хранения и обработки данных о вершинах, таких как координаты вершин, нормали, цвета и координаты текстуры.

Индексные буферные объекты (IBO). Содержит индексы (индексные данные) графической модели, которая будет отображаться.

После определения необходимой геометрии и сохранения их в массивах JavaScript вам необходимо передать эти массивы в буферные объекты, откуда данные будут передаваться в шейдерные программы. Чтобы сохранить данные в буферах, необходимо выполнить следующие шаги.

  • Создайте пустой буфер.

  • Привязать соответствующий объект массива к пустому буферу.

  • Передайте данные (вершины / индексы) в буфер, используя один из типизированных массивов .

  • Отсоедините буфер (необязательно).

Создайте пустой буфер.

Привязать соответствующий объект массива к пустому буферу.

Передайте данные (вершины / индексы) в буфер, используя один из типизированных массивов .

Отсоедините буфер (необязательно).

Создание буфера

Чтобы создать пустой буферный объект, WebGL предоставляет метод с именем createBuffer () . Этот метод возвращает вновь созданный буферный объект, если создание было успешным; иначе он возвращает нулевое значение в случае сбоя.

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

var vertex_buffer = gl .createBuffer();

Примечаниеgl является ссылочной переменной для текущего контекста WebGL.

Привязать буфер

После создания пустого объекта буфера вам необходимо привязать к нему соответствующий буфер массива (целевой объект). Для этой цели WebGL предоставляет метод bindBuffer () .

Синтаксис

Синтаксис метода bindBuffer () следующий:

void bindBuffer (enum target, Object buffer)

Этот метод принимает два параметра, и они обсуждаются ниже.

target — первая переменная является значением enum, представляющим тип буфера, который мы хотим связать с пустым буфером. У вас есть два предопределенных значения перечисления в качестве опций для этого параметра. Они —

  • ARRAY_BUFFER, который представляет данные вершины.

  • ELEMENT_ARRAY_BUFFER, который представляет данные индекса.

ARRAY_BUFFER, который представляет данные вершины.

ELEMENT_ARRAY_BUFFER, который представляет данные индекса.

Буфер объекта — вторая является ссылочной переменной для объекта буфера, созданного на предыдущем шаге. Переменная-ссылка может быть объектом буфера вершин или объектом буфера индекса.

пример

В следующем фрагменте кода показано, как использовать метод bindBuffer ().

//vertex buffer
var vertex_buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);

//Index buffer
var Index_Buffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, index_buffer);

Передача данных в буфер

Следующим шагом является передача данных (вершин / индексов) в буфер. До сих пор данные представлены в виде массива, и прежде чем передавать их в буфер, нам нужно обернуть их в один из типизированных массивов WebGL. Для этой цели WebGL предоставляет метод с именем bufferData () .

Синтаксис

Синтаксис метода bufferData () следующий:

void bufferData (enum target, Object data, enum usage)

Этот метод принимает три параметра, и они обсуждаются ниже —

target — первый параметр — это значение enum, представляющее тип буфера массива, который мы использовали. Варианты этого параметра:

  • ARRAY_BUFFER, который представляет данные вершины .

  • ELEMENT_ARRAY_BUFFER, который представляет данные индекса .

ARRAY_BUFFER, который представляет данные вершины .

ELEMENT_ARRAY_BUFFER, который представляет данные индекса .

Данные объекта . Второй параметр — это значение объекта, которое содержит данные, которые должны быть записаны в буферный объект. Здесь мы должны передать данные, используя типизированные массивы .

Использование . Третьим параметром этого метода является переменная enum, которая определяет, как использовать данные объекта буфера (сохраненные данные) для рисования фигур. Для этого параметра есть три параметра, перечисленных ниже.

  • gl.STATIC_DRAW — Данные будут указаны один раз и использованы много раз.

  • gl.STREAM_DRAW — Данные будут указаны один раз и использованы несколько раз.

  • gl.DYNAMIC_DRAW — данные будут указываться многократно и использоваться многократно.

gl.STATIC_DRAW — Данные будут указаны один раз и использованы много раз.

gl.STREAM_DRAW — Данные будут указаны один раз и использованы несколько раз.

gl.DYNAMIC_DRAW — данные будут указываться многократно и использоваться многократно.

пример

В следующем фрагменте кода показано, как использовать метод bufferData () . Предположим, что вершины и индексы — это массивы, содержащие данные вершин и индексов соответственно.

//vertex buffer
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);

//Index buffer
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);

Типизированные массивы

WebGL предоставляет специальный тип массива, называемый типизированными массивами, для передачи элементов данных, таких как вершина индекса и текстура. Эти типизированные массивы хранят большие объемы данных и обрабатывают их в собственном двоичном формате, что приводит к повышению производительности. Типизированными массивами, используемыми в WebGL, являются Int8Array, Uint8Array, Int16Array, Uint16Array, Int32Array, UInt32Array, Float32Array и Float64Array.

Заметка

  • Как правило, для хранения данных вершин мы используем Float32Array ; и для хранения данных индекса мы используем Uint16Array .

  • Вы можете создавать типизированные массивы так же, как массивы JavaScript, используя новое ключевое слово.

Как правило, для хранения данных вершин мы используем Float32Array ; и для хранения данных индекса мы используем Uint16Array .

Вы можете создавать типизированные массивы так же, как массивы JavaScript, используя новое ключевое слово.

Уберите буферы

Рекомендуется открепить буферы после их использования. Это можно сделать, передав нулевое значение вместо объекта буфера, как показано ниже.

gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);

WebGL предоставляет следующие методы для выполнения операций с буфером:

Sr.No. Методы и описание
1

void bindBuffer ( цель перечисления, буфер объектов)

цель — ARRAY_BUFFER, ELEMENT_ARRAY_BUFFER

2

void bufferData ( цель enum, длинный размер , использование enum)

цель — ARRAY_BUFFER, ELEMENT_ARRAY_BUFFER

использование — STATIC_DRAW, STREAM_DRAW, DYNAMIC_DRAW

3

void bufferData ( цель перечисления, данные объекта, использование перечисления)

цель и использование — То же, что и для bufferData выше

4

void bufferSubData (enum target , long offset , Object data )

цель — ARRAY_BUFFER, ELEMENT_ARRAY_BUFFER

5 Объект createBuffer ()
6 void deleteBuffer ( Буфер объектов)
7

any getBufferParameter (enum target , enum pname )

цель — ARRAY_BUFFER, ELEMENT_ ARRAY_BUFFER

pname — BUFFER_SIZE, BUFFER_USAGE

8 bool isBuffer (объектный буфер )

void bindBuffer ( цель перечисления, буфер объектов)

цель — ARRAY_BUFFER, ELEMENT_ARRAY_BUFFER

void bufferData ( цель enum, длинный размер , использование enum)

цель — ARRAY_BUFFER, ELEMENT_ARRAY_BUFFER

использование — STATIC_DRAW, STREAM_DRAW, DYNAMIC_DRAW

void bufferData ( цель перечисления, данные объекта, использование перечисления)

цель и использование — То же, что и для bufferData выше

void bufferSubData (enum target , long offset , Object data )

цель — ARRAY_BUFFER, ELEMENT_ARRAY_BUFFER

any getBufferParameter (enum target , enum pname )

цель — ARRAY_BUFFER, ELEMENT_ ARRAY_BUFFER

pname — BUFFER_SIZE, BUFFER_USAGE

WebGL — шейдеры

Шейдеры — это программы, которые работают на GPU. Шейдеры написаны на OpenGL ES Shader Language (известный как ES SL). ES SL имеет свои собственные переменные, типы данных, классификаторы, встроенные входы и выходы.

Типы данных

В следующей таблице перечислены основные типы данных, предоставляемые OpenGL ES SL.

Sr.No. Тип и описание
1

недействительным

Представляет пустое значение.

2

BOOL

Принимает истину или ложь.

3

ИНТ

Это целочисленный тип данных со знаком.

4

поплавок

Это плавающий скалярный тип данных.

5

vec2, vec3, vec4

n-компонентный вектор с плавающей точкой

6

bvec2, bvec3, bvec4

Булево вектор

7

ivec2, ivec3, ivec4

целое число со знаком

8

мат2, мат3, мат4

Матрица с плавающей запятой 2×2, 3×3, 4×4

9

sampler2D

Доступ к 2D-текстуре

10

samplerCube

Доступ к текстуре с отображением куба

недействительным

Представляет пустое значение.

BOOL

Принимает истину или ложь.

ИНТ

Это целочисленный тип данных со знаком.

поплавок

Это плавающий скалярный тип данных.

vec2, vec3, vec4

n-компонентный вектор с плавающей точкой

bvec2, bvec3, bvec4

Булево вектор

ivec2, ivec3, ivec4

целое число со знаком

мат2, мат3, мат4

Матрица с плавающей запятой 2×2, 3×3, 4×4

sampler2D

Доступ к 2D-текстуре

samplerCube

Доступ к текстуре с отображением куба

Отборочные

В OpenGL ES SL есть три основных классификатора:

Sr.No. Квалификатор и описание
1

атрибут

Этот классификатор действует как связь между вершинным шейдером и OpenGL ES для данных на каждую вершину. Значение этого атрибута меняется при каждом выполнении вершинного шейдера.

2

единообразный

Этот классификатор связывает шейдерные программы и приложение WebGL. В отличие от квалификатора атрибута, значения униформ не меняются. Униформа только для чтения; Вы можете использовать их с любыми основными типами данных, чтобы объявить переменную.

Пример — равномерное vec4 lightPosition;

3

варьируя

Этот классификатор формирует связь между вершинным шейдером и фрагментным шейдером для интерполированных данных. Он может использоваться со следующими типами данных — float, vec2, vec3, vec4, mat2, mat3, mat4 или массивы.

Примервариация vec3 нормальная;

атрибут

Этот классификатор действует как связь между вершинным шейдером и OpenGL ES для данных на каждую вершину. Значение этого атрибута меняется при каждом выполнении вершинного шейдера.

единообразный

Этот классификатор связывает шейдерные программы и приложение WebGL. В отличие от квалификатора атрибута, значения униформ не меняются. Униформа только для чтения; Вы можете использовать их с любыми основными типами данных, чтобы объявить переменную.

Пример — равномерное vec4 lightPosition;

варьируя

Этот классификатор формирует связь между вершинным шейдером и фрагментным шейдером для интерполированных данных. Он может использоваться со следующими типами данных — float, vec2, vec3, vec4, mat2, mat3, mat4 или массивы.

Примервариация vec3 нормальная;

Вершинный шейдер

Вершинный шейдер — это программный код, который вызывается для каждой вершины. Он трансформирует (перемещает) геометрию (например, треугольник) из одного места в другое. Он обрабатывает данные каждой вершины (данные для каждой вершины), такие как координаты вершины, нормали, цвета и координаты текстуры.

В коде вершинного шейдера ES GL программисты должны определять атрибуты для обработки данных. Эти атрибуты указывают на объект буфера вершин, написанный на JavaScript. Следующие задачи могут быть выполнены с использованием вершинных шейдеров вместе с вершинным преобразованием —

  • Преобразование вершин
  • Нормальное преобразование и нормализация
  • Генерация координат текстуры
  • Преобразование координат текстуры
  • Осветительные приборы
  • Применение цветного материала

Предопределенные переменные

OpenGL ES SL предоставляет следующие предопределенные переменные для вершинного шейдера:

Sr.No. Переменные и описание
1

highp vec4 gl_Position;

Держит позицию вершины.

2

mediump float gl_PointSize;

Содержит преобразованный размер точки. Единицами этой переменной являются пиксели.

highp vec4 gl_Position;

Держит позицию вершины.

mediump float gl_PointSize;

Содержит преобразованный размер точки. Единицами этой переменной являются пиксели.

Образец кода

Взгляните на следующий пример кода вершинного шейдера. Обрабатывает вершины треугольника.

attribute vec2 coordinates;

void main(void) {
   gl_Position = vec4(coordinates, 0.0, 1.0);
};

Если вы внимательно наблюдаете приведенный выше код, мы объявили переменную атрибута с координатами имени. (Эта переменная будет связана с объектом буфера вершин с помощью метода getAttribLocation () . Координаты атрибута передаются в качестве параметра этому методу вместе с программным объектом шейдера.)

На втором шаге данной программы вершинного шейдера определяется переменная gl_position .

gl_Position

gl_Position — это предопределенная переменная, которая доступна только в программе вершинного шейдера. Содержит позицию вершины. В приведенном выше коде атрибуты координат передаются в виде вектора. Поскольку вершинный шейдер является операцией для каждой вершины, значение gl_position рассчитывается для каждой вершины.

Позже значение gl_position используется примитивной сборкой, отсечкой, отбраковкой и другими операциями с фиксированной функциональностью, которые работают с примитивами после завершения обработки вершины.

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

Фрагмент шейдера

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

  • Операции с интерполированными значениями
  • Доступ к текстуре
  • Нанесение текстур
  • Туман
  • Цветовая сумма

Предопределенные переменные

OpenGL ES SL предоставляет следующие предопределенные переменные для фрагментного шейдера:

Sr.No. Переменные и описание
1

mediump vec4 gl_FragCoord ;

Содержит позицию фрагмента в буфере кадра.

2

bool gl_FrontFacing;

Содержит фрагмент, принадлежащий переднему примитиву.

3

mediump vec2 gl_PointCoord;

Удерживает положение фрагмента внутри точки (только растеризация точки).

4

mediump vec4 gl_FragColor;

Содержит значение цвета выходного фрагмента шейдера

5

mediump vec4 gl_FragData [n]

Содержит цвет фрагмента для цветного вложения n .

mediump vec4 gl_FragCoord ;

Содержит позицию фрагмента в буфере кадра.

bool gl_FrontFacing;

Содержит фрагмент, принадлежащий переднему примитиву.

mediump vec2 gl_PointCoord;

Удерживает положение фрагмента внутри точки (только растеризация точки).

mediump vec4 gl_FragColor;

Содержит значение цвета выходного фрагмента шейдера

mediump vec4 gl_FragData [n]

Содержит цвет фрагмента для цветного вложения n .

Образец кода

В следующем примере кода фрагментного шейдера показано, как применить цвет к каждому пикселю в треугольнике.

void main(void) {
   gl_FragColor = vec4(0, 0.8, 0, 1);
}

В приведенном выше коде значение цвета хранится в переменной gl.FragColor . Программа фрагмента шейдера передает вывод в конвейер, используя фиксированные переменные функции; FragColor является одним из них. Эта переменная содержит значение цвета пикселей модели.

Хранение и компиляция шейдерных программ

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

var vertCode =
   'attribute vec2 coordinates;' +
	
   'void main(void) {' +
      ' gl_Position = vec4(coordinates, 0.0, 1.0);' +
   '}';

Компиляция шейдера

Компиляция включает следующие три шага —

  • Создание объекта шейдера
  • Прикрепление исходного кода к созданному объекту шейдера
  • Компиляция программы

Создание вершинного шейдера

Чтобы создать пустой шейдер, WebGL предоставляет метод с именем createShader () . Создает и возвращает шейдерный объект. Его синтаксис выглядит следующим образом —

Object createShader (enum type)

Как указано в синтаксисе, этот метод принимает предопределенное значение перечисления в качестве параметра. У нас есть два варианта для этого —

  • gl.VERTEX_SHADER для создания вершинного шейдера

  • gl.FRAGMENT_SHADER для создания фрагментного шейдера.

gl.VERTEX_SHADER для создания вершинного шейдера

gl.FRAGMENT_SHADER для создания фрагментного шейдера.

Присоединение источника к шейдеру

Вы можете присоединить исходный код к созданному объекту шейдера, используя метод shaderSource () . Его синтаксис выглядит следующим образом —

void shaderSource (Object shader, string source)

Этот метод принимает два параметра —

  • шейдер — Вы должны передать созданный объект шейдера как один параметр.

  • Исходный код — Вы должны передать программный код шейдера в строковом формате.

шейдер — Вы должны передать созданный объект шейдера как один параметр.

Исходный код — Вы должны передать программный код шейдера в строковом формате.

Компиляция программы

Чтобы скомпилировать программу, вы должны использовать метод compileShader () . Его синтаксис следующий:

compileShader(Object shader)

Этот метод принимает программный объект шейдера в качестве параметра. После создания объекта программы шейдера присоедините к нему исходный код и передайте этот объект этому методу.

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

// Vertex Shader
var vertCode =
   'attribute vec3 coordinates;' +
	
   'void main(void) {' +
      ' gl_Position = vec4(coordinates, 1.0);' +
   '}';

var vertShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertShader, vertCode);
gl.compileShader(vertShader);
 
// Fragment Shader
var fragCode =
   'void main(void) {' +
      ' gl_FragColor = vec4(0, 0.8, 0, 1);' +
   '}';

var fragShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragShader, fragCode);
gl.compileShader(fragShader);

Комбинированная программа

После создания и компиляции обеих программ шейдеров вам необходимо создать комбинированную программу, содержащую оба шейдера (вершина и фрагмент). Следующие шаги должны быть выполнены —

  • Создать программный объект
  • Присоедините оба шейдера
  • Связать оба шейдера
  • Используйте программу

Создать программный объект

Создайте программный объект с помощью метода createProgram () . Он вернет пустой программный объект. Вот его синтаксис —

createProgram();

Прикрепить шейдеры

Присоедините шейдеры к созданному программному объекту, используя метод attachShader () . Его синтаксис выглядит следующим образом —

attachShader (Object program , Object shader );

Этот метод принимает два параметра —

  • Программа — передать созданный пустой программный объект как один параметр.

  • Shader — пройти одну из программ скомпилированных шейдеров (вершинный шейдер, фрагментный шейдер)

Программа — передать созданный пустой программный объект как один параметр.

Shader — пройти одну из программ скомпилированных шейдеров (вершинный шейдер, фрагментный шейдер)

Примечание. С помощью этого метода необходимо подключить оба шейдера.

Связать шейдеры

Свяжите шейдеры, используя метод linkProgram () , передав объект программы, к которому вы прикрепили шейдеры. Его синтаксис выглядит следующим образом —

linkProgram(shaderProgram);

Используйте программу

WebGL предоставляет метод с именем useProgram () . Вы должны передать ему связанную программу. Его синтаксис выглядит следующим образом —

useProgram(shaderProgram);

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

var shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertShader);
gl.attachShader(shaderProgram, fragShader);
gl.linkProgram(shaderProgram);
gl.useProgram(shaderProgram); 

Связывание атрибутов и объектов буфера

Каждый атрибут в программе вершинного шейдера указывает на объект буфера вершин. После создания объектов буфера вершин программисты должны связать их с атрибутами программы вершинного шейдера. Каждый атрибут указывает только на один объект буфера вершин, из которого они извлекают значения данных, а затем эти атрибуты передаются в шейдерную программу.

Чтобы связать объекты Vertex Buffer с атрибутами программы вершинного шейдера, вы должны выполнить следующие шаги:

  • Получить атрибут местоположения
  • Укажите атрибут на объект буфера вершин
  • Включить атрибут

Получить местоположение атрибута

WebGL предоставляет метод getAttribLocation (), который возвращает местоположение атрибута. Его синтаксис выглядит следующим образом —

ulong getAttribLocation (Object program , string name )

Этот метод принимает программный объект вершинного шейдера и значения атрибутов программы вершинного шейдера.

В следующем фрагменте кода показано, как использовать этот метод.

var coordinatesVar = gl.getAttribLocation(shader_program, "coordinates"); 

Здесь shader_program является объектом программы шейдера, а координаты — атрибутом программы вершинного шейдера.

Укажите Атрибут для VBO

Чтобы назначить объект буфера переменной атрибута, WebGL предоставляет метод vertexAttribPointer () . Вот синтаксис этого метода —

void vertexAttribPointer ( location , int size , enum type , bool normalized , long stride , long offset )

Этот метод принимает шесть параметров, и они обсуждаются ниже.

  • Расположение — указывает место хранения переменной атрибута. При использовании этой опции вы должны передать значение, возвращаемое методом getAttribLocation () .

  • Размер — определяет количество компонентов на вершину в объекте буфера.

  • Тип — указывает тип данных.

  • Нормализовано — это логическое значение. Если true, неплавающие данные нормализуются до [0, 1]; в противном случае он нормализуется до [-1, 1].

  • Stride — указывает количество байтов между различными элементами данных вершины или ноль для шага по умолчанию.

  • Смещение — указывает смещение (в байтах) в объекте буфера, чтобы указать, из какого байта хранятся данные вершины. Если данные сохраняются с самого начала, смещение равно 0.

Расположение — указывает место хранения переменной атрибута. При использовании этой опции вы должны передать значение, возвращаемое методом getAttribLocation () .

Размер — определяет количество компонентов на вершину в объекте буфера.

Тип — указывает тип данных.

Нормализовано — это логическое значение. Если true, неплавающие данные нормализуются до [0, 1]; в противном случае он нормализуется до [-1, 1].

Stride — указывает количество байтов между различными элементами данных вершины или ноль для шага по умолчанию.

Смещение — указывает смещение (в байтах) в объекте буфера, чтобы указать, из какого байта хранятся данные вершины. Если данные сохраняются с самого начала, смещение равно 0.

Следующий фрагмент кода показывает, как использовать vertexAttribPointer () в программе:

gl.vertexAttribPointer(coordinatesVar, 3, gl.FLOAT, false , 0, 0);

Включение атрибута

Активируйте атрибут вершинного шейдера для доступа к объекту буфера в вершинном шейдере. Для этой операции WebGL предоставляет метод enableVertexAttribArray () . Этот метод принимает местоположение атрибута в качестве параметра. Вот как использовать этот метод в программе —

gl.enableVertexAttribArray(coordinatesVar); 

WebGL — рисование модели

После связывания буферов с шейдерами, последний шаг — нарисовать необходимые примитивы. WebGL предоставляет два метода, а именно drawArrays () и drawElements () для рисования моделей.

drawArrays ()

drawArrays () — это метод, который используется для рисования моделей с использованием вершин. Вот его синтаксис —

void drawArrays(enum mode, int first, long count)

Этот метод принимает следующие три параметра —

  • mode — в WebGL модели отрисовываются с использованием примитивных типов. Используя режим, программисты должны выбрать один из примитивных типов, предоставляемых WebGL. Возможные значения для этого параметра — gl.POINTS, gl.LINE_STRIP, gl.LINE_LOOP, gl.LINES, gl.TRIANGLE_STRIP, gl.TRIANGLE_FAN и gl.TRIANGLES.

  • first — эта опция указывает начальный элемент во включенных массивах. Это не может быть отрицательным значением.

  • count — эта опция указывает количество элементов для визуализации.

mode — в WebGL модели отрисовываются с использованием примитивных типов. Используя режим, программисты должны выбрать один из примитивных типов, предоставляемых WebGL. Возможные значения для этого параметра — gl.POINTS, gl.LINE_STRIP, gl.LINE_LOOP, gl.LINES, gl.TRIANGLE_STRIP, gl.TRIANGLE_FAN и gl.TRIANGLES.

first — эта опция указывает начальный элемент во включенных массивах. Это не может быть отрицательным значением.

count — эта опция указывает количество элементов для визуализации.

Если вы рисуете модель, используя метод drawArrays () , то WebGL, визуализируя фигуры, создает геометрию в порядке, в котором определены координаты вершины.

пример

Если вы хотите нарисовать один треугольник, используя метод drawArray () , то вам нужно передать три вершины и вызвать метод drawArrays () , как показано ниже.

var vertices = [-0.5,-0.5, -0.25,0.5, 0.0,-0.5,];
gl.drawArrays(gl.TRIANGLES, 0, 3);

Это создаст треугольник, как показано ниже.

Треугольник

Предположим, что вы хотите нарисовать смежные треугольники, тогда вы должны передать следующие три вершины по порядку в буфере вершин и указать количество элементов, которые должны быть визуализированы как 6.

var vertices = [-0.5,-0.5, -0.25,0.5, 0.0,-0.5, 0.0,-0.5, 0.25,0.5, 0.5,-0.5,];
gl.drawArrays(gl.TRIANGLES, 0, 6);

Это создаст смежный треугольник, как показано ниже.

Треугольник 1

drawElements ()

drawElements () — это метод, который используется для рисования моделей с использованием вершин и индексов. Его синтаксис выглядит следующим образом —

void drawElements (enum mode, long count, enum type, long offset)

Этот метод принимает следующие четыре параметра —

  • режим — модели WebGL отрисовываются с использованием примитивных типов. Используя режим, программисты должны выбрать один из примитивных типов, предоставляемых WebGL. Список возможных значений для этого параметра — gl.POINTS, gl.LINE_STRIP, gl.LINE_LOOP, gl.LINES, gl.TRIANGLE_STRIP, gl.TRIANGLE_FAN и gl.TRIANGLES.

  • count — эта опция указывает количество элементов для визуализации.

  • тип — эта опция указывает тип данных индексов, который должен быть UNSIGNED_BYTE или UNSIGNED_SHORT.

  • смещение — эта опция указывает начальную точку рендеринга. Обычно это первый элемент (0).

режим — модели WebGL отрисовываются с использованием примитивных типов. Используя режим, программисты должны выбрать один из примитивных типов, предоставляемых WebGL. Список возможных значений для этого параметра — gl.POINTS, gl.LINE_STRIP, gl.LINE_LOOP, gl.LINES, gl.TRIANGLE_STRIP, gl.TRIANGLE_FAN и gl.TRIANGLES.

count — эта опция указывает количество элементов для визуализации.

тип — эта опция указывает тип данных индексов, который должен быть UNSIGNED_BYTE или UNSIGNED_SHORT.

смещение — эта опция указывает начальную точку рендеринга. Обычно это первый элемент (0).

Если вы рисуете модель, используя метод drawElements () , тогда объект индексного буфера также должен быть создан вместе с объектом буфера вершин. Если вы используете этот метод, данные вершин будут обрабатываться один раз и использоваться столько раз, сколько указано в индексах.

пример

Если вы хотите нарисовать один треугольник, используя индексы, вам нужно передать индексы вместе с вершинами и вызвать метод drawElements (), как показано ниже.

var vertices = [ -0.5,-0.5,0.0, -0.25,0.5,0.0, 0.0,-0.5,0.0 ];
var indices = [0,1,2];

gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT,0);

Это даст следующий результат —

Треугольник

Если вы хотите нарисовать контагиозные треугольники, используя метод drawElements () , просто добавьте другие вершины и упомяните индексы для остальных вершин.

var vertices = [
   -0.5,-0.5,0.0,
   -0.25,0.5,0.0,
   0.0,-0.5,0.0,
   0.25,0.5,0.0,
   0.5,-0.5,0.0 
];

var indices = [0,1,2,2,3,4];

gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT,0);

Это даст следующий результат —

Треугольник 1

Требуемые операции

Прежде чем рисовать примитив, вам необходимо выполнить несколько операций, которые описаны ниже.

Очистить холст

Прежде всего, вы должны очистить холст, используя метод clearColor () . Вы можете передать значения RGBA нужного цвета в качестве параметра этому методу. Затем WebGL очищает холст и заполняет его указанным цветом. Поэтому вы можете использовать этот метод для установки цвета фона.

Посмотрите на следующий пример. Здесь мы передаем значение RGBA серого цвета.

gl.clearColor(0.5, 0.5, .5, 1);

Включить тест глубины

Включите проверку глубины, используя метод enable () , как показано ниже.

gl.enable(gl.DEPTH_TEST); 

Очистить бит буфера цвета

Очистите цвет, а также буфер глубины, используя метод clear () , как показано ниже.

gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

Установите порт просмотра

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

gl.viewport(0,0,canvas.width,canvas.height);

WebGL — точки рисования

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

Требуемые шаги

Следующие шаги необходимы для создания приложения WebGL для рисования точек.

Шаг 1. Подготовьте холст и получите контекст рендеринга WebGL

На этом шаге мы получаем объект контекста рендеринга WebGL, используя метод getContext ().

Шаг 2 — Определите геометрию и сохраните ее в буферных объектах

Поскольку мы рисуем три точки, мы определяем три вершины с трехмерными координатами и сохраняем их в буферах.

var vertices = [
   -0.5,0.5,0.0,
   0.0,0.5,0.0,
   -0.25,0.25,0.0, 
];

Шаг 3 — Создание и компиляция шейдерных программ

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

  • Вершинный шейдер — В вершинном шейдере данного примера мы определяем векторный атрибут для хранения трехмерных координат и присваиваем его переменной gl_position .

  • gl_pointsize — это переменная, используемая для назначения размера точке. Мы назначаем размер точки как 10.

Вершинный шейдер — В вершинном шейдере данного примера мы определяем векторный атрибут для хранения трехмерных координат и присваиваем его переменной gl_position .

gl_pointsize — это переменная, используемая для назначения размера точке. Мы назначаем размер точки как 10.

var vertCode = 'attribute vec3 coordinates;' +

   'void main(void) {' +
      ' gl_Position = vec4(coordinates, 1.0);' +
      'gl_PointSize = 10.0;'+
   '}';
  • Фрагментный шейдер — В фрагментном шейдере мы просто назначаем цвет фрагмента переменной gl_FragColor

Фрагментный шейдер — В фрагментном шейдере мы просто назначаем цвет фрагмента переменной gl_FragColor

var fragCode = 'void main(void) {' +' gl_FragColor = vec4(1, 0.5, 0.0, 1);' +'}';

Шаг 4 — Связать шейдерные программы для буферизации объектов

На этом этапе мы связываем объекты буфера с программой шейдера.

Шаг 5 — Рисование необходимого объекта

Мы используем метод drawArrays () для рисования точек. Поскольку количество точек, которые мы хотим нарисовать, равно трем, значение счетчика равно 3.

gl.drawArrays(gl.POINTS, 0, 3)

Пример — нарисуйте три точки, используя WebGL

Вот полная программа WebGL, чтобы нарисовать три точки —

Live Demo

<!doctype html>
<html>
   <body>
      <canvas width = "570" height = "570" id = "my_Canvas"></canvas>

      <script>
         /*================Creating a canvas=================*/
         var canvas = document.getElementById('my_Canvas');
         gl = canvas.getContext('experimental-webgl'); 

         /*==========Defining and storing the geometry=======*/

         var vertices = [
            -0.5,0.5,0.0,
            0.0,0.5,0.0,
            -0.25,0.25,0.0, 
         ];

         // Create an empty buffer object to store the vertex buffer
         var vertex_buffer = gl.createBuffer();

         //Bind appropriate array buffer to it
         gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);

         // Pass the vertex data to the buffer
         gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);

         // Unbind the buffer
         gl.bindBuffer(gl.ARRAY_BUFFER, null);

         /*=========================Shaders========================*/

         // vertex shader source code
         var vertCode =
            'attribute vec3 coordinates;' +

            'void main(void) {' +
               ' gl_Position = vec4(coordinates, 1.0);' +
               'gl_PointSize = 10.0;'+
            '}';

         // Create a vertex shader object
         var vertShader = gl.createShader(gl.VERTEX_SHADER);
         
         // Attach vertex shader source code
         gl.shaderSource(vertShader, vertCode);

         // Compile the vertex shader
         gl.compileShader(vertShader);

         // fragment shader source code
         var fragCode =
            'void main(void) {' +
               ' gl_FragColor = vec4(0.0, 0.0, 0.0, 0.1);' +
            '}';

         // Create fragment shader object
         var fragShader = gl.createShader(gl.FRAGMENT_SHADER);

         // Attach fragment shader source code
         gl.shaderSource(fragShader, fragCode);

         // Compile the fragmentt shader
         gl.compileShader(fragShader);
         
         // Create a shader program object to store
         // the combined shader program
         var shaderProgram = gl.createProgram();

         // Attach a vertex shader
         gl.attachShader(shaderProgram, vertShader); 

         // Attach a fragment shader
         gl.attachShader(shaderProgram, fragShader);

         // Link both programs
         gl.linkProgram(shaderProgram);

         // Use the combined shader program object
         gl.useProgram(shaderProgram);

         /*======== Associating shaders to buffer objects ========*/

         // Bind vertex buffer object
         gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);

         // Get the attribute location
         var coord = gl.getAttribLocation(shaderProgram, "coordinates");

         // Point an attribute to the currently bound VBO
         gl.vertexAttribPointer(coord, 3, gl.FLOAT, false, 0, 0);

         // Enable the attribute
         gl.enableVertexAttribArray(coord);

         /*============= Drawing the primitive ===============*/

         // Clear the canvas
         gl.clearColor(0.5, 0.5, 0.5, 0.9);

         // Enable the depth test
         gl.enable(gl.DEPTH_TEST);
 
         // Clear the color buffer bit
         gl.clear(gl.COLOR_BUFFER_BIT);

         // Set the view port
         gl.viewport(0,0,canvas.width,canvas.height);

         // Draw the triangle
         gl.drawArrays(gl.POINTS, 0, 3);
      </script>
   </body>
</html>

Это даст следующий результат —

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

В предыдущей главе (глава 11) мы обсуждали, как нарисовать три точки, используя WebGL. В главе 5 мы взяли пример приложения, чтобы продемонстрировать, как нарисовать треугольник. В обоих примерах мы нарисовали примитивы, используя только вершины.

Чтобы нарисовать более сложные фигуры / сетки, мы также передаем индексы геометрии вместе с вершинами шейдерам. В этой главе мы увидим, как нарисовать треугольник, используя индексы.

Шаги, необходимые для рисования треугольника

Следующие шаги необходимы для создания приложения WebGL для рисования треугольника.

Шаг 1 — Подготовьте Canvas и получите контекст рендеринга WebGL

На этом шаге мы получаем объект контекста рендеринга WebGL, используя getContext () .

Шаг 2 — Определите геометрию и сохраните ее в буферных объектах

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

var vertices = [
   -0.5,0.5,0.0,
   -0.5,-0.5,0.0,
   0.5,-0.5,0.0, 
];
	
indices = [0,1,2]; 

Шаг 3 — Создание и компиляция шейдерных программ

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

  • Вершинный шейдер — В вершинном шейдере программы мы определяем векторный атрибут для хранения трехмерных координат и назначаем его gl_position .

Вершинный шейдер — В вершинном шейдере программы мы определяем векторный атрибут для хранения трехмерных координат и назначаем его gl_position .

var vertCode =
   'attribute vec3 coordinates;' +
	
   'void main(void) {' +
      ' gl_Position = vec4(coordinates, 1.0);' +
   '}';
  • Фрагментный шейдер. В фрагментном шейдере мы просто назначаем цвет фрагмента переменной gl_FragColor .

Фрагментный шейдер. В фрагментном шейдере мы просто назначаем цвет фрагмента переменной gl_FragColor .

var fragCode = 'void main(void) {' +
   ' gl_FragColor = vec4(1, 0.5, 0.0, 1);' +
'}';

Шаг 4 — Связать шейдерные программы с объектами буфера

На этом шаге мы связываем объекты буфера и программу шейдера.

Шаг 5 — Рисование необходимого объекта

Поскольку мы рисуем треугольник с помощью индексов, мы будем использовать drawElements() . Для этого метода мы должны передать количество индексов. Значение indices.length обозначает количество индексов.

gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT,0);

Пример — Рисование треугольника

Следующий программный код показывает, как нарисовать треугольник в WebGL, используя индексы —

Live Demo

<!doctype html>
<html>
   <body>
      <canvas width = "570" height = "570" id = "my_Canvas"></canvas>

      <script>
         /*============== Creating a canvas ====================*/
         var canvas = document.getElementById('my_Canvas');
         gl = canvas.getContext('experimental-webgl');
      
         /*======== Defining and storing the geometry ===========*/

         var vertices = [
            -0.5,0.5,0.0,
            -0.5,-0.5,0.0,
            0.5,-0.5,0.0, 
         ];
         
         indices = [0,1,2];
         
         // Create an empty buffer object to store vertex buffer
         var vertex_buffer = gl.createBuffer();

         // Bind appropriate array buffer to it
         gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
         
         // Pass the vertex data to the buffer
         gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);

         // Unbind the buffer
         gl.bindBuffer(gl.ARRAY_BUFFER, null);

         // Create an empty buffer object to store Index buffer
         var Index_Buffer = gl.createBuffer();

         // Bind appropriate array buffer to it
         gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, Index_Buffer);

         // Pass the vertex data to the buffer
         gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
         
         // Unbind the buffer
         gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);

         /*================ Shaders ====================*/
         
         // Vertex shader source code
         var vertCode =
            'attribute vec3 coordinates;' +
				
            'void main(void) {' +
               ' gl_Position = vec4(coordinates, 1.0);' +
            '}';
            
         // Create a vertex shader object
         var vertShader = gl.createShader(gl.VERTEX_SHADER);

         // Attach vertex shader source code
         gl.shaderSource(vertShader, vertCode);

         // Compile the vertex shader
         gl.compileShader(vertShader);

         //fragment shader source code
         var fragCode =
            'void main(void) {' +
               ' gl_FragColor = vec4(0.0, 0.0, 0.0, 0.1);' +
            '}';
            
         // Create fragment shader object
         var fragShader = gl.createShader(gl.FRAGMENT_SHADER);

         // Attach fragment shader source code
         gl.shaderSource(fragShader, fragCode); 
         
         // Compile the fragmentt shader
         gl.compileShader(fragShader);

         // Create a shader program object to store
         // the combined shader program
         var shaderProgram = gl.createProgram();

         // Attach a vertex shader
         gl.attachShader(shaderProgram, vertShader);

         // Attach a fragment shader
         gl.attachShader(shaderProgram, fragShader);

         // Link both the programs
         gl.linkProgram(shaderProgram);

         // Use the combined shader program object
         gl.useProgram(shaderProgram);

         /*======= Associating shaders to buffer objects =======*/

         // Bind vertex buffer object
         gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);

         // Bind index buffer object
         gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, Index_Buffer);
         
         // Get the attribute location
         var coord = gl.getAttribLocation(shaderProgram, "coordinates");

         // Point an attribute to the currently bound VBO
         gl.vertexAttribPointer(coord, 3, gl.FLOAT, false, 0, 0); 
         
         // Enable the attribute
         gl.enableVertexAttribArray(coord);

         /*=========Drawing the triangle===========*/

         // Clear the canvas
         gl.clearColor(0.5, 0.5, 0.5, 0.9);

         // Enable the depth test
         gl.enable(gl.DEPTH_TEST);

         // Clear the color buffer bit
         gl.clear(gl.COLOR_BUFFER_BIT);

         // Set the view port
         gl.viewport(0,0,canvas.width,canvas.height);

         // Draw the triangle
         gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT,0);
      </script>
    </body>
</html>

Если вы запустите этот пример, он выдаст следующий вывод:

WebGL — режимы рисования

В предыдущей главе (глава 12) мы обсуждали, как нарисовать треугольник с помощью WebGL. В дополнение к треугольникам, WebGL поддерживает различные другие режимы рисования. В этой главе описываются режимы рисования, поддерживаемые WebGL.

Параметр режима

Давайте посмотрим на синтаксис методов — drawElements () и draw Arrays () .

void drawElements(enum mode, long count, enum type, long offset);

void drawArrays(enum mode, int first, long count);

Если вы четко наблюдаете, оба метода принимают режим параметров. Используя этот параметр, программисты могут выбрать режим рисования в WebGL.

Режимы рисования, предоставляемые WebGL, перечислены в следующей таблице.

Sr.No. Режим и описание
1

gl.POINTS

Чтобы нарисовать ряд точек.

2

gl.LINES

Нарисовать серию несвязанных отрезков (отдельных линий).

3

gl.LINE_STRIP

Чтобы нарисовать серию соединенных отрезков.

4

gl.LINE_LOOP

Чтобы нарисовать серию соединенных отрезков. Он также объединяет первую и последнюю вершины, образуя цикл.

5

gl.TRIANGLES

Чтобы нарисовать серию отдельных треугольников.

6

gl.TRIANGLE_STRIP

Чтобы нарисовать серию соединенных треугольников в полосе моды.

7

gl.TRIANGLE_FAN

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

gl.POINTS

Чтобы нарисовать ряд точек.

gl.LINES

Нарисовать серию несвязанных отрезков (отдельных линий).

gl.LINE_STRIP

Чтобы нарисовать серию соединенных отрезков.

gl.LINE_LOOP

Чтобы нарисовать серию соединенных отрезков. Он также объединяет первую и последнюю вершины, образуя цикл.

gl.TRIANGLES

Чтобы нарисовать серию отдельных треугольников.

gl.TRIANGLE_STRIP

Чтобы нарисовать серию соединенных треугольников в полосе моды.

gl.TRIANGLE_FAN

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

Пример — нарисуйте три параллельные линии

В следующем примере показано, как нарисовать три параллельные линии, используя gl.LINES .

Live Demo

<!doctype html>
<html>
   <body>
      <canvas width = "300" height = "300" id = "my_Canvas"></canvas>

      <script>
         /*======= Creating a canvas =========*/

         var canvas = document.getElementById('my_Canvas');
         var gl = canvas.getContext('experimental-webgl');

         /*======= Defining and storing the geometry ======*/

         var vertices = [
            -0.7,-0.1,0,
            -0.3,0.6,0,
            -0.3,-0.3,0,
            0.2,0.6,0,
            0.3,-0.3,0,
            0.7,0.6,0 
         ]

         // Create an empty buffer object
         var vertex_buffer = gl.createBuffer();

         // Bind appropriate array buffer to it
         gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
      
         // Pass the vertex data to the buffer
         gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);

         // Unbind the buffer
         gl.bindBuffer(gl.ARRAY_BUFFER, null);

         /*=================== Shaders ====================*/

         // Vertex shader source code
         var vertCode =
            'attribute vec3 coordinates;' +
            'void main(void) {' +
               ' gl_Position = vec4(coordinates, 1.0);' +
            '}';

         // Create a vertex shader object
         var vertShader = gl.createShader(gl.VERTEX_SHADER);

         // Attach vertex shader source code
         gl.shaderSource(vertShader, vertCode);

         // Compile the vertex shader
         gl.compileShader(vertShader);

         // Fragment shader source code
         var fragCode =
            'void main(void) {' +
               'gl_FragColor = vec4(0.0, 0.0, 0.0, 0.1);' +
            '}';

         // Create fragment shader object
         var fragShader = gl.createShader(gl.FRAGMENT_SHADER);

         // Attach fragment shader source code
         gl.shaderSource(fragShader, fragCode);

         // Compile the fragmentt shader
         gl.compileShader(fragShader);

         // Create a shader program object to store
         // the combined shader program
         var shaderProgram = gl.createProgram();

         // Attach a vertex shader
         gl.attachShader(shaderProgram, vertShader);

         // Attach a fragment shader
         gl.attachShader(shaderProgram, fragShader);

         // Link both the programs
         gl.linkProgram(shaderProgram);

         // Use the combined shader program object
         gl.useProgram(shaderProgram);

         /*======= Associating shaders to buffer objects ======*/

         // Bind vertex buffer object
         gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);

         // Get the attribute location
         var coord = gl.getAttribLocation(shaderProgram, "coordinates");

         // Point an attribute to the currently bound VBO
         gl.vertexAttribPointer(coord, 3, gl.FLOAT, false, 0, 0);

         // Enable the attribute
         gl.enableVertexAttribArray(coord);

         /*============ Drawing the triangle =============*/

         // Clear the canvas
         gl.clearColor(0.5, 0.5, 0.5, 0.9);

         // Enable the depth test
         gl.enable(gl.DEPTH_TEST);

         // Clear the color and depth buffer
         gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

         // Set the view port
         gl.viewport(0,0,canvas.width,canvas.height);

         // Draw the triangle
         gl.drawArrays(gl.LINES, 0, 6);

         // POINTS, LINE_STRIP, LINE_LOOP, LINES,
         // TRIANGLE_STRIP,TRIANGLE_FAN, TRIANGLES
      </script>
   </body>
</html>

Если вы запустите этот пример, он выдаст следующий вывод:

Режимы рисования

В приведенной выше программе, если вы замените режим drawArrays () на один из следующих режимов рисования, он будет каждый раз выводить разные результаты.

Режимы рисования Выходы
LINE_STRIP Линия полосы
LINE_LOOP Линия Петля
TRIANGLE_STRIP Полоса треугольника
TRIANGLE_FAN Треугольник Вентилятор
ТРЕУГОЛЬНИКИ треугольники

WebGL — рисование четырехугольника

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

В этой главе мы рассмотрим пример того, как нарисовать четырехугольник с помощью WebGL.

Шаги, чтобы нарисовать четырехугольник

Следующие шаги необходимы для создания приложения WebGL, чтобы нарисовать четырехугольник.

Шаг 1. Подготовьте холст и получите контекст рендеринга WebGL

На этом шаге мы получаем объект контекста рендеринга WebGL, используя getContext () .

Шаг 2 — Определите геометрию и сохраните ее в буферных объектах

Квадрат можно нарисовать двумя треугольниками. В этом примере мы предоставляем вершины для двух треугольников (с одним общим ребром) и индексов.

var vertices = [
   -0.5,0.5,0.0,
   -0.5,-0.5,0.0,
   0.5,-0.5,0.0,
   0.5,0.5,0.0 
];

indices = [3,2,1,3,1,0]; 

Шаг 3 — Создание и компиляция шейдерных программ

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

  • Вершинный шейдер — В вершинном шейдере программы мы определяем векторный атрибут для хранения трехмерных координат и назначаем его gl_position .

Вершинный шейдер — В вершинном шейдере программы мы определяем векторный атрибут для хранения трехмерных координат и назначаем его gl_position .

var vertCode =
   'attribute vec3 coordinates;' +
   'void main(void) {' +
      ' gl_Position = vec4(coordinates, 1.0);' +
   '}';
  • Фрагментный шейдер. В фрагментном шейдере мы просто назначаем цвет фрагмента переменной gl_FragColor .

Фрагментный шейдер. В фрагментном шейдере мы просто назначаем цвет фрагмента переменной gl_FragColor .

var fragCode = 'void main(void) {' +' gl_FragColor = vec4(0.5, 0.3, 0.0, 7.5);' +'}';

Шаг 4 — Связать шейдерные программы для буферизации объектов

На этом этапе мы связываем объекты буфера с программой шейдера.

Шаг 5 — Рисование необходимого объекта

Поскольку мы рисуем два треугольника, чтобы сформировать квад, используя индексы, мы будем использовать метод drawElements () . Для этого метода мы должны передать количество индексов. Значение indices.length дает количество индексов.

gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT,0);

Пример — нарисуйте четырехугольник

Следующая программа показывает, как создать приложение WebGL для рисования четырехугольника.

Live Demo

<!doctype html>
<html>
   <body>
      <canvas width = "570" height = "570" id = "my_Canvas"></canvas>

      <script>
         /*============ Creating a canvas =================*/
      
         var canvas = document.getElementById('my_Canvas');
         gl = canvas.getContext('experimental-webgl');
      
         /*========== Defining and storing the geometry =========*/

         var vertices = [
            -0.5,0.5,0.0,
            -0.5,-0.5,0.0,
            0.5,-0.5,0.0,
            0.5,0.5,0.0 
         ];

         indices = [3,2,1,3,1,0];

         // Create an empty buffer object to store vertex buffer
         var vertex_buffer = gl.createBuffer();

         // Bind appropriate array buffer to it
         gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);

         // Pass the vertex data to the buffer
         gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);

         // Unbind the buffer
         gl.bindBuffer(gl.ARRAY_BUFFER, null);

         // Create an empty buffer object to store Index buffer
         var Index_Buffer = gl.createBuffer();

         // Bind appropriate array buffer to it
         gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, Index_Buffer);

         // Pass the vertex data to the buffer
         gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);

         // Unbind the buffer
         gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);

         /*====================== Shaders =======================*/

         // Vertex shader source code
         var vertCode =
            'attribute vec3 coordinates;' +
            'void main(void) {' +
               ' gl_Position = vec4(coordinates, 1.0);' +
            '}';

         // Create a vertex shader object
         var vertShader = gl.createShader(gl.VERTEX_SHADER);

         // Attach vertex shader source code
         gl.shaderSource(vertShader, vertCode);

         // Compile the vertex shader
         gl.compileShader(vertShader);

         // Fragment shader source code
         var fragCode =
            'void main(void) {' +
               ' gl_FragColor = vec4(0.0, 0.0, 0.0, 0.1);' +
            '}';

         // Create fragment shader object 
         var fragShader = gl.createShader(gl.FRAGMENT_SHADER);

         // Attach fragment shader source code
         gl.shaderSource(fragShader, fragCode);

         // Compile the fragmentt shader
         gl.compileShader(fragShader);

         // Create a shader program object to
         // store the combined shader program
         var shaderProgram = gl.createProgram();

         // Attach a vertex shader
         gl.attachShader(shaderProgram, vertShader);

         // Attach a fragment shader
         gl.attachShader(shaderProgram, fragShader);

         // Link both the programs
         gl.linkProgram(shaderProgram);

         // Use the combined shader program object
         gl.useProgram(shaderProgram);

         /* ======= Associating shaders to buffer objects =======*/

         // Bind vertex buffer object
         gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);

         // Bind index buffer object
         gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, Index_Buffer); 

         // Get the attribute location
         var coord = gl.getAttribLocation(shaderProgram, "coordinates");

         // Point an attribute to the currently bound VBO
         gl.vertexAttribPointer(coord, 3, gl.FLOAT, false, 0, 0);

         // Enable the attribute
         gl.enableVertexAttribArray(coord);

         /*============= Drawing the Quad ================*/

         // Clear the canvas
         gl.clearColor(0.5, 0.5, 0.5, 0.9);

         // Enable the depth test
         gl.enable(gl.DEPTH_TEST);

         // Clear the color buffer bit
         gl.clear(gl.COLOR_BUFFER_BIT);

         // Set the view port
         gl.viewport(0,0,canvas.width,canvas.height);

         // Draw the triangle
         gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT,0);
      </script>
   </body>
</html>

Если вы запустите этот пример, он выдаст следующий вывод:

WebGL — Цвета

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

Применение цветов

Чтобы применить цвета, вы должны определить цвета для каждой вершины, используя значения RGB в массиве JavaScript. Вы можете назначить одинаковые значения всем вершинам, чтобы иметь уникальный цвет для объекта. После определения цветов вы должны создать цветовой буфер и сохранить в нем эти значения, а также связать его с атрибутами вершинного шейдера.

В вершинном шейдере, вместе с атрибутом координат (который содержит положение вершин), мы определяем атрибут и переменную для обработки цветов.

Атрибут color содержит значение цвета для каждой вершины, а переменная — это переменная, которая передается в качестве входных данных фрагментному шейдеру. Поэтому мы должны присвоить значение цвета переменному .

В фрагментном шейдере переменная , содержащая значение цвета, присваивается gl_FragColor , который содержит окончательный цвет объекта.

Шаги, чтобы применить цвета

Следующие шаги необходимы для создания приложения WebGL, чтобы нарисовать Quad и применить к нему цвета.

Шаг 1. Подготовьте холст и получите контекст рендеринга WebGL

На этом шаге мы получаем объект контекста рендеринга WebGL, используя getContext () .

Шаг 2 — Определите геометрию и сохраните ее в буферных объектах

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

var vertices = [
   -0.5,0.5,0.0,
   -0.5,-0.5,0.0, 
   0.5,-0.5,0.0,
   0.5,0.5,0.0 
];

var colors = [ 0,0,1, 1,0,0, 0,1,0, 1,0,1,];
indices = [3,2,1,3,1,0]; 

Шаг 3 — Создание и компиляция шейдерных программ

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

  • Вершинный шейдер — В вершинном шейдере программы мы определяем векторные атрибуты для хранения трехмерных координат (положения) и цвета каждой вершины. Переменная переменная объявляется для передачи значений цвета из вершинного шейдера во фрагментный шейдер. И, наконец, значение, хранимое в атрибуте цвета, присваивается переменному .

Вершинный шейдер — В вершинном шейдере программы мы определяем векторные атрибуты для хранения трехмерных координат (положения) и цвета каждой вершины. Переменная переменная объявляется для передачи значений цвета из вершинного шейдера во фрагментный шейдер. И, наконец, значение, хранимое в атрибуте цвета, присваивается переменному .

var vertCode = 'attribute vec3 coordinates;'+
   'attribute vec3 color;'+
   'varying vec3 vColor;'+
	
   'void main(void) {' +
      ' gl_Position = vec4(coordinates, 1.0);' +
      'vColor = color;'+
   '}';
  • Фрагментный шейдер — В фрагментном шейдере мы присваиваем изменение переменной gl_FragColor .

Фрагментный шейдер — В фрагментном шейдере мы присваиваем изменение переменной gl_FragColor .

var fragCode = 'precision mediump float;'+
   'varying vec3 vColor;'+
   'void main(void) {'+
      'gl_FragColor = vec4(vColor, 1.);'+
   '}';

Шаг 4 — Связать шейдерные программы с объектами буфера

На этом шаге мы связываем объекты буфера и программу шейдера.

Шаг 5 — Рисование необходимого объекта

Поскольку мы рисуем два треугольника, которые образуют квад, используя индексы, мы будем использовать метод drawElements () . Для этого метода мы должны передать количество индексов. Значение indices.length указывает количество индексов.

gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT,0);

Пример — применение цвета

Следующая программа демонстрирует, как нарисовать квад с помощью приложения WebGL и применить к нему цвета.

Live Demo

<!doctype html>
<html>
   <body>
    <canvas width = "300" height = "300" id = "my_Canvas"></canvas>

      <script>
         /*============= Creating a canvas ==================*/
         var canvas = document.getElementById('my_Canvas');
         gl = canvas.getContext('experimental-webgl');
         
         /*========== Defining and storing the geometry ==========*/

         var vertices = [
            -0.5,0.5,0.0,
            -0.5,-0.5,0.0,
            0.5,-0.5,0.0,
            0.5,0.5,0.0
         ];

         var colors = [0,0,1, 1,0,0, 0,1,0, 1,0,1,];
         
         indices = [3,2,1,3,1,0];
         
         // Create an empty buffer object and store vertex data
         var vertex_buffer = gl.createBuffer();
         gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
         gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
         gl.bindBuffer(gl.ARRAY_BUFFER, null);

         // Create an empty buffer object and store Index data
         var Index_Buffer = gl.createBuffer();
         gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, Index_Buffer);
         gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
         gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);

         // Create an empty buffer object and store color data
         var color_buffer = gl.createBuffer ();
         gl.bindBuffer(gl.ARRAY_BUFFER, color_buffer);
         gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);

         /*======================= Shaders =======================*/
         
         // vertex shader source code
         var vertCode = 'attribute vec3 coordinates;'+
            'attribute vec3 color;'+
            'varying vec3 vColor;'+
            'void main(void) {' +
               ' gl_Position = vec4(coordinates, 1.0);' +
               'vColor = color;'+
            '}';
            
         // Create a vertex shader object
         var vertShader = gl.createShader(gl.VERTEX_SHADER);

         // Attach vertex shader source code
         gl.shaderSource(vertShader, vertCode);

         // Compile the vertex shader
         gl.compileShader(vertShader);


         // fragment shader source code
         var fragCode = 'precision mediump float;'+
            'varying vec3 vColor;'+
            'void main(void) {'+
               'gl_FragColor = vec4(vColor, 1.);'+
            '}';
            
         // Create fragment shader object
         var fragShader = gl.createShader(gl.FRAGMENT_SHADER);

         // Attach fragment shader source code
         gl.shaderSource(fragShader, fragCode);

         // Compile the fragmentt shader
         gl.compileShader(fragShader);

         // Create a shader program object to
         // store the combined shader program
         var shaderProgram = gl.createProgram();

         // Attach a vertex shader
         gl.attachShader(shaderProgram, vertShader);

         // Attach a fragment shader
         gl.attachShader(shaderProgram, fragShader);

         // Link both the programs
         gl.linkProgram(shaderProgram);

         // Use the combined shader program object
         gl.useProgram(shaderProgram);

         /* ======== Associating shaders to buffer objects =======*/

         // Bind vertex buffer object
         gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);

         // Bind index buffer object
         gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, Index_Buffer);

         // Get the attribute location
         var coord = gl.getAttribLocation(shaderProgram, "coordinates");

         // point an attribute to the currently bound VBO
         gl.vertexAttribPointer(coord, 3, gl.FLOAT, false, 0, 0);

         // Enable the attribute
         gl.enableVertexAttribArray(coord);

         // bind the color buffer
         gl.bindBuffer(gl.ARRAY_BUFFER, color_buffer);
         
         // get the attribute location
         var color = gl.getAttribLocation(shaderProgram, "color");
 
         // point attribute to the volor buffer object
         gl.vertexAttribPointer(color, 3, gl.FLOAT, false,0,0) ;
 
         // enable the color attribute
         gl.enableVertexAttribArray(color);

         /*============Drawing the Quad====================*/

         // Clear the canvas
         gl.clearColor(0.5, 0.5, 0.5, 0.9);

         // Enable the depth test
         gl.enable(gl.DEPTH_TEST);

         // Clear the color buffer bit
         gl.clear(gl.COLOR_BUFFER_BIT);

         // Set the view port
         gl.viewport(0,0,canvas.width,canvas.height);

         //Draw the triangle
         gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT,0);
      </script>
   </body>
</html>

Если вы запустите этот пример, он выдаст следующий вывод:

WebGL — Перевод

До сих пор мы обсуждали, как рисовать различные формы и применять к ним цвета с помощью WebGL. Здесь, в этой главе, мы возьмем пример, чтобы показать, как перевести треугольник.

Перевод

Перевод — одно из аффинных преобразований, предоставляемых WebGL. Используя перевод, мы можем переместить треугольник (любой объект) на плоскости XYZ. Предположим, у нас есть треугольник [a, b, c], и мы хотим переместить треугольник в положение, которое составляет 5 единиц к положительной оси X и 3 единицы к положительной оси Y. Тогда новые вершины будут [a + 5, b + 3, c + 0]. Это означает, что для перевода треугольника нам нужно добавить расстояния перемещения, скажем, tx, ty, tz к каждой вершине.

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

В вершинном шейдере, наряду с атрибутом, координатами (которые содержат позиции вершин), мы определяем равномерную переменную, которая содержит расстояния перемещения (x, y, z). Позже мы добавим эту равномерную переменную в переменную координат и присвоим результат переменной gl_Position .

Примечание. Так как вершинный шейдер будет запускаться на каждой вершине, все вершины треугольника будут переведены.

Шаги по переводу треугольника

Следующие шаги необходимы для создания приложения WebGL, чтобы нарисовать треугольник и затем перевести его в новую позицию.

Шаг 1. Подготовьте холст и получите контекст рендеринга WebGL

На этом шаге мы получаем объект контекста рендеринга WebGL, используя getContext () .

Шаг 2 — Определите геометрию и сохраните ее в буферных объектах

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

var vertices = [ -0.5,0.5,0.0, -0.5,-0.5,0.0, 0.5,-0.5,0.0, ];

Шаг 3 — Создание и компиляция шейдерных программ

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

  • Вершинный шейдер — В вершинном шейдере программы мы определяем векторный атрибут для хранения трехмерных координат. Наряду с этим, мы определяем унифицированную переменную для хранения расстояний перевода, и, наконец, мы добавляем эти два значения и присваиваем ее gl_position, которая содержит конечную позицию вершин.

Вершинный шейдер — В вершинном шейдере программы мы определяем векторный атрибут для хранения трехмерных координат. Наряду с этим, мы определяем унифицированную переменную для хранения расстояний перевода, и, наконец, мы добавляем эти два значения и присваиваем ее gl_position, которая содержит конечную позицию вершин.

var vertCode =
   'attribute vec4 coordinates;' +
   'uniform vec4 translation;'+
   'void main(void) {' +
      ' gl_Position = coordinates + translation;' +
   '}';
  • Фрагментный шейдер. В фрагментном шейдере мы просто назначаем цвет фрагмента переменной gl_FragColor.

Фрагментный шейдер. В фрагментном шейдере мы просто назначаем цвет фрагмента переменной gl_FragColor.

var fragCode = 'void main(void) {' +' gl_FragColor = vec4(1, 0.5, 0.0, 1);' +'}';

Шаг 4 — Связать шейдерные программы с объектами буфера

На этом этапе мы связываем объекты буфера с программой шейдера.

Шаг 5 — Рисование необходимого объекта

Поскольку мы рисуем треугольник с помощью индексов, мы будем использовать метод drawArrays () . Для этого метода мы должны передать количество вершин / элементов, которые необходимо рассмотреть. Поскольку мы рисуем треугольник, мы передадим 3 в качестве параметра.

gl.drawArrays(gl.TRIANGLES, 0, 3);

Пример — перевести треугольник

В следующем примере показано, как перевести треугольник на плоскости XYZ.

Live Demo

<!doctype html>
<html>
   <body>
      <canvas width = "300" height = "300" id = "my_Canvas"></canvas>
         
      <script>
         /*=================Creating a canvas=========================*/
         var canvas = document.getElementById('my_Canvas');
         gl = canvas.getContext('experimental-webgl'); 
 
         /*===========Defining and storing the geometry==============*/
         var vertices = [
            -0.5,0.5,0.0, 	
            -0.5,-0.5,0.0, 	
            0.5,-0.5,0.0,   
         ];
            
         //Create an empty buffer object and store vertex data            
         var vertex_buffer = gl.createBuffer(); 
			
         //Create a new buffer
         gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);   
			
         //bind it to the current buffer			
         gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW); 
			
         // Pass the buffer data
         gl.bindBuffer(gl.ARRAY_BUFFER, null);  
            
         /*========================Shaders============================*/
            
         //vertex shader source code 
         var vertCode =
            'attribute vec4 coordinates;' + 
            'uniform vec4 translation;'+
            'void main(void) {' +
               '  gl_Position = coordinates + translation;' +
            '}';
            
         //Create a vertex shader program object and compile it              
         var vertShader = gl.createShader(gl.VERTEX_SHADER);
         gl.shaderSource(vertShader, vertCode);
         gl.compileShader(vertShader);
            
   
         //fragment shader source code
         var fragCode =
            'void main(void) {' +
               '   gl_FragColor = vec4(0.0, 0.0, 0.0, 0.1);' +
            '}';

         //Create a fragment shader program object and compile it            
         var fragShader = gl.createShader(gl.FRAGMENT_SHADER);
         gl.shaderSource(fragShader, fragCode);
         gl.compileShader(fragShader);
            
         //Create and use combiened shader program
         var shaderProgram = gl.createProgram();
         gl.attachShader(shaderProgram, vertShader);
         gl.attachShader(shaderProgram, fragShader);
         gl.linkProgram(shaderProgram);
   
         gl.useProgram(shaderProgram);
   
         /* ===========Associating shaders to buffer objects============*/
      
         gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);    
         var coordinatesVar = gl.getAttribLocation(shaderProgram, "coordinates");
         gl.vertexAttribPointer(coordinatesVar, 3, gl.FLOAT, false, 0, 0);   
         gl.enableVertexAttribArray(coordinatesVar); 
   
         /* ==========translation======================================*/
         var Tx = 0.5, Ty = 0.5, Tz = 0.0;
         var translation = gl.getUniformLocation(shaderProgram, 'translation');
         gl.uniform4f(translation, Tx, Ty, Tz, 0.0);
 
         /*=================Drawing the riangle and transforming it========================*/ 

         gl.clearColor(0.5, 0.5, 0.5, 0.9);
         gl.enable(gl.DEPTH_TEST);
   
         gl.clear(gl.COLOR_BUFFER_BIT);
         gl.viewport(0,0,canvas.width,canvas.height);
         gl.drawArrays(gl.TRIANGLES, 0, 3);
      </script>
    </body>
 </html>

Если вы запустите этот пример, он выдаст следующий вывод:

WebGL — масштабирование

В этой главе мы рассмотрим пример, показывающий, как изменить масштаб треугольника с помощью WebGL.

пересчет

Масштабирование — это не что иное, как увеличение или уменьшение размера объекта. Например, если треугольник имеет вершины размера [a, b, c], то треугольник с вершинами [2a, 2b, 2c] будет в два раза больше своего размера. Поэтому, чтобы масштабировать треугольник, вы должны умножить каждую вершину на коэффициент масштабирования. Вы также можете масштабировать конкретную вершину.

Чтобы масштабировать треугольник, в вершинном шейдере программы мы создаем равномерную матрицу и умножаем значения координат на эту матрицу. Позже мы передаем диагональную матрицу 4 × 4 с масштабными коэффициентами координат x, y, z в диагональных позициях (последняя диагональная позиция 1).

Требуемые шаги

Следующие шаги необходимы для создания приложения WebGL для масштабирования треугольника.

Шаг 1. Подготовьте холст и получите контекст рендеринга WebGL

На этом шаге мы получаем объект контекста рендеринга WebGL, используя getContext () .

Шаг 2 — Определите геометрию и сохраните ее в буферных объектах

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

var vertices = [ -0.5,0.5,0.0, -0.5,-0.5,0.0, 0.5,-0.5,0.0, ];

Шаг 3 — Создание и компиляция шейдерных программ

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

  • Вершинный шейдер — В вершинном шейдере программы мы определяем векторный атрибут для хранения трехмерных координат. Наряду с этим, мы определяем равномерную матрицу для хранения коэффициентов масштабирования, и, наконец, мы умножаем эти два значения и присваиваем ей gl_position, которая содержит конечную позицию вершин.

Вершинный шейдер — В вершинном шейдере программы мы определяем векторный атрибут для хранения трехмерных координат. Наряду с этим, мы определяем равномерную матрицу для хранения коэффициентов масштабирования, и, наконец, мы умножаем эти два значения и присваиваем ей gl_position, которая содержит конечную позицию вершин.

var vertCode =
   'attribute vec4 coordinates;' +
   'uniform mat4 u_xformMatrix;' +
   'void main(void) {' +
      ' gl_Position = u_xformMatrix * coordinates;' +
   '}';
  • Фрагментный шейдер. В фрагментном шейдере мы просто назначаем цвет фрагмента переменной gl_FragColor .

Фрагментный шейдер. В фрагментном шейдере мы просто назначаем цвет фрагмента переменной gl_FragColor .

var fragCode = 'void main(void) {' +' gl_FragColor = vec4(1, 0.5, 0.0, 1);' +'}';

Шаг 4 — Связать шейдерные программы с объектами буфера

На этом этапе мы связываем объекты буфера с программой шейдера.

Шаг 5 — Рисование необходимого объекта

Поскольку мы рисуем треугольник с помощью индексов, мы используем метод drawArrays () . Для этого метода мы должны передать количество вершин / элементов, которые необходимо рассмотреть. Поскольку мы рисуем треугольник, мы передадим 3 в качестве параметра.

gl.drawArrays(gl.TRIANGLES, 0, 3);

Пример — масштабирование треугольника

В следующем примере показано, как масштабировать треугольник —

Live Demo

<!doctype html>
<html>
   <body>
      <canvas width = "300" height = "300" id = "my_Canvas"></canvas>

      <script>
         /*=================Creating a canvas=========================*/
         var canvas = document.getElementById('my_Canvas');
         gl = canvas.getContext('experimental-webgl'); 

         /*===========Defining and storing the geometry==============*/
         var vertices =  [
            -0.5,0.5,0.0, 	
            -0.5,-0.5,0.0, 	
            0.5,-0.5,0.0,   
         ];

         //Create an empty buffer object and store vertex data

         var vertex_buffer = gl.createBuffer();                                                     
         gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);                                                
         gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);           
         gl.bindBuffer(gl.ARRAY_BUFFER, null);  

         /*========================Shaders============================*/

         //Vertex shader source code
         var vertCode =
            'attribute vec4 coordinates;' + 
            'uniform mat4 u_xformMatrix;' +
            'void main(void) {' +
               '  gl_Position = u_xformMatrix * coordinates;' +
            '}';

         //Create a vertex shader program object and compile it                
         var vertShader = gl.createShader(gl.VERTEX_SHADER);
         gl.shaderSource(vertShader, vertCode);
         gl.compileShader(vertShader);

         //fragment shader source code
         var fragCode =
            'void main(void) {' +
               '   gl_FragColor = vec4(0.0, 0.0, 0.0, 0.1);' +
            '}';

         //Create a fragment shader program object and compile it 
         var fragShader = gl.createShader(gl.FRAGMENT_SHADER);
         gl.shaderSource(fragShader, fragCode);
         gl.compileShader(fragShader);

         //Create and use combiened shader program
         var shaderProgram = gl.createProgram();
         gl.attachShader(shaderProgram, vertShader);
         gl.attachShader(shaderProgram, fragShader);
         gl.linkProgram(shaderProgram);

         gl.useProgram(shaderProgram); 

         /*===================scaling==========================*/

         var Sx = 1.0, Sy = 1.5, Sz = 1.0;
         var xformMatrix = new Float32Array([
            Sx,   0.0,  0.0,  0.0,
            0.0,  Sy,   0.0,  0.0,
            0.0,  0.0,  Sz,   0.0,
            0.0,  0.0,  0.0,  1.0  
         ]);

         var u_xformMatrix = gl.getUniformLocation(shaderProgram, 'u_xformMatrix');
         gl.uniformMatrix4fv(u_xformMatrix, false, xformMatrix);

         /* ===========Associating shaders to buffer objects============*/
         gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);   

         var coordinatesVar = gl.getAttribLocation(shaderProgram, "coordinates"); 
         gl.vertexAttribPointer(coordinatesVar, 3, gl.FLOAT, false, 0, 0);  
         gl.enableVertexAttribArray(coordinatesVar);

         /*=================Drawing the Quad========================*/ 
         gl.clearColor(0.5, 0.5, 0.5, 0.9);
         gl.enable(gl.DEPTH_TEST);

         gl.clear(gl.COLOR_BUFFER_BIT);
         gl.viewport(0,0,canvas.width,canvas.height);
         gl.drawArrays(gl.TRIANGLES, 0, 3);
      </script>
   </body>
</html>      

Если вы запустите этот пример, он выдаст следующий вывод:

WebGL — Вращение

В этой главе мы рассмотрим пример поворота треугольника с помощью WebGL.

Пример — Поворот треугольника

Следующая программа показывает, как вращать треугольник с помощью WebGL.

Live Demo

<!doctype html>
<html>
   <body>
      <canvas width = "400" height = "400" id = "my_Canvas"></canvas>

      <script>
         /*=================Creating a canvas=========================*/
         var canvas = document.getElementById('my_Canvas');
         gl = canvas.getContext('experimental-webgl');

         /*===========Defining and storing the geometry==============*/

         var vertices = [ -1,-1,-1, 1,-1,-1, 1, 1,-1 ];
         var colors = [ 1,1,1, 1,1,1, 1,1,1 ];
         var indices = [ 0,1,2 ];

         //Create and store data into vertex buffer
         var vertex_buffer = gl.createBuffer ();
         gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
         gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);

         //Create and store data into color buffer
         var color_buffer = gl.createBuffer ();
         gl.bindBuffer(gl.ARRAY_BUFFER, color_buffer);
         gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);

         //Create and store data into index buffer
         var index_buffer = gl.createBuffer ();
         gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, index_buffer);
         gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);

         /*==========================Shaders=========================*/

         var vertCode = 'attribute vec3 position;'+
            'uniform mat4 Pmatrix;'+
            'uniform mat4 Vmatrix;'+
            'uniform mat4 Mmatrix;'+
            'attribute vec3 color;'+//the color of the point
            'varying vec3 vColor;'+

            'void main(void) { '+//pre-built function
               'gl_Position = Pmatrix*Vmatrix*Mmatrix*vec4(position, 1.);'+
               'vColor = color;'+
            '}';

         var fragCode = 'precision mediump float;'+
            'varying vec3 vColor;'+
            'void main(void) {'+
               'gl_FragColor = vec4(vColor, 1.);'+
            '}';

         var vertShader = gl.createShader(gl.VERTEX_SHADER);
         gl.shaderSource(vertShader, vertCode);
         gl.compileShader(vertShader);

         var fragShader = gl.createShader(gl.FRAGMENT_SHADER);
         gl.shaderSource(fragShader, fragCode);
         gl.compileShader(fragShader);

         var shaderProgram = gl.createProgram();
         gl.attachShader(shaderProgram, vertShader);
         gl.attachShader(shaderProgram, fragShader);
         gl.linkProgram(shaderProgram);

         /*===========associating attributes to vertex shader ============*/

         var Pmatrix = gl.getUniformLocation(shaderProgram, "Pmatrix");
         var Vmatrix = gl.getUniformLocation(shaderProgram, "Vmatrix");
         var Mmatrix = gl.getUniformLocation(shaderProgram, "Mmatrix");
         gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);

         var position = gl.getAttribLocation(shaderProgram, "position");
         gl.vertexAttribPointer(position, 3, gl.FLOAT, false,0,0) ; //position
         gl.enableVertexAttribArray(position);
         gl.bindBuffer(gl.ARRAY_BUFFER, color_buffer);

         var color = gl.getAttribLocation(shaderProgram, "color");
         gl.vertexAttribPointer(color, 3, gl.FLOAT, false,0,0) ; //color
         gl.enableVertexAttribArray(color);
         gl.useProgram(shaderProgram);

         /*========================= MATRIX ========================= */

         function get_projection(angle, a, zMin, zMax) {
            var ang = Math.tan((angle*.5)*Math.PI/180);//angle*.5
            return [
               0.5/ang, 0 , 0, 0,
               0, 0.5*a/ang, 0, 0,
               0, 0, -(zMax+zMin)/(zMax-zMin), -1,
               0, 0, (-2*zMax*zMin)/(zMax-zMin), 0
            ];
         }

         var proj_matrix = get_projection(40, canvas.width/canvas.height, 1, 100);
         var mov_matrix = [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1];
         var view_matrix = [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1];

         //translating z
         view_matrix[14] = view_matrix[14]-6; //zoom

         /*=======================rotation========================*/
         function rotateZ(m, angle) {
            var c = Math.cos(angle);
            var s = Math.sin(angle);
            var mv0 = m[0], mv4 = m[4], mv8 = m[8]; 

            m[0] = c*m[0]-s*m[1];
            m[4] = c*m[4]-s*m[5];
            m[8] = c*m[8]-s*m[9];
            m[1] = c*m[1]+s*mv0;
            m[5] = c*m[5]+s*mv4;
            m[9] = c*m[9]+s*mv8;
         }

         /*=================Drawing===========================*/

         var time_old = 0;
         var animate = function(time) {
            var dt = time-time_old;
            rotateZ(mov_matrix, dt*0.002);
            time_old = time;

            gl.enable(gl.DEPTH_TEST);
            gl.depthFunc(gl.LEQUAL);
            gl.clearColor(0.5, 0.5, 0.5, 0.9);
            gl.clearDepth(1.0);
            gl.viewport(0.0, 0.0, canvas.width, canvas.height);
            gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

            gl.uniformMatrix4fv(Pmatrix, false, proj_matrix);
            gl.uniformMatrix4fv(Vmatrix, false, view_matrix);
            gl.uniformMatrix4fv(Mmatrix, false, mov_matrix);

            gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, index_buffer);
            gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT, 0);
            window.requestAnimationFrame(animate);
         }
         animate(0);
      </script>
   </body>
</html>

Если вы запустите этот пример, он выдаст следующий вывод:

WebGL — вращение куба

В этой главе мы рассмотрим пример, показывающий, как рисовать вращающийся трехмерный куб с помощью WebGL.

Пример — нарисуйте вращающийся 3D-куб

Следующая программа показывает, как нарисовать вращающийся 3D-куб —

Live Demo

<!doctype html>
<html>
   <body>
      <canvas width = "570" height = "570" id = "my_Canvas"></canvas>

      <script>
         /*============= Creating a canvas =================*/
         var canvas = document.getElementById('my_Canvas');
         gl = canvas.getContext('experimental-webgl');

         /*============ Defining and storing the geometry =========*/

         var vertices = [
            -1,-1,-1, 1,-1,-1, 1, 1,-1, -1, 1,-1,
            -1,-1, 1, 1,-1, 1, 1, 1, 1, -1, 1, 1,
            -1,-1,-1, -1, 1,-1, -1, 1, 1, -1,-1, 1,
            1,-1,-1, 1, 1,-1, 1, 1, 1, 1,-1, 1,
            -1,-1,-1, -1,-1, 1, 1,-1, 1, 1,-1,-1,
            -1, 1,-1, -1, 1, 1, 1, 1, 1, 1, 1,-1, 
         ];

         var colors = [
            5,3,7, 5,3,7, 5,3,7, 5,3,7,
            1,1,3, 1,1,3, 1,1,3, 1,1,3,
            0,0,1, 0,0,1, 0,0,1, 0,0,1,
            1,0,0, 1,0,0, 1,0,0, 1,0,0,
            1,1,0, 1,1,0, 1,1,0, 1,1,0,
            0,1,0, 0,1,0, 0,1,0, 0,1,0
         ];

         var indices = [
            0,1,2, 0,2,3, 4,5,6, 4,6,7,
            8,9,10, 8,10,11, 12,13,14, 12,14,15,
            16,17,18, 16,18,19, 20,21,22, 20,22,23 
         ];

         // Create and store data into vertex buffer
         var vertex_buffer = gl.createBuffer ();
         gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
         gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);

         // Create and store data into color buffer
         var color_buffer = gl.createBuffer ();
         gl.bindBuffer(gl.ARRAY_BUFFER, color_buffer);
         gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);

         // Create and store data into index buffer
         var index_buffer = gl.createBuffer ();
         gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, index_buffer);
         gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);

         /*=================== Shaders =========================*/

         var vertCode = 'attribute vec3 position;'+
            'uniform mat4 Pmatrix;'+
            'uniform mat4 Vmatrix;'+
            'uniform mat4 Mmatrix;'+
            'attribute vec3 color;'+//the color of the point
            'varying vec3 vColor;'+

            'void main(void) { '+//pre-built function
               'gl_Position = Pmatrix*Vmatrix*Mmatrix*vec4(position, 1.);'+
               'vColor = color;'+
            '}';

         var fragCode = 'precision mediump float;'+
            'varying vec3 vColor;'+
            'void main(void) {'+
               'gl_FragColor = vec4(vColor, 1.);'+
            '}';

         var vertShader = gl.createShader(gl.VERTEX_SHADER);
         gl.shaderSource(vertShader, vertCode);
         gl.compileShader(vertShader);

         var fragShader = gl.createShader(gl.FRAGMENT_SHADER);
         gl.shaderSource(fragShader, fragCode);
         gl.compileShader(fragShader);

         var shaderProgram = gl.createProgram();
         gl.attachShader(shaderProgram, vertShader);
         gl.attachShader(shaderProgram, fragShader);
         gl.linkProgram(shaderProgram);

         /* ====== Associating attributes to vertex shader =====*/
         var Pmatrix = gl.getUniformLocation(shaderProgram, "Pmatrix");
         var Vmatrix = gl.getUniformLocation(shaderProgram, "Vmatrix");
         var Mmatrix = gl.getUniformLocation(shaderProgram, "Mmatrix");

         gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
         var position = gl.getAttribLocation(shaderProgram, "position");
         gl.vertexAttribPointer(position, 3, gl.FLOAT, false,0,0) ;

         // Position
         gl.enableVertexAttribArray(position);
         gl.bindBuffer(gl.ARRAY_BUFFER, color_buffer);
         var color = gl.getAttribLocation(shaderProgram, "color");
         gl.vertexAttribPointer(color, 3, gl.FLOAT, false,0,0) ;

         // Color
         gl.enableVertexAttribArray(color);
         gl.useProgram(shaderProgram);

         /*==================== MATRIX =====================*/

         function get_projection(angle, a, zMin, zMax) {
            var ang = Math.tan((angle*.5)*Math.PI/180);//angle*.5
            return [
               0.5/ang, 0 , 0, 0,
               0, 0.5*a/ang, 0, 0,
               0, 0, -(zMax+zMin)/(zMax-zMin), -1,
               0, 0, (-2*zMax*zMin)/(zMax-zMin), 0 
            ];
         }

         var proj_matrix = get_projection(40, canvas.width/canvas.height, 1, 100);

         var mov_matrix = [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1];
         var view_matrix = [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1];

         // translating z
         view_matrix[14] = view_matrix[14]-6;//zoom

         /*==================== Rotation ====================*/

         function rotateZ(m, angle) {
            var c = Math.cos(angle);
            var s = Math.sin(angle);
            var mv0 = m[0], mv4 = m[4], mv8 = m[8];

            m[0] = c*m[0]-s*m[1];
            m[4] = c*m[4]-s*m[5];
            m[8] = c*m[8]-s*m[9];

            m[1]=c*m[1]+s*mv0;
            m[5]=c*m[5]+s*mv4;
            m[9]=c*m[9]+s*mv8;
         }

         function rotateX(m, angle) {
            var c = Math.cos(angle);
            var s = Math.sin(angle);
            var mv1 = m[1], mv5 = m[5], mv9 = m[9];

            m[1] = m[1]*c-m[2]*s;
            m[5] = m[5]*c-m[6]*s;
            m[9] = m[9]*c-m[10]*s;

            m[2] = m[2]*c+mv1*s;
            m[6] = m[6]*c+mv5*s;
            m[10] = m[10]*c+mv9*s;
         }

         function rotateY(m, angle) {
            var c = Math.cos(angle);
            var s = Math.sin(angle);
            var mv0 = m[0], mv4 = m[4], mv8 = m[8];

            m[0] = c*m[0]+s*m[2];
            m[4] = c*m[4]+s*m[6];
            m[8] = c*m[8]+s*m[10];

            m[2] = c*m[2]-s*mv0;
            m[6] = c*m[6]-s*mv4;
            m[10] = c*m[10]-s*mv8;
         }

         /*================= Drawing ===========================*/
         var time_old = 0;

         var animate = function(time) {

            var dt = time-time_old;
            rotateZ(mov_matrix, dt*0.005);//time
            rotateY(mov_matrix, dt*0.002);
            rotateX(mov_matrix, dt*0.003);
            time_old = time;

            gl.enable(gl.DEPTH_TEST);
            gl.depthFunc(gl.LEQUAL);
            gl.clearColor(0.5, 0.5, 0.5, 0.9);
            gl.clearDepth(1.0);

            gl.viewport(0.0, 0.0, canvas.width, canvas.height);
            gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
            gl.uniformMatrix4fv(Pmatrix, false, proj_matrix);
            gl.uniformMatrix4fv(Vmatrix, false, view_matrix);
            gl.uniformMatrix4fv(Mmatrix, false, mov_matrix);
            gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, index_buffer);
            gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT, 0);

            window.requestAnimationFrame(animate);
         }
         animate(0);
      </script>
   </body>
</html>

Если вы запустите этот пример, он выдаст следующий вывод:

WebGL — Интерактивный куб

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

Пример — нарисуйте интерактивный куб

Следующая программа показывает, как вращать куб с помощью элементов управления мышью.

Live Demo

<!doctype html>
<html>
   <body>
      <canvas width = "570" height = "570" id = "my_Canvas"></canvas>

      <script>
         /*============= Creating a canvas ======================*/
         var canvas = document.getElementById('my_Canvas');
         gl = canvas.getContext('experimental-webgl');

         /*========== Defining and storing the geometry ==========*/

         var vertices = [
            -1,-1,-1, 1,-1,-1, 1, 1,-1, -1, 1,-1,
            -1,-1, 1, 1,-1, 1, 1, 1, 1, -1, 1, 1,
            -1,-1,-1, -1, 1,-1, -1, 1, 1, -1,-1, 1,
            1,-1,-1, 1, 1,-1, 1, 1, 1, 1,-1, 1,
            -1,-1,-1, -1,-1, 1, 1,-1, 1, 1,-1,-1,
            -1, 1,-1, -1, 1, 1, 1, 1, 1, 1, 1,-1, 
         ];

         var colors = [
            5,3,7, 5,3,7, 5,3,7, 5,3,7,
            1,1,3, 1,1,3, 1,1,3, 1,1,3,
            0,0,1, 0,0,1, 0,0,1, 0,0,1,
            1,0,0, 1,0,0, 1,0,0, 1,0,0,
            1,1,0, 1,1,0, 1,1,0, 1,1,0,
            0,1,0, 0,1,0, 0,1,0, 0,1,0 
         ];

         var indices = [
            0,1,2, 0,2,3, 4,5,6, 4,6,7,
            8,9,10, 8,10,11, 12,13,14, 12,14,15,
            16,17,18, 16,18,19, 20,21,22, 20,22,23 
         ];

         // Create and store data into vertex buffer
         var vertex_buffer = gl.createBuffer ();
         gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
         gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);

         // Create and store data into color buffer
         var color_buffer = gl.createBuffer ();
         gl.bindBuffer(gl.ARRAY_BUFFER, color_buffer);
         gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);

         // Create and store data into index buffer
         var index_buffer = gl.createBuffer ();
         gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, index_buffer);
         gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);

         /*=================== SHADERS =================== */

         var vertCode = 'attribute vec3 position;'+
            'uniform mat4 Pmatrix;'+
            'uniform mat4 Vmatrix;'+
            'uniform mat4 Mmatrix;'+
            'attribute vec3 color;'+//the color of the point
            'varying vec3 vColor;'+
            'void main(void) { '+//pre-built function
               'gl_Position = Pmatrix*Vmatrix*Mmatrix*vec4(position, 1.);'+
               'vColor = color;'+
            '}';

         var fragCode = 'precision mediump float;'+
            'varying vec3 vColor;'+
            'void main(void) {'+
               'gl_FragColor = vec4(vColor, 1.);'+
            '}';

         var vertShader = gl.createShader(gl.VERTEX_SHADER);
         gl.shaderSource(vertShader, vertCode);
         gl.compileShader(vertShader);

         var fragShader = gl.createShader(gl.FRAGMENT_SHADER);
         gl.shaderSource(fragShader, fragCode);
         gl.compileShader(fragShader);

         var shaderprogram = gl.createProgram();
         gl.attachShader(shaderprogram, vertShader);
         gl.attachShader(shaderprogram, fragShader);
         gl.linkProgram(shaderprogram);

         /*======== Associating attributes to vertex shader =====*/
         var _Pmatrix = gl.getUniformLocation(shaderprogram, "Pmatrix");
         var _Vmatrix = gl.getUniformLocation(shaderprogram, "Vmatrix");
         var _Mmatrix = gl.getUniformLocation(shaderprogram, "Mmatrix");

         gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
         var _position = gl.getAttribLocation(shaderprogram, "position");
         gl.vertexAttribPointer(_position, 3, gl.FLOAT, false,0,0);
         gl.enableVertexAttribArray(_position);

         gl.bindBuffer(gl.ARRAY_BUFFER, color_buffer);
         var _color = gl.getAttribLocation(shaderprogram, "color");
         gl.vertexAttribPointer(_color, 3, gl.FLOAT, false,0,0) ;
         gl.enableVertexAttribArray(_color);
         gl.useProgram(shaderprogram);

         /*==================== MATRIX ====================== */

         function get_projection(angle, a, zMin, zMax) {
            var ang = Math.tan((angle*.5)*Math.PI/180);//angle*.5
            return [
               0.5/ang, 0 , 0, 0,
               0, 0.5*a/ang, 0, 0,
               0, 0, -(zMax+zMin)/(zMax-zMin), -1,
               0, 0, (-2*zMax*zMin)/(zMax-zMin), 0 
			   ];
         }

         var proj_matrix = get_projection(40, canvas.width/canvas.height, 1, 100);
         var mo_matrix = [ 1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1 ];
         var view_matrix = [ 1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1 ];

         view_matrix[14] = view_matrix[14]-6;

         /*================= Mouse events ======================*/

         var AMORTIZATION = 0.95;
         var drag = false;
         var old_x, old_y;
         var dX = 0, dY = 0;

         var mouseDown = function(e) {
            drag = true;
            old_x = e.pageX, old_y = e.pageY;
            e.preventDefault();
            return false;
         };

         var mouseUp = function(e){
            drag = false;
         };

         var mouseMove = function(e) {
            if (!drag) return false;
            dX = (e.pageX-old_x)*2*Math.PI/canvas.width,
            dY = (e.pageY-old_y)*2*Math.PI/canvas.height;
            THETA+= dX;
            PHI+=dY;
            old_x = e.pageX, old_y = e.pageY;
            e.preventDefault();
         };

         canvas.addEventListener("mousedown", mouseDown, false);
         canvas.addEventListener("mouseup", mouseUp, false);
         canvas.addEventListener("mouseout", mouseUp, false);
         canvas.addEventListener("mousemove", mouseMove, false);

         /*=========================rotation================*/

         function rotateX(m, angle) {
            var c = Math.cos(angle);
            var s = Math.sin(angle);
            var mv1 = m[1], mv5 = m[5], mv9 = m[9];

            m[1] = m[1]*c-m[2]*s;
            m[5] = m[5]*c-m[6]*s;
            m[9] = m[9]*c-m[10]*s;

            m[2] = m[2]*c+mv1*s;
            m[6] = m[6]*c+mv5*s;
            m[10] = m[10]*c+mv9*s;
         }

         function rotateY(m, angle) {
            var c = Math.cos(angle);
            var s = Math.sin(angle);
            var mv0 = m[0], mv4 = m[4], mv8 = m[8];

            m[0] = c*m[0]+s*m[2];
            m[4] = c*m[4]+s*m[6];
            m[8] = c*m[8]+s*m[10];

            m[2] = c*m[2]-s*mv0;
            m[6] = c*m[6]-s*mv4;
            m[10] = c*m[10]-s*mv8;
         }

         /*=================== Drawing =================== */

         var THETA = 0,
         PHI = 0;
         var time_old = 0;

         var animate = function(time) {
            var dt = time-time_old;

            if (!drag) {
               dX *= AMORTIZATION, dY*=AMORTIZATION;
               THETA+=dX, PHI+=dY;
            }

            //set model matrix to I4

            mo_matrix[0] = 1, mo_matrix[1] = 0, mo_matrix[2] = 0,
            mo_matrix[3] = 0,

            mo_matrix[4] = 0, mo_matrix[5] = 1, mo_matrix[6] = 0,
            mo_matrix[7] = 0,

            mo_matrix[8] = 0, mo_matrix[9] = 0, mo_matrix[10] = 1,
            mo_matrix[11] = 0,

            mo_matrix[12] = 0, mo_matrix[13] = 0, mo_matrix[14] = 0,
            mo_matrix[15] = 1;

            rotateY(mo_matrix, THETA);
            rotateX(mo_matrix, PHI);

            time_old = time; 
            gl.enable(gl.DEPTH_TEST);

            // gl.depthFunc(gl.LEQUAL);

            gl.clearColor(0.5, 0.5, 0.5, 0.9);
            gl.clearDepth(1.0);
            gl.viewport(0.0, 0.0, canvas.width, canvas.height);
            gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

            gl.uniformMatrix4fv(_Pmatrix, false, proj_matrix);
            gl.uniformMatrix4fv(_Vmatrix, false, view_matrix);
            gl.uniformMatrix4fv(_Mmatrix, false, mo_matrix);

            gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, index_buffer);
            gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT, 0);

            window.requestAnimationFrame(animate);
         }
         animate(0);
      </script>
   </body>
</html> 

Если вы запустите этот пример, он выдаст следующий вывод: