3D-графика через WebGL и ThreeJS


Содержание

Знакомство и подключение WebGl или OpenGl в JavaScript.

WebGL (Web-based Graphics Library) — программная библиотека для языка программирования JavaScript, позволяющая создавать на JavaScript интерактивную 3D-графику, функционирующую в широком спектре совместимых с ней веб-браузеров. За счёт использования низкоуровневых средств поддержки OpenGL, часть кода на WebGL может выполняться непосредственно на видеокартах.

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

Подготовка к визуализации в 3D
Первое, что вам понадобится для использования WebGL для визуализации в 3D — это элемент canvas. Фрагмент на HTML ниже содержит элемент canvas и определяет обработчик события onload, которое инициализирует наш контекст WebGL.

Подготовка контекста WebGL
Функция start(), в нашем JavaScript коде вызывается после загрузки документа. Ее назначение — настройка контекста WebGL и начать отрисовку содержимого.

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

Как только мы получили ссылку на canvas, мы вызываем функцию initWebGL(); Эту функцию мы определяем незамедлительно, ее работа — инициализировать контекст WebGL.

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

Всё вышеперечисленное необходимо сделать только для первоначальной инициализации. Чуть позже мы увидим работу по визуализации трехмерных объектов.

Создание контекста WebGL

Чтобы получить контекст WebGL для canvas, мы запрашиваем у элемента canvas контекст именуемый как «webgl». Если данная попытка завершается неудачно, мы пытаемся получить контекст, именуемый как «experimental-webgl». Если данная попытка также завершается неудачно, мы отображаем окно с предупреждением, позволяющим пользователю понять, что его браузер не поддерживает WebGL. Это всё, что необходимо сделать. На данном этапе мы будем иметь в переменной gl либо значение null (означающее, что контекст WebGL не доступен), либо ссылку на контекст WebGL в котором, мы будем производить отрисовку.

Изменение размера контекста WebGL
Новый контекст WebGL будет иметь возможность задания размеров област
Рабочий пример в прии отображения в момент получения контекста путем задания высоты и ширины элемента canvas, без использования CSS. Редактирование стиля элемента canvas будет изменять его отображаемый размер, без изменения размеров области отрисовки. Редактирование атрибутов ширины и высоты элемента canvas после создания контекста не будет также изменять число пикселей для отрисовки. Чтобы изменить размер области отрисовки, с которой WebGL производит работу, например, когда пользователь изменяет размер окна на весь экран или когда вам необходимо менять настройки графики в самом приложении, вам необходимо вызвать контекстную функцию WebGL viewport(), чтобы подтвердить изменения.

Чтобы изменить размер области отрисовки контекста WebGL с переменными gl и canvas, использующимися в примере выше:

Добавление двухмерного контента в контекст WebGL

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

Освещение сцены

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

Инициализация шейдеров
Шейдеры задаются при помощи языка высокого уровня для программирования шейдеров — OpenGL ES Shading Language. Для того, чтобы сделать проще процесс поддержки и обновления нашего контента, мы можем фактически написать наш код, загружающий шейдеры и помещающий их в HTML документ, вместо того, чтобы встраивать его весь в JavaScript. Давайте рассмотрим нашу процедуру initShaders(), которая выполнит эту задачу:

Затем мы создаем шейдерную программу, вызывая функцию createProgram() объекта WebGL, присоединяя два шейдера к нему, и связывая шейдерную программу. После выполнения этого, проверяется значение параметра LINK_STATUS объекта gl для того, чтобы убедиться, что программа успешно скомпанована. Если это так, мы активируем новую шейдерную программу.

Загрузка шейдеров из DOM
Функция getShader() получает из DOM шейдерную программу с определенным именем, возвращая скомпилированную шейдерную программу вызывающему, или значение null, если шейдерная программа не может быть загружена или скомпилирована.

Как только элемент с указанным ID найден, его текст помещается в переменную theSource.

После того, как код для шейдера считан, мы проверяем MIME тип шейдерного объекта, чтобы определить является он вершинным (MIME type «x-shader/x-vertex») или фрагментным (MIME type «x-shader/x-fragment») шейдером, а затем создаем соответствующий тип шейдера из полученного исходного кода.

Шейдеры
После этого нам необходимо добавить шейдерные программы в HTML описывающий наш документ. Подробная информация о том, как работают шейдеры выходит за рамки этой статьи, как и впрочем описание синтаксиса языка программирования шейдеров.
Фрагментный шейдер
Каждый пиксель в полигоне называется фрагментом в языке GL. Фрагментные шейдеры необходимы для назначения цвета для каждого пикселя. В данном случае, мы просто назначаем белый цвет каждому пикселю.
gl_FragColor — встроенная переменная GL, используемая для управления цветом фрагментов. Устанавливая ее значение назначаем цвет пикселям. Ниже приведен пример этого.
Вершинный шейдер
Вершинный шейдер определяет положение и форму каждой вершины.

Первый шаг — очистка цветом фона сцены контекста. Затем мы устанавливаем перспективу камеры. Мы устанавливаем угол обзора в 45°, с соотношением ширины к высоте равным 640/480 (размеры нашего объекта canvas). Мы также определяем, что мы хотим видеть отрисованными объекты на расстоянии от 0.1 до 100 единиц от камеры.

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

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

3D-анимация через WebGL и ThreeJS

Богдан Войдевич — front-end разработчик в креативном веб-агентстве Facility. Работает в сфере с 2012 года. Специалист в области разработке сайтов с WOW-эффектами. Выступал в этом году на FECONF-2020.

WebGL — это 3D для Интернета. В наше время развитие Web сфера позволяет использовать 3D графику в браузерах пользователей при просмотре web страницы. Использование библиотеки ThreeJS позволяет эффективно решить данную задачу.

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

  • Введение WebGL и ThreeJS;
  • Работа с камерой, светом и рендером;
  • Геометрия на сцене;
  • Стилизация текстур;
  • Анимация элементов.

Уровень аудитории: начальный.

Увидимся в Projector!

You are using an outdated browser. Please upgrade your browser to improve your experience.

WebGL — технология 3D графики в интернет

WebGL — технология 3D графики в интернет

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


Трёхмерный онлайн-контент — один из основных трендов современного Интернета.

Новый уровень вовлеченности

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

Стандарт WebGL

WebGL — API для работы с 3D-графикой в веб-браузере. WebGL не требует установки плагинов и поддерживается практически всеми современными браузерами как на стационарных, так и на мобильных платформах. Технология WebGL была впервые представлена в 2007 году и продолжает активно развиваться по сей день. Сейчас это стабильное и надёжное решение, индустриальный стандарт для интерактивной 3D-графики в Интернете.

Пиши один раз, запускай везде

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

Использование WebGL радикально упрощает разработку интерактивных веб-приложений. Однажды созданный, ваш проект будет одинаково выглядеть и одинаково хорошо работать везде.

Blend4Web — решение для WebGL

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

С его помощью обычный программист или 3D-художник получает возможность просто и быстро создать полноценное веб-приложение. А команда программистов, веб-дизайнеров и художников — средство для создания веб-приложений любой сложности, даже такого, которое ни в чём не уступит standalone-проектам.

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

[EN] Creative Coding with Canvas & WebGL

Научитесь использовать Canvas и WebGL с ThreeJS в этом курсе JavaScript по креативному кодированию! Путешествие по обширному миру графического программирования в Интернете. Узнайте о генеративном искусстве, интерактивной анимации, трехмерной графике с ThreeJS и пользовательских шейдерах в GLSL. Это фундаментальные концепции, лежащие в основе творческой разработки, в том числе приложения VR / AR, играх, художественных инсталляциях, интерактивных веб-интерфейсах и различных других видах вычислительного искусства.

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

С помощью WEBCL, ThreeJS, GLSL Вы сможете создавать по-истине оригинальные WEB-сайты, которые выходят за рамки привычного и смогут легко оставить позади даже самые крутые HTML сайты. Ведь данные технологии добавляют поддержки трехмерной графики, а за счет шейдеров, можно создавать различные эффекты, как для WEB-страниц, так и для изображений (фотографий), создавая не просто HTML-сайты, пусть и динамические, но нечто большее. WEBGL дает разработчику гораздо больше возможностей, чем любые из технологий разметки страницы (float, flex, grid).

Learn to use Canvas and WebGL with ThreeJS in this JavaScript course on Creative Coding! Tour the vast landscape of graphics programming on the web. Learn about generative art, interactive animations, 3D graphics with ThreeJS, and custom shaders in GLSL. These are the fundamental concepts behind creative development work, including VR/AR apps, games, art installations, interactive web experiences, and various other forms of computational arts.

Diving into 3D WebGL with Three.js

The web has been the most used platform for software development since the start of the 21st century as it transitioned from a document sharing platform to a home for scalable applications.

We have had the animation and gaming industry also move from traditional and 2D graphics/animations to 3D. More recently, there has been much innovation around virtual reality (VR) and augmented reality (AR), and most of that is also coming to the web.

As an organization that tries to stay at the top of trends and innovation, Google has just released Poly, a platform to browse and download 3D models and scenes.

This article is well timed, as we are only a few weeks away from December, the month of 3D — #3December. I hope the guide below helps you create stunning 3D art to be a part of it this year.

The following are elements that make up a 3D model:

I will go right into those in a bit, but first, I have to talk about the renderer.

If you’re familiar with frameworks like React, you’re aware of how nothing gets rendered to display without a renderer for the targeted platform — for the web that is the DOM (ReactDOM).

Since THREE.js is mostly used on the web, the WebGL renderer is used to render our scenes for display. The nature of the THREE.js API makes it such that its API can be used with any platform at all, as long as there is a 3D renderer available.

Now, without anything to display, let us render to a blank canvas. Grab the latest version of THREE.js from CDNJS

and start hacking.

The setSize method sets the size of the rendered display right before we append it as a element into the DOM.

The WebGLRenderer instance can take some parameters. One of the commonly used is the alpha to make the rest of the page display behind the canvas.

Scene

A scene, like in theater arts contains the characters, some lights, and has a camera to capture for rendering.

Camera

There are different cameras available with THREE.js. The perspective camera acts like a real world camera for our created 3D space as its projections are like that of the way human eyes would naturally project unto real-world objects. Orthographic camera projects an image that has a fixed size and look, no matter the distance it has from the model.

Here is a demo that shows the difference between both cameras.

See the Pen Penrose triangle by Louis Hoebregts (@Mamboleoo) on CodePen.

The demos here will focus on the perspective camera.


The PerspectiveCamera takes four arguments. The Field of View (FOV), the aspect ratio, the near clip pane, the far clip pane.

Tip: Aspect ratio should be the width of the element divided by the height. On a full web page, that translates to window width over window height

To understand how the field of view works, consider these Battlefield views

If you look closely, you will see that the view with a higher FOV captures more objects in the scene without necessarily seeming closer or more distant than that with a lesser FOV. Here is a bird’s eye view of what happens as you scale up the FOV

To affirm you are not lost, here is a summary of everything said so far in an image for a mind-picture.

The mesh is the 3D model. It is usually made up of a geometry and a material.

More on geometries and materials later.

Lighting

If you have ever had the privilege of being at a live drama or watched a movie being filmed, it is common to see lights around. They make the model visible and also aid the visualized direction (animated models) or position.

Илон Маск рекомендует:  Атрибут cellspacing в HTML

There are five properly supported and stable types of light in THREE.js namely:

  • Ambient Light
  • Directional Light
  • Hemisphere Light
  • Point Light
  • Spot Light

Ambient Light

This light gives no sense of direction as it casts no shadows on the objects in the scene. Here are some examples

Directional Light

A directional light acts like a distant outdoor sunlight. The parallel distant light rays cause it not to cast any shadows on the object in the scene.

This pen showed earlier to distinguish camera types, also uses directional light.

See the Pen Penrose triangle by Louis Hoebregts (@Mamboleoo) on CodePen.

Hemisphere Light

The hemisphere light illuminates the object from above the scene and fades gradually as it touches bottom.

Different lights can be added to a scene, so let us add a hemisphere light to the scene of trees with ambient light.

This light also does not cast shadows. As you can see, adding the hemisphere light just took the ambient lighted scene from a 06:30 pm look to a 08:00 am look.

Point Light

Point lights are like light bulbs and can be placed in different parts of the scene creating a sense of direction and casting shadows on the objects.

This demo shows a central source of light (moon) using a point light and different stars also using point light.

SpotLight

Like being in the spotlight and having the lights shine on you, you can create conic lights that are originating from a smaller light source and incrementally expanding as they shine on the object in the scene.

By adding the spotlight to the scene of trees from examples of above, we get this:

It allows shadow casting on each of the trees. Here is another spotlight example that reflects literally being a spotlight

The examples so far do not look applicable to real-world applications, and you might question the need to learn THREE.js or WebGL besides creative coding. To reorientate that thinking, here are some examples of 3D in web applications today:

LittleWorkshop created a WebVR experience to exhibit a showroom. Companies and individuals could adopt this for selling furniture or even subletting homes.

Redplant studio allows you to try on different colors on different parts of a bag. This could also be applied to most e-commerce websites, and the possibilities are endless from there on.

Summary

The goal of this article is to get you to understand the need for 3D and some of the THREE.js jargon required to build 3D applications in it.

The next article in this series will get your feet wet by walking you through ways to build your own 3D art.

Joseph Rex

X-Team Weekly

Our curated newsletter across programming, productivity, and inspiration.
Keep up to date with the X-Team culture.


Быстрый старт в WebGL (Quickstart in WebGL)

WebGL (Web-based Graphics Library) — кроссплатформенный API для 3D-графики в браузере. WebGL следует клиентскому подходу генерации цифрового изображения из модели (рендеринга) с использованием графического процессора (аппаратный рендеринг). Код WebGL приложения представляет собой сочетание HTML5, JavaScript (JS) и языка GLSL (OpenGL Shading Language):

  • WebGL интегрирован в JS, а JS интегрирован в HTML 5.
  • JS необходим для связи с центральным процессором (CPU — Central Processor Unit).
  • GLSL используется для связи с графическим процессором (GPU- Graphic Processor Unit).

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

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

Шейдер — компьютерная программа на языке GLSL, предназначенная для исполнения на GPU с его тысячами параллельно работающих ядер. Шейдеры бывают вершинными и фрагментными (еще их называют пиксельными).

Вершинный шейдер предназначен для обработки каждой вершины и нахождения её координат с учетом матриц модели и проекций. Фрагментный шейдер предназначен для расчета цвета каждого пикселя (двумерной точки).

Архитектуру WebGL-приложения сегодня в некотором смысле можно сравнить с тем, как наши предки видели вселенную.

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

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

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

Пример простого WebGL приложения

Ниже приводится текст кода приложения с использованием WebGL для рисования простого треугольника с 2D-координатами. Краткое описание фрагмента кода рассматривается в последующих разделах. С более подробным описанием этого и других приложений можно ознакомиться в статье WebGL — Quick Guide.

В программе были выполнены 5 следующих шагов:

Все эти шаги подробно описаны в разделах далее.

Определение WebGL контекста

WebGL-приложения написаны на языке JavaScript. Через него вы можете напрямую взаимодействовать с элементами HTML документа . В HTML5 определен элемент как «растровый холст, который может быть использован для отображения 2D графики. Через объект canvas можно получить WebGL контекст, который обеспечивает возможности 3D графики библиотеки OpenGL.

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

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

Создание 3D-модели и сохранение ее в буферах

Трехмерная модель создается с использованием следующих примитивов:

Вершины модели определяются в пространственной системе координат, плоскость xy которой совпадает с плоскостью окна:

В OpenGL WinApi C++ приложении (см. 3D графика на основе OpenGL WinApi C++) для отрисовки квадрата использовался бы такой код:

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

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

  • Vertex Buffer Object (VBO) — содержит данные для каждой вершины .
  • Index Buffer Object (IBO) — содержит индексы вершин.

Сохраняем вершины треугольника в массиве JavaScript и передаем этот массив в VBO.

Мы можем точно также сохранить индексы вершин треугольника в массиве и передать этот массив в IBO. Принципиальное отличие между созданием буферов для VBO и IBO лишь в выделенном красным цветом параметре:

Создание, компиляция и подключение шейдеров

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

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

Программа вершинного шейдера — код, выполняемый для каждой вершины:

Переменная coordinates объявлена с классификатором attribute. Значение такой переменной доступно в JS и в вершинном шейдере. Переменная coordinates будет связана с VBO через метод getAttribLocation (см. Шаг 4).

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

Шейдерные программы — независимые программы, Поэтому их можно написать как отдельный скрипт или можно хранить непосредственно в строковом формате:


Программа фрагметного шейдера — код, выполняемый для каждого пикселя:

В предопределенной переменной gl.FragColor сохраняется значение цвета пикселя.

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

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

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

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

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

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

Создание объекта-шейдера

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

Как указано в синтаксисе, этот метод принимает предопределенное значение перечисления в качестве параметра:

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

Прикрепление шейдерной программы к объекту-шейдеру

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

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

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

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

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

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

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

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

Комбинированная шейдерная программа

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

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

Создание программного объекта

Создается пустой программный объект с помощью метода createProgram ():

Присоединение шейдеров к программному объекту

Шейдеры присоединяются к созданному программному объекту, используя метод attachShader () :

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

  • program — пустой программный объект.
  • shader — один из скомпилированных шейдеров (вершинный или фрагментный шейдер)

С помощью метода attachShader() необходимо подключить оба шейдера.

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

Шейдеры связываются, используя метод linkProgram () :


shaderProgram — объект программы, к которому прикреплены шейдеры

Использование программы

Для использования программы WebGL предоставляет метод с именем useProgram ():

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

Фрагмент кода

Код для создания, компиляции и использования комбинированной шейдерной программы:

Связывание шейдеров с буферами

Атрибут программы вершинного шейдера необходимо связать с Vertex Buffer Object (VBO) в следующей последовательности:

  • Получить местоположение атрибута.
  • Указать атрибуту на VBO.
  • Активировать атрибут.

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

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

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

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

Указание атрибуту на VBO

Чтобы назначить VBO переменной атрибута, WebGL предоставляет метод:

Этот метод принимает шесть параметров:

  • location — указывает место хранения переменной атрибута. При использовании этой опции вы должны передать значение, возвращаемое методом getAttribLocation () .
  • size — определяет количество компонентов на вершину в объекте буфера.
  • type — указывает тип данных.
  • normalized — это логическое значение. Если true, неплавающие данные нормализуются до [0, 1]; в противном случае он нормализуется до [-1, 1].
  • stride — указывает количество байтов между различными элементами данных вершины или ноль для шага по умолчанию.
  • offset — указывает смещение (в байтах) в объекте буфера, чтобы указать, из какого байта хранятся данные вершины. Если данные сохраняются с самого начала, offset равно 0.

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

Активация атрибута

Для активации атрибута вершинного шейдера с получением доступа к VBO используется метод enableVertexAttribArray (). Этот метод принимает в качестве параметра переменную, которая хранит местоположение атрибута.

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

Отображение графики

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

Метод drawArrays ()

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

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

  • 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 создает геометрию в порядке, в котором определены координаты вершины.

Примеры

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

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

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

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

drawElements ()


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

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

  • mode — модели WebGL отрисовываются с использованием примитивных типов. Используя режим, программисты должны выбрать один из примитивных типов, предоставляемых WebGL. Список возможных значений для этого параметра — gl.POINTS, gl.LINE_STRIP, gl.LINE_LOOP, gl.LINES, gl.TRIANGLE_STRIP, gl.TRIANGLE_FAN и gl.TRIANGLES.
  • count — эта опция указывает количество элементов для визуализации.
  • type — эта опция указывает тип данных индексов, который должен быть UNSIGNED_BYTE или UNSIGNED_SHORT.
  • offset — эта опция указывает начальную точку рендеринга. Обычно это первый элемент (0).

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

Пример

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

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

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

Компьютерная графика c применением Threejs

Не так давно гуляя по просторам интернета, я наткнулся на интересную штуку под названием Threejs. Она представляет из себя кроссбраузерную библиотеку и позволяет создавать ускоренную на GPU 3D графику, используя язык JavaScript как часть сайта без подключения проприетарных плагинов для браузера. Это возможно благодаря использованию технологии WebGL. Не буду на ней останавливаться, лишь только скажу, что она основывается на использования низкоуровневых средств поддержки OpenGL, т.е. часть кода на WebGL может выполняться непосредственно на видеокартах. Программы, исполняемые на графических процессорах, называются шейдерами.

Илон Маск рекомендует:  Oracle введение в проектирование информационных систем

Шейдер – небольшая программа, выполняемая на стороне видеокарты или другого аппаратного, или программного устройства рендеринга, которая позволяет производить отдельные элементы цикла рендеринга объекта особым, отличным от стандартного, образом. Иначе говоря, шейдер – программа, выполняющая некоторую часть цикла рендеринга.

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

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

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

Геометрический шейдер, в отличие от вершинного, способен обработать не только одну вершину, но и целый примитив.

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

Хватит теории. Окунёмся в моё прошлое. Первый опыт работы с компьютерной графикой я получил на лабораторных работах по КГ в институте. Это были одни из самых интереснейший лабораторных работ. Всё началось с WinApi, и результатом была такая программка. Буквы прыгали и крутились.

После прекрасного домика я стал познавать азы OpenGL.

А это просто шедевр=) Вращающаяся и переливающаяся фигура.

Была даже работа с визуализацией части солнечной системы.

Всеми любимая змейка стала даже темой моей курсовой. Реализована она была также на OpenGL.

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

Плавно переходим к шейдерам. Первой задачей было реализовать флаг Бенина. В результате вышло как-то так.

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

Постепенно для написания шейдеров мы стали применять специальные программы для разработки шейдеров.

Здесь использовалась программа для GLSL шейдеров Render Monkey. На картинке же продемонстрирован 3D объект (куб) с микрорельефом.

Также удалось поработать с параллельные вычисления на GPU. Использовался OpenCL и опять всё те же шейдеры. На картинки продемонстрирован эффект акварели.

Сам шейдер был такой:

Всё хватит истории. Пора вернуться к текущему моменту времени и к основной теме статьи.

Налив чашечку кофе с молочком, вспомнив былое я начал разбираться в только что скаченной библиотеки Threejs. Закинул её на локальный сервер, иначе некоторые функции могут не работать.

Создаём html файл примерно с таким кодом.

Подключим дополнительные библиотеки.

Теперь сформируем два шейдера

Определим переменные и создадим необходимые функции

Функция animate() и onWindowResize() содержат стандартный код. Если захочешь ищи в гугле).

Подключаем необходимый шрифт в формате json. Можно найти в папке со скаченной библиотекой по следующему пути examples\fonts.


Теперь перейдём к функции init(). Фрагменты кода представлены ниже.

Описываем материалы для объектов и параметры для надписи, которую будем выводить на экран.

Здесь параметры завышать особо не стоит, ибо FPS может сильно просесть. Всё зависит от мощности GPU.

Идем далее. Работаем собственно с шейдерами и добавляем созданный текст на сцену.

Осталось немного в функцию рендера вставляем следующую строку

Смотрим результат в браузере

Это ещё не конец. Добавим управление мышью. Не зря же мы библиотеку подключали (OrbitControls.js).

Удерживая левую кнопку мыши у нас будет вращение камеры, а правую изменение её местоположения.

Что-то фон мрачненький. Сделаем, пожалуй, Skybox(SkySphere).

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

Автоматически библиотекой dat.gui.min.js к клавише H привязано скрытие/отображение меню с параметрами. Мне показалось это не очень удобным для применения технологии в проектах. Поэтому в данной библиотеке я переназначил событие на менее используемую клавишу (F9).

Ну и в завершении я добавил автоматическое вращение текста и эффект распада.

В завершении хочу сказать, что данная библиотека реально очень классная и полезная.

Оставлю несколько интересный ссылок:

Небольшая галерея с результатами прилагается.

1. WEB — графика с Three.js. Общий принцип создания графики на Three.js

Three.js — это легкая библиотека для создания кроссбраузерных графических WEB приложений. Данная библиотека для отображения графики может использовать как Canvas из HTML5, как SVG для отображения 2D графики, так и WebGL для отображения 3D графики.

Примечание. Что плохо, так это то, что раз WebGL работает не во всех браузерах и типичным примером этого является отсутствие поддержки WebGL в JDK, посредством которых можно было бы создавать 3D программы на HTML5, из-за чего моя любимая платформа JavaFX не удовлетворяет меня в некоторых моих проектах �� , но есть Canvas и SVG.

Последнюю версию Three.js можно скачать с репозитории GitHub или на официальном сайте Three.js. После распаковки архива у вас есть целый набор примеров и вспомогательных инструментов для работы с графикой. Следует отметить, что для работы некоторых примеров потребуется сервер, без которого они, наверняка не заработают в браузере, а так для начала достаточно обычного текстового редактора и навыков работы на HTML/JavaScript. Библиотека Three.js сама по себе кроссбраузерна, но если мы будем писать на голом JavaScript необходимо помнить, что пользовательский код на JavaScript должен быть оптимизирован под каждый браузер, а можно сделать еще легче — использовать кроссбраузерную библиотеку, такую как jQuery, но для простых примеров сойдет и обычный JavaScript �� .

Прежде чем идти дальше, давайте разберем общую архитектуру построения Three.js — приложений и обозначим основные моменты, на которых следует акцентировать внимание. Ниже приведен рисунок, который отражает основной принцип. Все, что отображает Threejs — это либо объекты Canvas, либо SVG или WebGL, а JavaScript выступает связующим звеном между DOM HTML — интерфейса страницы — 6 и элементами сцены — 1 Three.js. В простейшем случае сцена может состоять из самой области вывода — 1, она так и называется — сцена(Scene), из камеры — 2, из объектов, которых мы хотим отобразить — 3 и освещения — пока этого всего нам достаточно, чтобы рассмотреть простейшие примеры. После окончания построения сцены начинается этап рендеринга(прорисовки) — 4 и приема пользовательских команд для изменения состояния элементов сцены — 1.

Итак, что нам нужно сделать для того, чтобы отобразить простой объект в окне браузера:

  • создать сцену;
  • создать рендер;
  • создать освещение;
  • создать камеру;
  • создать объекты;
  • добавить освещение, камеру и объекты на сцену;
  • добавить сцену на рендер;

Давайте теперь приступим к процессу кодирования и для этого нам, в первую очередь, будет необходимо создать скелет пустого HTML с названием index.html

В разделе head мы подключаем библиотеку Three.js и наш рабочий скрипт, который мы назвали script.js, обеих закинули в папку js, из которого мы их читаем. Библиотека Three.js находиться в скачанном архиве в папке build, причем есть компрессивная и полная версия, разницы нет, кроме как в размере файла. В компрессивном отсутствуют лишние пробелы и символы. Итак, мы подключили файлы библиотеки и нашего рабочего скрипта, теперьпосмотрим на наш файл script.js

В итоге должен получиться вот такой вот результат

Изучение WebGL и three.js

Я новичок и начинаю изучать 3D-компьютерную графику в веб-браузерах. Я заинтересован в создании 3D-игр в браузере. Для тех, кто изучил как WebGL, так и three.js.

Требуется ли знание WebGL для использования three.js?

В чем преимущества использования трех. js против WebGL?

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

Это означает, что вам нужно понять:

  • Концепции WebGL
  • Three.js
  • Основные математические понятия

Three.js. Three.js отлично справляется с абстрагированием многих деталей WebGL, поэтому лично я предлагаю использовать Three.js для вашего проекта. Но помните, что Three.js находится в альфе, и она часто меняется, поэтому вы должны быть готовы к этому. Большинство людей изучают Tr.js, изучая примеры. Избегайте устаревших книг и руководств и избегайте примеров из сети, ссылающихся на старые версии библиотеки.

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

Математика. Опять же, вы, по крайней мере, должны понимать понятия. Три хорошие книги:

3D Math Primer для разработки графики и игр от Fletcher Dunn и Ian Parberry


Существенная математика для игр и интерактивных приложений: руководство программистов Джеймса М. Ван Верта и Ларса М. Бишопа

Математика для программирования 3D-игр и компьютерной графики Эрика Лендьеля

Я надеюсь, что это будет полезно для вас. Удачи.

DevBurn

О разработке и не только…

WebGL Урок 1 — Треугольник и квадрат

Давайте поднимемся до этой функции и взглянем на нее:

Она, в свою очередь, вызывает функции для инициализации WebGL и шейдеров, которые я упоминал ранее, передавая в них параметром элемент canvas, на котором мы хотим нарисовать 3D-объекты, и затем инициализирует буферы функцией initBuffers. Буферы содержат описание треугольника и квадрата, которые мы будем рисовать — мы вскоре о них поговорим. Далее функция выполняет базовую настройку WebGL — заливает canvas черным цветом, очищая его, и включает проверку глубины (чтобы объекты, нарисованные позади других объектов, скрывались объектами, находящимися впереди них). Эти настройки выполняются через вызов методов объекта gl — мы увидим, как он инициализируется, немного позже. И, наконец, вызывается функция drawScene, которая рисует треугольник и квадрат на основании буферов.

Позже мы обязательно вернемся к initGL и initShaders, так как они важны в понимании принципов работы, но сначала взглянем на initBuffers и drawScene.

Сначала initBuffers, строчка за строчкой:

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

Мы создали буфер для координат вершин треугольника. Вершины — это точки в измерении 3D, которые определяют форму, которую мы рисуем. Для нашего треугольника мы имеем три точки (которые мы установим с минуты на минуту). Этот буфер фактически является кусочком области памяти на видеокарте. Устанавливая вершины один раз при инициализации, мы затем при отрисовке сцены просто говорим WebGL «нарисуй мне то, о чем я тебе говорил ранее», и так мы можем сделать наш код действительно эффективным, особенно при анимации сцен, где объекты рисуются десятки раз в секунду для создания движения. Конечно, когда у нас всего лишь три вершины, их запись в память видеокарты не будет проблемой. Но когда вы имеете дело с большими моделями, состоящими из десятков тысяч вершин, правильное использование буферов будет существенным плюсом. Далее:

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

Далее, мы определяем координаты вершин через массив JavaScript. Как вы можете видеть, это точки равнобедренного треугольника с центром в (0, 0, 0).

Теперь мы создали объект Float32Array на основании нашего массива JavaScript и сказали, чтобы WebGL использовал его для заполнения текущего буфера, которым конечно же является наш triangleVertexPositionBuffer. Мы поговорим подробнее о Float32Arrays в будущих уроках, а пока все, что вам нужно знать, что это путь преобразования массива JavaScript в нечто подходящее для заполнения буфера WebGL.

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

Теперь мы закончили настройку буфера для треугольника и приступаем к квадрату:

Здесь все довольно очевидно — квадрат имеет четыре вершины вместо трех и поэтому массив больше и numItems отличается.

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

Первое, что нам нужно сделать — немного рассказать WebGL о размерах элемента canvas, используя функцию viewport. Мы вернемся к тому, почему это важно, в (гораздо!) более поздних уроках. Сейчас вам просто нужно знать, что нужно вызывать эту функцию с размерами canvas в качестве параметров перед началом отрисовки. Затем мы очищаем canvas для подготовки к отрисовке:

Мы установили перспективу, с которой мы хотим обозревать сцену. По умолчанию близкие объекты будут иметь тот же размер, что и очень отдаленные (такой стиль 3D называется ортографическая проекция). Чтобы отдаленные объекты выглядели меньше, нам нужно немного рассказать о перспективе. Для этой сцены мы говорим, что наше (вертикальное) поле зрения — 45°, сообщаем отношение ширины к высоте элемента canvas и говорим, что не хотим видеть объекты ближе 0.1 единиц и дальше 100 единиц.

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

Теперь, когда мы определили перспективу, мы можем продолжить двигаться к отрисовке объектов:

Сначала нужно «переместиться» в центр 3D-сцены. В OpenGL при отрисовке сцены каждый объект отрисовывается в «текущей» позиции с «текущим» поворотом — например, вы говорите «переместись на 20 единиц прямо, повернись на 32 градуса и нарисуй робота», что в свою очередь является сложным набором инструкций «это смести, немного поверни, отрисуй». Это удобно, потому что вы можете поместить код «нарисуй робота» в функцию и затем легко устанавливать положение робота просто изменением параметров перемещения/поворота и вызовом этой функции.

Текущее положение и текущий поворот находятся в матрице. Как вы, возможно, изучали в школе, матрицы могут представлять собой переходы (перемещение из одной координаты в другую), повороты и другие геометрические трансформации. По некоторым причинам, в которые я не хочу сейчас углубляться, используется матрица размером 4х4 (не 3х3) для представления любого количество трансформаций в 3D-пространстве. Вы начинаете с единичной матрицы — да, именно так, первая матрица представляет собой преобразование, которое ничего не меняет — затем умножаете на матрицу, которая осуществляет первое преобразование, затем второе преобразование и так далее. Комбинированная матрица объединяет все преобразования в одной матрице. Матрица, которую мы используем для представления текущего состояния положения/поворота, называется модель-вид матрицей. Как вы уже наверное догадались, переменная mvMatrix содержит матрицу модель-вид, а функция mat4.identity устанавливает ее в единичную матрицу, чтобы мы могли начать умножение на переходы и повороты. Другими словами, функция переносит нас в начальную точку, из которой мы можем двигаться к отрисовке нашего 3D-мира.

Илон Маск рекомендует:  Почти все о заставках

Внимательный читатель заметит, что в начале обсуждения матриц я сказал «в OpenGL», не «в WebGL». Все потому, что WebGL не содержит такого функционала в графической библиотеке. Вместо этого мы используем стороннюю библиотеку матриц — замечательную glMatrix от Brandon Jones — плюс некоторые изящные ухищрения для достижения того же эффекта. Об этих ухищрениях поговорим позже.

Хорошо, двигаемся дальше по коду, который рисует треугольник на левой части нашего canvas.

После перемещения центра нашего 3D-пространства установкой mvMatrix в единичную матрицу мы двигаем треугольник на 1.5 единицы влево (отрицательное число по оси X) и на семь единиц внутрь сцены (отдаляемся от наблюдателя, отрицательное значение по оси Z). (mat4.translate, как вы могли уже догадаться, означает «умножить данную матрицу на матрицу перехода со следующими параметрами»)

Следующим шагом будет начало непосредственной отрисовки!

Итак, вы помните, что для использования одного из наших буферов, мы вызываем gl.bindBuffer для указания текущего буфера и затем вызываем код, который оперирует им. Здесь мы выбираем наш triangleVertexPositionBuffer, затем говорим WebGL, что его значения должны быть использованы как координаты вершин. Я объясню немного больше о том, как это работает, позже. Сейчас вы можете увидеть, что мы используем свойство itemSize, которое мы устанавливали на буфере, чтобы сказать WebGL, что каждый элемент в буфере содержит три числа.

Здесь мы говорим WebGL учитывать нашу текущую матрицу модель-вид (а также проекционную матрицу, о которой позже). Это необходимо, потому что вся эта работа с матрицами не встроена в WebGL. Все дело в том, что все изменения в переменной mvMatrix происходят только в пространстве JavaScript. Функция setMatrixUniforms, которая определена выше по коду, переносит эти изменения в видеокарту.

Теперь WebGL имеет массив чисел, он знает, что это координаты вершин, и он знает о наших матрицах. Пора сказать, что с этим всем нужно сделать:

Или другими словами «отрисуй треугольниками массив вершин, который я дал тебе ранее, начиная с индекса 0 в массиве и до элемента номер numItems».

После этого WebGL отобразит наш треугольник. Приступаем к квадрату:

Мы начнем с движения нашей матрицы модель-вид на три единицы вправо. Помните, что мы уже смещены на 1.5 единицы влево и на 7 единиц отдалены от сцены, поэтому после этого движения мы будем смещены на 1.5 единицы вправо и на 7 единиц вдаль. Далее:

Так мы сообщаем WebGL, что нужно использовать наш буфер квадрата для координат вершин…

…снова переносим матрицу модель-вид и матрицу проекции (чтобы изменения mvTranslate отразились в видеокарте) и наконец:


…отрисовываем точки. Вы спросите, что такое TRIANGLE_STRIP? Что ж, дословно это «лента треугольников» :). Если точнее, то это последовательность треугольников, когда первые три вершины массива образуют первый треугольник, затем две последних вершины первого треугольника и одна следующая за ними вершина образуют второй треугольник и так далее. В нашем случае это такой сляпанный наспех способ задания квадрата. В более сложных примерах такой способ может быть очень полезен для задания сложных поверхностей треугольниками, которые аппроксимируют эти поверхности.

В любом случае, теперь мы можем закрыть функцию drawScene.

Если вы забрались так далеко, то определенно готовы начать экспериментировать. Копируйте код в локальный файл — либо из GitHub, либо из онлайн-версии. В последнем случае вам понадобится index.html и glMatrix-0.9.5.min.js. Запустите пример локально и убедитесь, что он работает. Затем попробуйте изменить некоторые координаты вершин — например, установите z-координату квадрата равной 2 или -3 и посмотрите, как он становится больше или меньше при приближении и отдалении. Или попробуйте изменить пару координат и посмотрите, как объект искривляется в перспективе. Играйтесь и не обращайте на меня никакого внимания. Я подожду.

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

Вы по-прежнему со мной? Спасибо :). Давайте сразу разберем самые скучные функции. Первая из них, вызываемая в webGLStart, — это initGL. Она почти на самом верху страницы и вот еще копия для справки:

Здесь все очень просто. Как вы могли заметить, функции initBuffers и drawScene часто обращались к объекту gl, который явно относится к «чему-то» из самого сердца WebGL. Функция берет это «что-то», которое называется контекстом WebGL, и инициализирует его через вызов контекста элемента canvas со стандартным именем контекста в качестве параметра (как вы могли догадаться, когда-нибудь имя контекста сменится с «experimental-webgl» на «webgl». Я обновлю этот урок и блог о нем, когда это случится. Подпишитесь на ленту RSS, если вы хотите узнать об этом — а также если хотите получать еженедельные новости о WebGL). Теперь, когда у нас есть контекст, мы снова воспользуемся возможностью JavaScript установить объекту любое свойство, чтобы хранить ширину и высоту элемента canvas, к которому этот объект относится. Затем мы сможем использовать эти свойства для настройки вида и перспективы в начале функции drawScene. На этом настройка контекста завершена.

После вызова initGL, функция webGLStart вызывает initShaders. Которая, конечно же, инициализирует шейдеры (спасибо, Кэп :)). Мы вернемся к ней позже, потому что сначала мы должны взглянуть на нашу матрицу модель-вид и на проекционную матрицу, которую я также упоминал ранее. Собственно, код:

Итак, мы определили переменную mvMatrix для матрицы модель-вид и pMatrix для проекционной матрицы и затем присваиваем им пустые (все элементы — нули) матрицы для начала работы. Стоит сказать немного больше о проекционной матрице. Как вы помните, мы использовали функцию mat4.perspective из glMatrix для установки нашей перспективы в начале функции drawScene. Это было необходимо, потому что WebGL напрямую не поддерживает перспективу, так же, как не поддерживает и матрицу модель-вид. Но как и процесс перемещения и вращения объектов заключается в матрице модель-вид, так и процесс отображения далеких объектов пропорционально более мелкими, чем близких объектов, отлично укладывается в логику матрицы. И, как вы несомненно догадались, этой матрицей служит проекционная матрица. Функция mat4.perspective с полем зрения и соотношением сторон заполняет матрицу значениями, которые устанавливают нужную нам перспективу.

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

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

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

И вот как они устанавливаются. Как вы помните, функция webGLStart вызывает initShaders, поэтому давайте пройдемся по ней строка за строкой:

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

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

Итак, для чего же нужен vertexPositionAttribute? Как вы возможно помните, мы использовали его в drawScene. Если вернуться к коду, который устанавливает вершины треугольника, вы увидите, что мы ассоциировали буфер с этим атрибутом. Скоро вы увидите, что это значит. А пока давайте обратим внимание, что мы также используем gl.enableVertexAttribArray, чтобы сказать WebGL, что мы хотим хотим передать значения для атрибута, используя массив.

Последнее, что делает функция initShaders — получает еще два значение из программы, положения двух вещей, называемых uniform-переменными. Скоро мы с ними столкнемся, а пока обратите внимание, что для удобства мы сохраняем их в объекте программы.

Теперь, взгляните на getShader:

Это еще одна функция, которая на самом деле гораздо проще, чем кажется на первый взгляд. Все, что мы здесь делаем — ищем на странице HTML-элемент, у которого ID равен значению параметра, получаем его содержимое, создаем фрагментный шейдер или вершинный шейдер в зависимости от его типа (о разнице между ними мы поговорим в следующих уроках) и затем передаем его в WebGL для компиляции в форму, которая может выполняться на видеокарте. Затем идет обработка ошибок — и все готово! Конечно, мы можем просто определить шейдеры в виде строк внутри кода JavaScript и не связываться с получением их из HTML. Но в HTML их гораздо удобнее читать, потому что они определены как скрипты на странице, как если бы они сами были JavaScript’ом.

Теперь взглянем на код шейдеров:

Первое, что нужно помнить, шейдеры не написаны на JavaScript, хотя происхождение языка очень похоже. В действительности, она написаны на специальном языке шейдеров, называемом GLSL — он многим обязан языку C (как и JavaScript, конечно).

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

Второй шейдер немного интереснее. Это вершинный шейдер, и он представляет собой часть кода видеокарты, который может делать с вершиной практически все, что угодно. Связанный с вершиной, шейдер содержит две uniform-переменные uMVMatrix и uPMatrix. Uniform-переменные очень полезны, потому что они доступны вне области шейдера — извне содержащей их программы, как вы помните из кода initShaders, где мы получали их расположение, и из кода, который мы сейчас рассмотрим, где мы присваиваем их значениям матрицы модель-вид и проекционной матрицы. Вы можете рассматривать программу шейдера как объект (в объектно-ориентированном смысле), а uniform-переменные — как поля этого объекта.

Шейдер вызывается для каждой вершины и вершина передается в код шейдера как aVertexPosition благодаря использованию vertexPositionAttribute в функции drawScene, когда мы назначили атрибут буферу. Небольшой кусочек кода в функции main шейдера просто умножает координаты вершины на матрицу модель-вид и проекционную матрицу и возвращает конечное положение вершины в качестве результата.

Итак, webGLStart вызывает initShaders, которая использует getShader для загрузки фрагментного шейдера и вершинного шейдера из скриптов веб-страницы, чтобы они были скомпилированы, переданы в WebGL и использованы в дальнейшем при отрисовке нашей 3D-сцены.

Ну и теперь необъясненной осталась только функция setMatrixUniforms, которую легко понять после всего того, что вы уже узнали :).

Здесь, используя ссылки на uniform-переменные, которые представляют наши проекционную матрицу и матрицу модель-вид, полученные в функции initShaders, мы передаем в WebGL значения из наших матриц в JavaScript.

Фух! Довольно много для первого урока, но надеюсь, что вы (и я тоже) поняли все основы, которые понадобятся нам при построении чего-нибудь более интересного — цветных, движущихся, настоящих трехмерных моделей WebGL. Хотите узнать больше? Читайте второй урок

10 thoughts on “ WebGL Урок 1 — Треугольник и квадрат ”

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

Слишком много фраз «это объясню позже». Не знаю как остальным, но мне не удобно скакать по урокам, чтобы разобраться в конкретном моменте. Но в целом, спасибо!

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

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

Добрый вечер! Очень интересует данная технология.
А вот как дизайнерам разрабатывать дизайн под такие проекты?
Дизайнеру нужно изучать языки программирования или как?
Если не сложно можете подробно рассказать.
Очень хочется начать использовать эту технологию на личных веб-сайтах. Но я больше специализируюсь на веб-дизайне.

Язык программирования изучать совсем не обязательно. Дизайнеры обычно работают в 3D-редакторах (Blender, 3ds Max, Maya), а затем либо показывают работу прямо в этом 3D-редакторе, либо куда-то экспортируют проект — например, в видео или на веб-страницу (если, конечно, у меня верные сведения о дизайнерах �� ).

Существуют и готовые решения для создания трёхмерных решений для сайтов — например, blend4web. На их сайте https://www.blend4web.com/ru масса демонстраций, мне понравилась демонстрация технологического процесса молокозавода https://www.blend4web.com/ru/demo/dairy_plant/

Сделал все как сказано, но выскакивают ошибки:
webgl.html:104 Uncaught ReferenceError: mat4 is not defined
at webgl.html:104
Uncaught ReferenceError: mat4 is not defined
at drawScene (webgl.html:147)
at webGLStart (webgl.html:176)
at onload (webgl.html:185)

Вероятней всего не подключена библиотека glMatrix. Посмотрите на код примера на GitHub — https://raw.githubusercontent.com/gpjt/webgl-lessons/master/lesson01/index.html

Вроде все обьесняно понятно но очень поверхностно и в целом я даже не смогу нарисовать треугольник, я вообще не понял шедевров и матриц(
Надеюсь остальные уроки объяснять что тут проходит.

Понравилась статья? Поделиться с друзьями:
Кодинг, CSS и SQL