Three.js: Создание сцены

Цель этого раздела — дать краткое введение в 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);
}

Оставьте комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

18 − 16 =

Прокрутить вверх