Подтвердить что ты не робот

Как работает WebGL?

Я ищу глубокое понимание того, как работает WebGL. Я хочу получить знания на том уровне, о котором больше всего заботятся люди, потому что знание не обязательно полезно для среднего программиста WebGL. Например, какую роль играет каждая часть (браузер, графический драйвер и т.д.) Всей системы рендеринга при получении изображения на экране? Должен ли каждый браузер создавать javascript/html-движок/среду для запуска WebGL в браузере? Почему хром является главой всех остальных с точки зрения совместимости с WebGL?

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

4b9b3361

Ответ 1

Надеюсь, эта небольшая рецензия полезна для вас. Он рассматривает большой фрагмент того, что я узнал о WebGL и 3D в целом. Кстати, если я получил что-то неправильно, кто-то, пожалуйста, поправьте меня, потому что я все еще учился!

Архитектура

Браузер - это просто веб-браузер. Все, что он делает, это разоблачить API WebGL (через JavaScript), который программист делает с остальными.

Насколько я могу судить, API WebGL - это, по сути, всего лишь набор (JavaScript-поставляемых) функций JavaScript, которые охватывают спецификацию OpenGL ES. Поэтому, если вы знаете OpenGL ES, вы можете быстро принять WebGL. Не путайте это с чистым OpenGL. "ES" имеет важное значение.

Спецификация WebGL была намеренно оставлена ​​очень низкоуровневой, оставив много быть повторно реализованы из одного приложения в другое. Это зависит от сообщество писать рамки для автоматизации и до разработчика выбрать, какую структуру использовать (если таковая имеется). Это не совсем сложно сворачивать свои собственные, но это означает много накладных расходов, потраченных на изобретать колесо. (FWIW, я работал над собой WebGL Framework под названием Jax некоторое время Теперь.)

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

В Windows есть дополнительный слой, который существует между API WebGL и аппаратным обеспечением: ANGLE или "Almost Native Engine Layer Engine" , Поскольку драйверы OpenGL ES в Windows обычно сосут, ANGLE принимает эти вызовы и вместо этого переводит их в вызовы DirectX 9.

Рисование в 3D

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

JavaScript

Во-первых, код JavaScript получает 3D-контекст из элемента холста HTML5. Затем он регистрирует набор шейдеров, которые записываются в GLSL ([Open] GL Shading Language) и по существу напоминают код C.

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

JavaScript настраивает исходные структуры данных и отправляет их в API WebGL, который отправляет их в ANGLE или OpenGL ES, который в конечном итоге отправляет его на графическое оборудование.

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

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

gl_Position = PROJECTION_MATRIX * VIEW_MATRIX * MODEL_MATRIX * VERTEX_POSITION

где VERTEX_POSITION - 4D-вектор (x, y, z и w, который обычно устанавливается равным 1); VIEW_MATRIX - это матрица 4x4, представляющая вид камеры в мир; MODEL_MATRIX - это матрица 4x4, которая преобразует координаты объектно-пространственного пространства (то есть коорды, локальные к объекту перед вращением или трансляцией) в мировые космические координаты; и PROJECTION_MATRIX, который представляет собой объектив камеры.

Чаще всего VIEW_MATRIX и MODEL_MATRIX предварительно вычисляются и называется MODELVIEW_MATRIX. Иногда все 3 предварительно вычисляются в MODELVIEW_PROJECTION_MATRIX или просто MVP. Как правило, это означает как оптимизация, хотя я бы хотел найти время, чтобы сделать некоторые тесты. Это возможно, что предварительная компиляция на JavaScript более медленная, если это каждый кадр, потому что сам JavaScript не так быстро. В этот случай, аппаратное ускорение, обеспечиваемое выполнением математики на Графический процессор может быть быстрее, чем делать это на процессоре в JavaScript. Мы можем конечно, надеюсь, что будущие реализации JS разрешат этот потенциал getcha, просто будучи быстрее.

Координаты клипа

Когда все они были применены, переменная gl_Position будет иметь набор координат XYZ, расположенных в пределах [-1, 1] и компонент W. Они называются координатами клипа.

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

После того, как вы поместите координаты клипа на gl_Position, WebGL делит результат на gl_Position.w, создавая так называемые нормализованные координаты устройства. Оттуда проецирование пикселя на экран - это простое умножение на 1/2 размера экрана, а затем добавление 1/2 размеров экрана. [1] Ниже приведены некоторые примеры преобразований клипов в 2D-координаты на дисплее 800x600:

clip = [0, 0]
x = (0 * 800/2) + 800/2 = 400
y = (0 * 600/2) + 600/2 = 300

clip = [0.5, 0.5]
x = (0.5 * 800/2) + 800/2 = 200 + 400 = 600
y = (0.5 * 600/2) + 600/2 = 150 + 300 = 450

clip = [-0.5, -0.25]
x = (-0.5  * 800/2) + 800/2 = -200 + 400 = 200
y = (-0.25 * 600/2) + 600/2 = -150 + 300 = 150

Пиксельные шейдеры

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

Глубина и буфер глубины

Теперь мы до сих пор игнорировали компонент Z координат клипа. Вот как это получается. Когда мы умножались на матрицу проекции, третий компонент клипа приводил к некоторому числу. Если это число больше 1,0 или меньше -1,0, то это число выходит за пределы диапазона проекционной матрицы, соответствующей значениям матрицы zFar и zNear соответственно.

Итак, если он не находится в диапазоне [-1, 1], то он полностью обрезается. Если он находится в этом диапазоне, то значение Z масштабируется до 0 до 1 [2] и сравнивается с буфером глубины [3]. Буфер глубины равен размеру экрана, так что, если используется проекция 800x600, буфер глубины составляет 800 пикселей в ширину и 600 пикселей в высоту. У нас уже есть координаты X и Y пикселя, поэтому они подключаются в буфер глубины, чтобы получить сохраненное в настоящее время значение Z. Если значение Z больше, чем новое значение Z, то новое значение Z ближе, чем то, что было ранее нарисовано, и заменяет его [4]. На этом этапе безопасно загораться соответствующий пиксель (или в случае WebGL, нарисовать пиксель на холсте) и сохранить значение Z в качестве нового значения глубины.

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

[1] Фактическое преобразование использует настройки gl.viewport для преобразования из нормализованных координат устройства в пиксели.

[2] Фактически он масштабируется до настроек gl.depthRange. Они по умолчанию от 0 до 1.

[3] Предполагая, что у вас есть буфер глубины, и вы включили глубинное тестирование с помощью gl.enable(gl.DEPTH_TEST).

[4] Вы можете установить, как значения Z сравниваются с gl.depthFunc

Ответ 2

Я бы прочитал эти статьи

http://webglfundamentals.org/webgl/lessons/webgl-how-it-works.html

Предполагая, что эти статьи полезны, остальная часть изображения заключается в том, что WebGL запускается в браузере. Он визуализирует тэг canvas. Вы можете думать о теге canvas, как тег img, за исключением того, что вы используете WebGL API для создания изображения вместо его загрузки.

Как и другие теги HTML5, тег canvas можно стилизовать с помощью CSS, находиться под или над другими частями страницы. Составлено (смешанное) с другими частями страницы. Преобразоваться, поворачиваться, масштабироваться CSS вместе с другими частями страницы. Это большая разница с OpenGL или OpenGL ES.