Цель этого раздела — дать краткое введение в three.js. Мы начнем с настройки сцены с вращающимся кубом. Внизу страницы приведен рабочий пример на случай, если вы застрянете и вам понадобится помощь.
Перед тем как начать
Если вы еще этого не сделали, ознакомьтесь с руководством по установке. Мы предполагаем, что вы уже настроили ту же структуру проекта (включая index.html
и main.js
), установили three.js и используете либо инструмент сборки, либо локальный сервер с CDN и картами импорта.
Создание сцены
Чтобы иметь возможность что-либо отображать с помощью three.js, нам нужно три вещи: сцена, камера и рендерер, чтобы мы могли отобразить сцену с помощью камеры.
- main.js
import * as THREE from 'three'; const scene = new THREE.Scene(); const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); const renderer = new THREE.WebGLRenderer(); renderer.setSize(window.innerWidth, window.innerHeight); document.body.appendChild(renderer.domElement);
Давайте на мгновение объясним, что здесь происходит. Мы настроили сцену, камеру и рендерер.
В three.js есть несколько различных камер. Пока давайте используем PerspectiveCamera
.
Первый атрибут — это поле зрения (FOV). FOV — это часть сцены, которая видна на экране в любой момент времени. Значение указывается в градусах.
Второй атрибут — это соотношение сторон. Почти всегда нужно использовать ширину элемента, разделенную на высоту, иначе вы получите тот же результат, что и при просмотре старых фильмов на широкоэкранном телевизоре — изображение будет выглядеть сжатым.
Следующие два атрибута — это ближняя и дальняя плоскости отсечения. Это означает, что объекты, находящиеся дальше от камеры, чем значение far
, или ближе, чем near
, не будут отображаться. Вам не нужно беспокоиться об этом сейчас, но вы можете использовать другие значения в своих приложениях для повышения производительности.
Далее идет рендерер. Помимо создания экземпляра рендерера, нам также нужно установить размер, при котором мы хотим, чтобы наше приложение отображалось. Хорошей идеей будет использовать ширину и высоту области, которую мы хотим заполнить нашим приложением — в данном случае, ширину и высоту окна браузера. Для ресурсоемких приложений вы также можете задать меньшие значения для setSize
, например, window.innerWidth/2
и window.innerHeight/2
, что приведет к отображению приложения в четверть размера.
Если вы хотите сохранить размер вашего приложения, но отображать его с более низким разрешением, вы можете сделать это, вызвав setSize
с false
в качестве updateStyle
(третий аргумент). Например, setSize(window.innerWidth/2, window.innerHeight/2, false)
будет отображать ваше приложение в половинном разрешении, при условии, что ваш <canvas>
имеет 100% ширины и высоты.
И последнее, но не менее важное: мы добавляем элемент рендерера в наш HTML-документ. Это элемент <canvas>
, который рендерер использует для отображения сцены.
«Это все хорошо, но где же тот куб, который вы обещали?» Давайте добавим его сейчас.
const geometry = new THREE.BoxGeometry(1, 1, 1); const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 }); const cube = new THREE.Mesh(geometry, material); scene.add(cube); camera.position.z = 5;
Чтобы создать куб, нам нужен BoxGeometry
. Это объект, который содержит все точки (вершины) и грани куба. Мы рассмотрим это подробнее в будущем.
Помимо геометрии, нам нужен материал, чтобы его раскрасить. Three.js поставляется с несколькими материалами, но пока мы будем использовать MeshBasicMaterial
. Все материалы принимают объект свойств, которые будут применены к ним. Чтобы все было очень просто, мы указываем только атрибут цвета 0x00ff00
, который является зеленым. Это работает так же, как цвета в CSS или Photoshop (шестнадцатеричные цвета).
Третья вещь, которая нам нужна, — это Mesh
. Меш — это объект, который принимает геометрию и применяет к ней материал, который мы затем можем вставить в нашу сцену и свободно перемещать.
По умолчанию, когда мы вызываем scene.add()
, объект, который мы добавляем, будет помещен в координаты (0,0,0)
. Это приведет к тому, что и камера, и куб окажутся внутри друг друга. Чтобы избежать этого, мы просто немного отодвигаем камеру.
Рендеринг сцены
Если вы скопировали код выше в файл main.js
, который мы создали ранее, вы не сможете ничего увидеть. Это потому, что мы еще ничего не рендерим. Для этого нам нужно то, что называется циклом рендеринга или анимации.
function animate() { renderer.render(scene, camera); } renderer.setAnimationLoop(animate);
Это создаст цикл, который заставляет рендерер отрисовывать сцену каждый раз, когда экран обновляется (на типичном экране это означает 60 раз в секунду). Если вы новичок в написании игр для браузера, вы можете спросить: «Почему бы просто не создать setInterval
?» Дело в том, что мы могли бы, но requestAnimationFrame
, который внутренне используется в WebGLRenderer
, имеет ряд преимуществ. Возможно, самое важное из них — это то, что он приостанавливается, когда пользователь переходит на другую вкладку браузера, тем самым не тратя драгоценную вычислительную мощность и заряд батареи.
Анимация куба
Если вы вставите весь код выше в файл, который вы создали до того, как мы начали, вы должны увидеть зеленый куб. Давайте сделаем все немного интереснее, вращая его.
Добавьте следующий код прямо перед вызовом renderer.render
в вашей функции animate
:
cube.rotation.x += 0.01; cube.rotation.y += 0.01;
Это будет выполняться каждый кадр (обычно 60 раз в секунду) и даст кубу приятную анимацию вращения. В основном, все, что вы хотите перемещать или изменять во время работы приложения, должно проходить через цикл анимации. Вы, конечно, можете вызывать другие функции оттуда, чтобы не получить функцию animate
, которая занимает сотни строк.
Результат
Поздравляем! Вы завершили свое первое приложение на three.js. Оно простое, но с чего-то нужно начинать.
Полный код доступен ниже и в виде редактируемого живого примера. Поиграйте с ним, чтобы лучше понять, как он работает.
- index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>My first three.js app</title> <style> body { margin: 0; } </style> </head> <body> <script type="module" src="/main.js"></script> </body> </html>
- main.js
import * as THREE from 'three'; const scene = new THREE.Scene(); const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); const renderer = new THREE.WebGLRenderer(); renderer.setSize(window.innerWidth, window.innerHeight); renderer.setAnimationLoop(animate); document.body.appendChild(renderer.domElement); const geometry = new THREE.BoxGeometry(1, 1, 1); const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 }); const cube = new THREE.Mesh(geometry, material); scene.add(cube); camera.position.z = 5; function animate() { cube.rotation.x += 0.01; cube.rotation.y += 0.01; renderer.render(scene, camera); }