В этой статье рассмотрим основы three.js — одного из самых быстрых 3D JavaScript движков.
Мы создадим простую сцену и разберём основные ключевые элементы движка.
Что будем делать?
В итоге у нас получится городок из разноцветных прямоугольников с тенями:
Управление: можно покрутить мышкой, колесом поприближать.
Версия в отдельно вкладке: ссылка.
Подробности и код
Я сделал эту демку взяв за основу проект шаблона Phaser2 на TypeScript под VSCode.
Всё что мне нужно было сделать — это приспособить threejs для TS и написать код.
TS расширения (файлы d.ts) для threejs и stats я взял из npm:
- для threejs: https://www.npmjs.com/package/@types/three
- для stats: https://www.npmjs.com/package/@types/stats
Прописываете их npm install в консоли и затем копируете файлы (оттуда куда они установились) в папку d.ts проекта.
Далее нужно изменить файл tsconfig.json, чтобы не было ошибок в чтении three js d.ts модулей:
Всё, основа готова, можно писать непосредственно код приложения.
Приведу код основных файлов.
В коде я старался соблюдать логический приоритет объектов по мере их создания, разберём их поподробнее.
Рендер
Рендер — основной элемент отображения. В нём настраиваются такие вещи как: antialias (сглаживание), тени и их тип, PixelRatio и другие основные элементы. Его нужно инициализировать и расположить на DOM элементе страницы, в моём случае это div с id=»game». Главная функция рендера — это render(scene, camera), в которую передаются следующие основные объекты: сцена и камера.
Эту функцию надо вызывать тогда, когда мы хотим отрисовать текущее состояние сцены, как правило это делают в событии AnimationFrame().
Современные браузеры, кроме IE9-, поддерживают стандарт Animation timing. Он позволяет синхронизировать наши анимации со встроенными механизмами обновления страницы. То есть, сгруппированы будут не только наши, но и CSS-анимации и другие браузерные перерисовки.
При этом графический ускоритель будет использован максимально эффективно, и исключена повторная обработка одних и тех же участков страницы. А значит – меньше будет загрузка CPU, да и сама анимация станет более плавной. Для этого используется функция requestAnimationFrame.
Сцена
Сцена — это root контейнер для всего, что может быть отображено нашим рендером (отрендерино). Если мы хотим, чтобы какой-то объект отобразился, то нужно добавить его на сцену.
Свет
Без источника света наша сцена будет просто чёрной, не освещаемой. Поэтому источник света необходим.
В Three.js существует 6 источников света, некоторые из них являются базовыми и имеются в любом 3D движке:
рассмотрим их поподробнее.
AmbientLight
Этот источник света освещает все объекты на сцене равномерно одинаково, его нельзя использовать как источник который отбрасывает тени, т.к. у него нет направления. Его можно использовать для придания оттенка теневой стороне объектов. Что я и сделал в данном примере, я создал этот источник с цветом 0x323232, чтобы теневая сторона объекта была не полностью чёрная, а мягко тёмно-серая.
DirrectionLight
Свет, который излучается в определенном направлении. Этот свет будет вести себя так, как если бы он был бесконечно далеко и его лучи параллельны. Т.е. этот источник имитирует наше Солнце. Ему можно задать позицию и направление свечения.
В данном примере я как раз применяю такой источник света для основного освещения.
PointLight
Свет, который излучается из одной точки во всех направлениях. Его можно использовать, например, для имитации света, излучаемого лампочкой.
SpotLight
Этот свет излучается из одной точки в одном направлении, вдоль конуса, который увеличивается в размере по мере удаления от источника. Другими словами — лучший вариант для имитации света прожектора или фонарика.
RectAreaLight
Источник света излучающийся с поверхности прямоугольника. По сути подобен SpotLight-у, только светит не из точки, а с прямоугольной плоскости.
Можно имитировать свет от окна или от неоновой полоски.
HemisphereLight
Этот источник света имитирует свечение небесной сферы, он подобен AmbientLight, только имеет 2 цвета освещения, один цвет освещает предметы сверху, а второй снизу.
Камера
Камера позволяет нам видеть нашу сцену. Существует 2 основных типа камеры: перспективной проекции и ортогональной проекции.
В данном примере я применил перспективную камеру.
Ортогональная камера создаёт впечатление 2D, вот пример:
Для управления камеры мышкой и тачем я использовал готовое решение — OrbitControls
Игровые объекты на сцене
Когда все основные элементы инициализированы, можно наполнять нашу сцену объектами. Данное действо происходит у меня в функции createScene().
Сначала я создаю 2 хелпера для системы координат и для источника света, можете раскомментировать их и посмотреть как они выглядят.
Затем я создаю плоскость, которая по идеи является землёй, а затем создаю рандомные прямоугольники-здания.
Можно обратить внимание, что все объекты — это меши.
Меш или сетка — этими терминами называют совокупность вершин, рёбер и полигонов, которые составляют один 3D объект. Слово меш походит от английского mesh — ячейка сети. А слово сетка — от английского wireframe, что переводится как каркас/проволочный каркас.
Так вот, меши создаются из 2-х составляющих, которые необходимы для определения их отображения: геометрия и текстура.
Для земли я использовал PlaneBufferGeometry (геометрию плоскости) и MeshLambertMaterial (материал без отбликов). А для домиков я использовал BoxGeometry (геометрия параллелепипеда) и такой же тип материала.
Далее я расставляю домики и придаю им рандомную высоту и цвет из заранее определённого массива. Так же я указываю мешу домика, чтобы он отбрасывал (castShadow) и принимал тень (receiveShadow), а плоскости земли только чтобы принимала.
В следующих статьях я обязательно разберу подробно все типы геометрии и материалов.
А видос?
Я записал видео, как с нуля сделал эту демку, взяв за основу свой шаблон TypeScript Phaser2:
Видео ускорено в 3 раза. Иногда я подглядывал в свой прошлогодний проект на three.js, чтобы вспомнить особенности добавления модулей и оформления теней.
Где скачать?
Как обычно весь код проекта залит в репозиторий.