WebGL и three.js. Урок 1. Основы

Я приветствую Вас на первом уроке курса «WebGL и three.js»! Прежде чем начать серию статей, давайте определимся, для кого они предназначены, какой уровень начальных знаний необходим, чтобы полноценно пройти этот курс.

Во-первых, должно быть понимание языка JavaScript: функций, циклов, массивов, объектов, синтаксиса и так далее. Без этого смотреть курс дальше нет никакого смысла (кроме как полюбоваться эффектами 3D).

Во-вторых, нужно, чтобы вы смогли развернуть (либо самостоятельно, либо по мануалу) локальный веб-сервер и создать папку с сайтом. Это нужно, чтобы AJAX корректно загрузил 3D-модели, которые мы будем вставлять в наши сцены в рамках курса. Если с этими пунктами проблем нет – добро пожаловать на курс!

Определимся, о чем этот курс, что такое WebGL и three.js.

WebGL – это программная библиотека для JavaScript’а, которая позволяет создавать 3D графику, функционирующую в браузерах. Другими словами, мы делаем 3D модель не на компьютере, в рамках программы, работающей в операционной системе, а непосредственно в браузере, но в то же время – это не флэш, к которому мы привыкли и не любим за то, что он постоянно тормозит. WebGL использует тег canvas, который появился в HTML5, но рисуем уже в 3D (а не в 2D, как привыкли).

Three.js – это библиотека, которая опирается на возможности WebGL и делает над ним надстройку, что позволяет работать с WebGL более удобным образом и писать меньше строчек кода.

Стоит объяснить, почему выбран three.js, а не чистый WebGL. Причин несколько. Первая и главная – быстрый результат. Когда вы пробуете новую технологию, вы являетесь в ней новичками, которым хочется увидеть моментальный результат. Сделать первую сцену, вывести машину в виде 3D модели и показывать друзьям, как она крутится, – здорово же! Гораздо интереснее, чем, скажем, две недели изучать шейдеры,  базовое отображение и создание материала для WebGL. Three.js же выполняет всю низкоуровневую работу с WebGL за нас, предоставляя набор классов с понятным интерфейсом для удобной работы с 3D графикой, а кроме этого, она позволяет быстро достичь результата, не разбираясь во всех сложностях и тонкостях в отображении материалов в WebGL. Скачать библиотеку и посмотреть множество интересных примеров можно на её официальном сайте (http://www.threejs.org). Мы также это будем делать в рамках всего курса: и смотреть готовые примеры, и писать свои.

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

Основные понятия WebGL и three.js

Первое, что появляется в 3D пространстве – это рендереры (так же называется класс в three.js). Рендерер – это сущность, отображающая на canvas выбранную сцену с выбранной камерой. Сцена – это 3D пространство, в котором располагаются нужные объекты: элементы (иначе - меши) и источники света, которые освещают элементы с какой-либо стороны. Для наглядности можно представить себе куб как самую простую сцену и три оси, где располагаются элементы. От чего в первую очередь зависит внешний вид элементов? А зависит он именно от камеры – той точки, с который мы сейчас смотрим на сцену (и в ту точку, куда мы смотрим). Поэтому рендерер, чтобы сделать отображение чего-либо на canvas, всегда принимает в себя (мы говорим уже о методе объекта WebGL) сцену и камеру. Именно эти две ключевых вещи формируют отображение пространства на тег canvas.

Что ещё есть на сцене? Источник света – элемент, который создаёт освещение. Он может быть рассеянным, точечным, направленным – всё это мы будем разбирать дальше в рамках курса. Самое главное и интересное понятие, которое здесь представлено, – это меш. Меш – это элемент сцены, который состоит из геометрии и материала. 3D объект – не простой объект, как мы хотели бы себе представить, а составная вещь. Любой объект, который мы хотим отобразить в 3D, состоит из геометрии и материала. Такой подход выбран, чтобы мы могли из простых геометрических примитивов создавать вещи, которые по-разному отображаются. Простейший пример геометрии материала: геометрия – это плоскость, материал – что-то, залитое красным цветом. В итоге получаем красную плоскость. Здесь разделяется структура и оформление. Кто знает HTML и CSS – а вы, скорее всего, их знаете, если слушаете этот курс, – то там существует такое же разделение, это тенденция.

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

Переходим непосредственно к материалу. Материал – вещь намного более сложная, чем цвет, поэтому на нём нужно остановиться подробнее. Материал – это способ отображения и внешний вид элемента. Здесь кроется интересная сложность: в прошлом примере   было сказано, что мы сделаем плоскость, к примеру, красной; но существует множество разных красных плоскостей, и происходит это потому, что материал – это именно способ отображения элемента. Какие-то элементы отражают свет и/или отбрасывают тени, а какие-то нет. И список можно продолжать – всё это зависит от материала. Материал – это ни в коем случае не просто цвет, это то, как он себя ведёт в рамках представления на сцене. Тени и отражение – простейшие примеры для демонстрации.

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

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

Примеры элементов на 3D сцене

(данную часть статьи нагляднее изучать по видео, которое находитися вверху экрана)

Итак, вы видите тег canvas, это первая сцена. Рендерер мы не видим никогда, потому что это камера плюс сцена. Сейчас мы увидим сцену, на которой будут три оси. Первая ось – это X, она идёт горизонтально, вторая ось – Y, идёт вертикально, третья – Z, которая идёт на нас и от нас.

three.js сцена и оси

Камера стоит немного сбоку, потому что если бы она стояла фронтально, увидеть ось Z не получилось бы. Оси должны быть понятны всем, направление привычное: по X слева минус, справа плюс; по Z вдали минус, вблизи плюс, по Y внизу минус, вверху плюс. Но обратите внимание на интересную деталь: ось Z почему-то толще в левой части экрана, а ближе к правой части становится всё тоньше и тоньше. Дело в том, что эта ось уходит всё дальше от нас, и камера отображает объекты согласно перспективе (это называется PerspectiveCamera, которая чаще всего используется на сцене). Есть ещё стандартная камера, но её отображение совсем нереалистичное: представьте обычную комнату, в которой у вещей нет перспективы.

Третью ось мы видим из определенной позиции камеры и смотрим – заметьте, это важно! – в определенном направлении. Сейчас мы оставляем камеру в той же точке, но меняем направление и смотрим по X в точку, скажем, 250.

three.js поворот камеры

Изображение изменилось, будто вы стоите в помещении в том же углу, что и раньше, но повернули голову и смотрите не на дверь, а на окно и видите совершенно другую картину. Кроме изменения точки, на которую мы смотрим, можно ещё изменить точку, откуда мы смотрим. Предположим, вы из угла комнаты перешли к двери, – теперь камера по X расположена ближе к нулю.

three.js перемещение камеры

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

Теперь посмотрим на такие понятия, как меш, геометрия и материалы. Сейчас на сцене постепенно появляется новый меш, который собран из геометрии под названием «прямоугольник» (по факту – это некая плоскость).

three.js plane geometry

Он составлен из материала, но материал не совсем обычный – не «basic material», а «phong material», самый сложный и самый реалистичный тип материала. На следующем этапе будет заметно, чем отличается поведение линии и плоскости. Линии составлены из «basic material» – самого простого материала, и просто покрашены в какой-то цвет, а плоскость составлена из реалистичного материала, и он, на самом деле, белый, но почему-то плоскость серая. Серой она является потому, что цвет источника освещения – 0х777777. Сейчас мы удалим из источника освещения синюю гамму и посмотрим, что произойдет: плоскость меняет свой цвет, а линии остаются такими же – продемонстрировано разное поведение материалов.

three.js plane geometry

Basic material не реагирует ни на что, а плоскость с реалистичным материалом реагирует на изменения освещения. Удалим ещё красную гамму: она становится зеленой.

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

three.js texture

По сути, мы передали в материал некую карту, которая указывает, как ему следует себя отображать. Если мы поменяем цвет источника освещения, например, переведем его на белый дневной свет, плоскость станет гораздо ярче. Текстура, на самом деле, зеленого цвета с синим кружком – эти цвета мы теперь видим так, как они были задуманы, а не так, как отображалось при освещении. То же самое, один в один, будет происходить, когда мы будем говорить уже не про плоскость, а про сложную 3D модель.

Загружаем 3D модель машины как готовый меш. Но меш обладает только геометрией, которая ещё никак не украшена.

three.js obj mesh

Разве это машина? Вы бы на такой согласились ездить?

three.js obj mesh texture

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

Поставим точку света: посмотрите, как от этого меняется 3D мир.

three.js obj point light

Мы поставили точку света ближе к нам, и получилось, что яркая часть сейчас освещена (которая ближе к левому углу), а дальше объект плоскости становится всё более зеленым. Это происходит потому, что свет туда долетает хуже. Это аналог лампы, которую вы поставили, направили на какую-нибудь доску, и ближнюю часть она освещает хорошо, а дальнюю – плохо. Свет может быть направленный, можно генерировать тени, но всё это мы с вами увидим и научимся делать в рамках следующих уроков.

На данном этапе мы рассмотрим этот 3D мир с разных сторон и подключим OrbitControl – специальную добавку к three.js. Таким образом мы можем покрутиться по сцене и посмотреть, как это выглядит.

three.js obj orbit control

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

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

А сейчас нужно обобщить основные понятия, которые мы сегодня узнали, посмотреть на иерархию отображения. Первоначально у нас есть рендерер – то, что работает с тегом canvas и выводит туда изображения. Он зависит от камеры и сцены: камера направлена на сцену. На сцене есть источники света – это массив, потому что их может быть много; много может быть и мешей – 3D объектов, которые заводятся на сцену. Каждый меш представляет собой геометрию и материал. Материал – это наиболее обширное понятие, есть «хитрые» материалы (например, с отражением), но это уже высший пилотаж, который мы сейчас рассматривать не будем.  Но так или иначе, материал включает в себя правила отображения, возможность поставить цвета, текстуры и многое другое. Так выглядит иерархия отображения в рамках просмотра сцены с простейшей стороны.

структура библиотеки three.js

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

На следующем уроке мы рассмотрим, как подключается библиотека three.js, создадим первую сцену и поставим туда какие-нибудь объекты.

Подписывайтесь на мой youtube канал, чтобы не пропустить следующие уроки!