Введение в 3D: основы Three.js

  • Tutorial

Cложность Web меняется ежедневно, и его возможности растут так же быстро, особенно с 3D-рендерингом. Кто только начинает вливаться в тему 3D — добро пожаловать под кат.



Зайдем издалека


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

Работа с WebGL, и с шейдерами в частности, — это довольно трудоемкий процесс. В процессе разработки необходимо описать каждую точку, линию, грань и так далее. Чтобы все это визуализировать, нам необходимо прописать довольно объемный кусок кода. Для повышения скорости разработки, была разработана библиотека Three.js.

Three.js – это библиотека JavaScript, содержащая набор готовых классов для создания и отображения интерактивной 3D графики в WebGL.

Three.js для WebGL — это то же самое, что jQuery для JavaScript. Библиотека предлагает декларативный синтаксис, и абстрагирует от головных болей связанных с 3D в браузере. Давайте проведем общий обзор и посмотрим, как начать работу, если вы новичок в мире 3D.

Подробнее о Three.js


Библиотека Three.js, как уже упоминалось, облегчает работу с WebGL. При использовании Three.js отпадает необходимость в написании шейдеров (но возможность остается), и появляется возможность оперировать привычными понятиями.

Над библиотекой работает большое количество разработчиков. Главным идеологом и разработчиком является Ricardo Cobello, известный под творческим псевдонимом Mr.Doob.

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

Три, так называемых, кита Three.js включают в себя:

  • Scene — своеобразная платформа, где размещаются все объекты, которые мы создаем;
  • Camera — по сути — это “глаз”, который будет направлен на сцену. Камера снимает и отображает объекты, которые расположены на сцене;
  • Renderer — визуализатор, который позволяет показывать сцену, снятую камерой.

В Three.js существует несколько типов камеры:

  • Perspective Camera
  • Stereo Camera
  • Orthographic Camera
  • Cube Camera

Самые распространенные из них — это Perspective Camera и Orthographic Camera.

Perspective Camera


Это наиболее распространенный режим проекции, используемый для рендеринга 3D-сцены.

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



Перспективная камера принимает 4 аргумента:

  • FOV или Field Of View (поле/угол зрения) — определяет угол, который вы можете видеть вокруг центра камеры.
  • Aspect ratio — пропорция, или, соотношение ширины к высоте экрана. При больших значениях поля зрения видимый размер объектов быстро уменьшается на удалении. При маленьких значениях, наоборот, видимый размер объектов слабо зависит от расстояния.
  • Near & Far — минимальное и максимальное расстояние от камеры, которое попадает в рендеринг. Так, очень далекие точки не будут отрисовываться вообще, как и точки, которые находятся очень близко.



Orthographic Camera


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

В данном случае все перпендикулярные прямые остаются перпендикулярными, все параллельные — параллельными. Если мы будем двигать камеру, прямые и объекты не будут искажаться.

Это может быть полезным при отображении 2D сцен и элементов UI.



Освещение


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

Примеры освещения:

  • Ambient Light — фоновое освещение, которое используется для освещения всех объектов сцены одинаково; не может быть использован для создания теней, так как не имеет направления.
  • Directional Light — свет, который излучается в определенном направлении. Этот свет будет вести себя так, как если бы он был бесконечно далеко, а лучи, излучаемые из него, были параллельны; данное освещение может отбрасывать тени, так как направлено оно на конкретный объект.
  • Point Light — свет, который излучается из одной точки во всех направлениях. Обычный случай использования такого освещения это повторение освещения от простой лампочки (без светильника).
  • Spot Light — данный свет излучается из одной точки в одном направлении, вдоль конуса, расширяемого по мере удаления от источника света.



Создание объектов на сцене


Объект, создаваемый на сцене, называется Mesh.

Mesh — это класс, представляющий объекты на основе треугольной полигональной сетки.

Этот класс принимает 2 аргумента:

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

Попробуем создать 2 простейшие фигуры: куб и сферу.

Первым делом переходим на сайт three.js, скачиваем последнюю версию библиотеки. Затем подключаем библиотеку в секции head или в начало секции body нашего документа, и все готово:

<!DOCTYPE html>
<html>
  <head>
    <meta charset=utf-8>
    <title>First Three.js app</title>
    <style>
      body { margin: 0; }
      canvas { width: 100%; height: 100% }
      </style>
  </head>
  <body>
    <script src="js/three.js"></script>
    <script>
      // Здесь Javascript код.
    </script>
  </body>
</html>

Далее, чтобы мы могли отобразить создаваемый объект, необходимо создать сцену, добавить камеру и настроить рендер.

Добавляем сцену:
var scene = new THREE.Scene();

Добавляем перспективную камеру:

var camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );

Камера принимает на себя 4 параметра, о которых было упомянуто выше:

  • угол зрения или FOV, в нашем случае это стандартный угол 75;
  • второй параметр — соотношение сторон или aspect ratio;
  • третьим и четвертым параметром идут минимальное и максимальное расстояние от камеры, которое попадет в рендеринг.

Добавляем и настраиваем рендер:

var renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );

Что мы сделали: сначала создали объект рендера, затем установили его размер в соответствии с размером видимой области и, наконец, добавили его на страницу, чтобы создать пустой элемент canvas, с которым будем работать.

После создания рендера указываем, где нужно отобразить тег canvas. В нашем случае мы добавили его в тег body.

Для создания самого куба сначала задаем геометрию:

var geometry = new THREE.BoxGeometry( 10, 10, 10);

Куб создается при помощи класса BoxGeometry. Это класс, который содержит в себе вершины и грани куба. Передаем размеры:

  • width: ширина куба, размер сторон по оси X
  • height: высота куба, т.е. размер сторон по оси Y
  • depth: глубина куба, т.е. размер сторон по оси Z

Чтобы раскрасить куб, задаем материал:

var material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );

В нашем случае задан MeshBasicMaterial и передан параметр цвета 0x00ff00, т.е. зеленый цвет. Этот материал в принципе используется для придания фигуре однородного цвета. Минус в том, что у фигуры пропадает глубина. Но этот материал вполне пригодиться при отрисовке каркасов при помощи параметра { wireframe: true }.

Теперь нам нужен объект Mesh, который принимает геометрию, и применяет к нему материал:

var cube = new THREE.Mesh( geometry, material );
scene.add( cube );

camera.position.z = 25;

Добавляем Mesh на сцену и отодвигаем камеру, так как все объекты после метода scene.add() по умолчанию добавляются с координатами (0,0,0), из-за чего камера и куб будут в одной точке.

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

function render() {
        requestAnimationFrame( render );
  cube.rotation.x += 0.01;
  cube.rotation.y += 0.01;      
  renderer.render( scene, camera );
}
render();

requestAnimationFrame — это запрос к браузеру, что вы хотите что-то анимировать. Мы передаем ему функцию для вызова, то есть функцию render().

Здесь же задаем параметры скорости вращения. В результате, цикл рендерит нашу сцену 60 раз в секунду и заставляет куб вращаться.


Теперь нарисуем сферу:

var geometry = new THREE.SphereGeometry(1, 32, 32);

Для построения сферы используется класс SphereGeometry, который принимает на себя:

  • радиус (значение по умолчанию равно 1)
  • widthSegments — количество горизонтальных сегментов (треугольников). Минимальное значение равно 3, значение по умолчанию 8
  • heightSegments — количество вертикальных сегментов. Минимальное значение равно 2, значение по умолчанию 6

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

Далее пробуем использовать другой материал — MeshNormalMaterial — многоцветный материал, который который сопоставляет векторы нормалей в RGB цвета:

var material = new THREE.MeshNormalMaterial();
var sphere = new THREE.Mesh( geometry, material );
scene.add( sphere );
camera.position.z = 3;

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

Последним шагом задаем цикл рендеринга:

function render() {
	requestAnimationFrame( render );
	sphere.rotation.x += 0.01;
  sphere.rotation.y += 0.01;
  renderer.render( scene, camera );
}
render();

И получаем следующее:


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

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

var scene = new THREE.Scene();
var spotLight = new THREE.SpotLight(0xeeeece);
spotLight.position.set(1000, 1000, 1000);
scene.add(spotLight);
var spotLight2 = new THREE.SpotLight(0xffffff);
spotLight2.position.set( -200, -200, -200);
scene.add(spotLight2);

SpotLight, как упоминалось выше, излучается из одной точки в одном направлении, вдоль конуса, расширяемого по мере удаления от источника света. Точечный свет помимо цвета может принимать на себя аргументы: intensity, distance, angle, penumbra, decay, а также отбрасывать тени.

О других типах света и их возможностях можно почитать тут.

Теперь определим саму фигуру:

var geometry = new THREE.TorusGeometry( 10, 3, 16, 100 );

Класс TorusGeometry предназначен для построения торусов или “валиков”. Этот класс принимает на себя следующие параметры:

  • радиус, по умолчанию 1;
  • диаметр трубы, по умолчанию 0.4;
  • radialSegments или количество сегментов-треугольников, по умолчанию 8;
  • tubularSegments или количество сегментов-граней, по умолчанию 6

Добавляем материал:

var material = new THREE.MeshPhongMaterial( {
color: 0xdaa520,
specular: 0xbcbcbc,
 } );

Этот материал предназначен для блестящих поверхностей. Ему мы передаем золотистый цвет, и добавляем свойство specular, которое влияет на блеск материала и его цвет. Цвет по умолчанию — 0x111111 — темно-серый.

Рендерим, и вот, что в итоге у нас получилось:


Еще немного о возможностях Three.js


Для включения Three.js в проект, нужно просто запустить npm install three.

Если вы объединяете файлы с помощью Webpack или Browserify, которые позволяют осуществлять require ('modules') в браузере, объединяя все ваши зависимости, у вас есть возможность импортировать модуль в свои исходные файлы и продолжить использовать его в обычном режиме:

var THREE = require('three');

var scene = new THREE.Scene();
...

Также есть возможность использования импорта синтаксиса ES6:

import * as THREE from 'three';

const scene = new THREE.Scene();
...

Или, если хотите импортировать только отдельные части библиотеки Three.js, например Scene:

import { Scene } from 'three';

const scene = new Scene();
...

Заключение


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

Библиотека Three.js позволяет творить и создавать действительно здоровские вещи. Вот несколько залипательных примеров:

Пример 1
Пример 2
Пример 3

Если вы хотите начать изучать 3D в JavaScript, все необходимое вы можете найти здесь или здесь.

Similar posts

AdBlock has stolen the banner, but banners are not teeth — they will be back

More
Ads

Comments 9

    0

    Вопрос не совсем в тему, но как вы интерактивные элементы в статью на хабре вставили?

      +1
      При помощи oembed:

      image

        0

        Не отображается :(

          +1
          Отредактировал коммент.

          В дополнение отмечу, что это все «магия» платформы CodePen:)
            0

            Спасибо! С телефона не отображалось.

      +2

      А можно узнать объективное мнение о разнице в Three.JS и BabylonJS? Кажется второй тоже достаточно популярен и, в чём-то, проще в освоении.

        +1
        Я особо не углублялся в BabylonJS, да и с TreeJS не работал так много, как хотелось бы.

        И Three.js, и Babylon.js — это простые в использовании библиотеки для работы с WebGL. Ключевым отличием могу назвать то, что Three.js был разработан для создания и отображения анимированной 3D-графики в веб-браузере, у этой библиотеки широкое назначение. В то время, как Babylon.js создавался для разработки 3D-игр, то есть он использует более целенаправленный подход.
        TreeJS — первопроходец, BabylonJS — достойный конкурент.

        На хабре, кстати, есть отличная статья на эту тему: Игровой мир WebGL или Three.js vs Babylon.js
          0
          ThreeJS имеет ряд недостатков. Например отсутствует нормальный Level Editor. Вы не можете составить сцену, а потом её импортировать. Саму интерактивную сцену приходится собирать в ручную в коде.
          Babylon.js и Playcanvas эту проблему решает. Вы создаете там сцену, а на её элементы уже вешаете необходимый код. Но как вы понимаете, это больше подходит для полноценных 3D проектов.
          Вопрос в том, как вы собираетесь на сайте использовать это 3D :). Если как полноценное 3D приложение, тогда смотрите в сторону babylon, а если только как 3D интерактивную вставку (как 3D картинку) — тогда Three.js отлично подойдет для решения ваших задач ).
          +1
          Отличная статья. Спасибо

          Only users with full accounts can post comments. Log in, please.