Библиотека JavaScript three.js для рисования 3D

Опубликовано 29 марта 2022 в 13:32 (Обновлено 9 января 2024 в 14:12)

Время чтения: 13 мин

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

JavaScript three.js
JavaScript three.js

Установка

Простая в использовании, легкая, кросс-браузерная 3D-библиотека JavaScript общего назначения для рисования и отображения 3D-объектов. Текущие сборки включают только WebGL рендерер, но WebGPU (экспериментальный), SVG и CSS3D рендереры также доступны в примерах.

Вы можете установить three.js с помощью npm и современных инструментов сборки или быстро начать работу, используя только статический хостинг или CDN. Для большинства пользователей лучшим выбором будет установка из npm.

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

Все способы установки three.js зависят от модулей ES, которые позволяют включать в конечный проект только те части библиотеки, которые необходимы.

Установка с помощью npm

Чтобы установить модуль npm three (ссылка), откройте окно терминала в папке вашего проекта и выполните команду:

npm install three

Пакет будет загружен и установлен. Затем вы будете готовы импортировать его в свой код:

// Option 1: Import the entire three.js core library.
import * as THREE from 'three';
const scene = new THREE.Scene();

// Option 2: Import just the parts you need.
import { Scene } from 'three';
const scene = new Scene();

При установке с помощью npm вы почти всегда будете использовать какой-либо инструмент для объединения всех пакетов, необходимых вашему проекту, в один файл JavaScript. Хотя любой современный JavaScript bundler может быть использован с three.js, наиболее популярным выбором является webpack.

Не все функции доступны непосредственно через модули three (это называется "голым импортом"). Другие популярные части библиотеки - такие как элементы управления, загрузчики и эффекты постобработки - должны быть импортированы из подпапки examples/jsm. Чтобы узнать больше, посмотрите раздел "Примеры" ниже.

Установка с использованием CDN или статического хостинга

Библиотеку three.js можно использовать без какой-либо системы сборки, загружая файлы на собственный веб-сервер или используя существующую CDN. Поскольку библиотека полагается на модули ES, любой скрипт, который ссылается на нее, должен использовать type="module", как показано ниже. Также необходимо определить Import Map (карту импорта), который разрешает голый спецификатор модуля three.

<script async src="https://unpkg.com/es-module-shims@1.3.6/dist/es-module-shims.js"></script>
<script type="importmap">
  {
    "imports": {
      "three": "https://unpkg.com/three@<version>/build/three.module.js"
    }
  }
</script>

<script type="module">
  import * as THREE from 'three';
  const scene = new THREE.Scene();
</script>

Поскольку карты импорта пока поддерживаются не всеми браузерами, необходимо добавить полифилл es-module-shims.js.

Примеры

Ядро three.js сосредоточено на самых важных компонентах 3D-движка. Многие другие полезные компоненты - такие как элементы управления, загрузчики и эффекты постобработки - находятся в каталоге examples/jsm.

Они называются "примерами", потому что, хотя вы можете использовать их готовыми, они также могут быть изменены и модифицированы. Эти компоненты всегда синхронизируются с основной библиотекой, в то время как аналогичные пакеты сторонних разработчиков на npm поддерживаются разными людьми и могут быть неактуальными.

Примеры не нужно устанавливать отдельно, но их нужно импортировать отдельно. Если three.js был установлен с помощью npm, вы можете загрузить компонент OrbitControls с помощью:

import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
const controls = new OrbitControls( camera, renderer.domElement );

Если three.js был установлен из CDN, используйте ту же CDN для установки других компонентов:

<script type="module">
  import { OrbitControls } from 'https://unpkg.com/three@<version>/examples/jsm/controls/OrbitControls.js';
  const controls = new OrbitControls( camera, renderer.domElement );
</script>

Важно, чтобы все файлы использовали одну и ту же версию. Не импортируйте разные примеры из разных версий и не используйте примеры из версии, отличной от версии самой библиотеки three.js.

Совместимость

Импорт CommonJS

Хотя большинство современных JavaScript-компонентов теперь поддерживают модули ES по умолчанию, некоторые старые инструменты сборки могут этого не делать. В таких случаях вы можете настроить бандлер на понимание ES-модулей: Например, для Browserify нужен только плагин babelify.

Node.js

Поскольку three.js создан для веб, он зависит от API браузера и DOM, которые не всегда существуют в Node.js. Некоторые из этих проблем могут быть решены с помощью фиксов, таких как headless-gl, или заменой таких компонентов, как TextureLoader, на собственные альтернативы. Другие DOM API могут быть глубоко переплетены с кодом, который их использует, и их будет сложнее обойти. Мы приветствуем простые и удобные для обслуживания запросы на улучшение поддержки Node.js, но рекомендуем сначала создать заявку для обсуждения ваших улучшений.

Обязательно добавьте { "type": "module" } в ваш package.json, чтобы включить модули ES6 в ваш проект node.

Проверка совместимости с WebGL

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

Добавьте

https://github.com/mrdoob/three.js/blob/master/examples/jsm/capabilities/WebGL.js

в свой JavaScript и выполните следующее, прежде чем пытаться что-либо отобразить:

if ( WebGL.isWebGLAvailable() ) {

	// Initiate function or other initializations here
	animate();

} else {

	const warning = WebGL.getWebGLErrorMessage();
	document.getElementById( 'container' ).appendChild( warning );

}

Создание сцены

Прежде чем использовать файл three.js, его нужно где-то отобразить. Сохраните следующий HTML в файл на своем компьютере вместе с копией файла three.js в каталоге js/ и откройте его в браузере.

Скачать three.js

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>My first three.js app</title>
		<style>
			body { margin: 0; }
		</style>
	</head>
	<body>
		<script src="js/three.js"></script>
		<script>
			// Our Javascript will go here.
		</script>
	</body>
</html>

Вот и все. Весь приведенный ниже код помещается в пустой тег <script>.

Чтобы иметь возможность отображать что-либо с помощью three.js, нам нужны три вещи: сцена (scene), камера (camera) и рендерер (renderer), чтобы мы могли отображать сцену с помощью камеры.

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.

Первый атрибут - это поле зрения field of view (FOV). FOV - это площадь сцены, которая видна на дисплее в любой момент времени. Значение выражается в градусах.

Второй - соотношение сторон aspect ratio. Почти всегда нужно использовать ширину элемента, деленную на высоту, иначе вы получите тот же результат, что и при воспроизведении старых фильмов на широкоэкранном телевизоре - изображение будет выглядеть сжатым.

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

Далее следует рендерер. Именно здесь происходит волшебство. В дополнение к WebGLRenderer, который мы используем здесь, three.js поставляется с несколькими другими, часто используемыми как запасные варианты для пользователей со старыми браузерами или для тех, у кого по каким-то причинам нет поддержки WebGL.

Помимо создания экземпляра рендерера, нам также необходимо задать размер, в котором мы хотим, чтобы он отображал наше приложение. Хорошо использовать ширину и высоту области, которую мы хотим заполнить нашим приложением - в данном случае это ширина и высота окна браузера. Для приложений, требующих высокой производительности, вы также можете задать setSize меньшие значения, например window.innerWidth/2 и window.innerHeight/2, которые заставят приложение рендериться в четверть размера.

Если вы хотите сохранить размер вашего приложения, но отобразить его с меньшим разрешением, вы можете сделать это, вызвав setSize с false в качестве updateStyle (третий аргумент). Например:

setSize(window.innerWidth/2, window.innerHeight/2, false)

отрисует ваше приложение с половинным разрешением, учитывая, что ваш <canvas> имеет 100% ширину и высоту.

И последнее, но не менее важное, мы добавляем элемент renderer в наш HTML-документ. Это элемент

"Это все хорошо, но где же обещанный кубик?"

Давайте добавим его сейчас.

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. Это объект, который содержит все точки (вершины vertices) и заливку (грани faces) куба. Мы рассмотрим это подробнее в будущем.

В дополнение к геометрии нам нужен материал, чтобы окрасить ее. Three.js поставляется с несколькими материалами, но мы пока будем придерживаться MeshBasicMaterial. Все материалы принимают объект свойств, которые будут к ним применяться. Чтобы все было очень просто, мы предоставим только атрибут цвета 0x00ff00, то есть зеленый. Это работает так же, как цвета работают в CSS или Photoshop (шестнадцатеричные цвета hex colors).

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

По умолчанию, когда мы вызываем scene.add(), объект, который мы добавляем, будет добавлен в координаты (0,0,0). Это приведет к тому, что камера и куб окажутся внутри друг друга. Чтобы избежать этого, мы просто немного выдвинем камеру.

Рендеринг (визуализация) сцены

Если вы скопируете код сверху в HTML-файл, который мы создали ранее, вы ничего не увидите. Это потому, что мы еще ничего не отобразили. Для этого нам нужен так называемый цикл рендеринга или анимации (render or animate loop).

function animate() {
	requestAnimationFrame( animate );
	renderer.render( scene, camera );
}
animate();

Это создаст цикл, который заставляет рендерер рисовать сцену при каждом обновлении экрана (на обычном экране это означает 60 раз в секунду). Если вы новичок в написании игр в браузере, вы можете сказать: "Почему бы нам просто не создать setInterval?".

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

Анимация куба

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

Добавьте следующий код прямо над вызовом renderer.render в вашей функции animate:

Этот цикл будет выполняться каждый кадр (обычно 60 раз в секунду) и придаст кубу красивую анимацию вращения. В принципе, все, что вы хотите передвинуть или изменить во время работы приложения, должно пройти через цикл animate. Конечно, вы можете вызывать оттуда другие функции, чтобы в итоге не получить функцию animate, состоящую из сотен строк.

Результат

Поздравляем! Вы завершили работу над своим первым приложением three.js. Оно простое, но нужно с чего-то начинать.

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

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>My first three.js app</title>
		<style>
			body { margin: 0; }
		</style>
	</head>
	<body>
		<script src="js/three.js"></script>
		<script>
			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 );

			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() {
				requestAnimationFrame( animate );

				cube.rotation.x += 0.01;
				cube.rotation.y += 0.01;

				renderer.render( scene, camera );
			};

			animate();
		</script>
	</body>
</html>

Как запускать вещи локально

Если вы используете только процедурные геометрии и не загружаете никаких текстур, веб-страницы должны работать прямо из файловой системы, просто дважды щелкните на HTML-файле в файловом менеджере, и он появится в браузере (вы увидите file:///yourFile.html в адресной строке).

Контент, загружаемый из внешних файлов

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

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

http://localhost/yourFile.html

Хотя можно также изменить настройки безопасности браузера вместо запуска локального сервера, мы не рекомендуем использовать такой подход. Такое решение может открыть ваше устройство для уязвимостей, если тот же браузер используется для обычного веб-серфинга. Использование локального сервера является стандартной практикой в веб-разработке, и ниже мы объясним, как установить и использовать локальный сервер.

Запуск локального сервера

Многие языки программирования имеют встроенные простые HTTP-серверы. Они не так полнофункциональны, как рабочие серверы, такие как Apache или NGINX, однако их должно быть достаточно для тестирования вашего приложения three.js.

Плагины для популярных редакторов кода

Некоторые редакторы кода имеют плагины, которые по запросу создают простой сервер.

Servez

Servez - это простой сервер с графическим интерфейсом.

Node.js five-server

Сервер разработки с возможностью перезагрузки в реальном времени. Для установки:

# Remove live-server (if you have it)
npm -g rm live-server

# Install five-server
npm -g i five-server

# Update five-server (from time to time)
npm -g i five-server@latest

Для запуска (из локальной директории):

five-server . -p 8000

Node.js http-server

В Node.js есть простой пакет HTTP-сервера. Чтобы установить:

npm install http-server -g

Для запуска (из локальной директории):

http-server . -p 8000

Сервер Python

Если у вас установлен Python, достаточно запустить его из командной строки (из рабочего каталога):

//Python 2.x
python -m SimpleHTTPServer

//Python 3.x
python -m http.server

Это позволит обслуживать файлы из текущей директории на localhost под портом 8000, т.е. в адресной строке вводим:

http://localhost:8000/

Сервер Ruby

Если у вас установлен Ruby, вы можете получить тот же результат, запустив эту программу:

ruby -r webrick -e "s = WEBrick::HTTPServer.new(:Port => 8000, :DocumentRoot => Dir.pwd); trap('INT') { s.shutdown }; s.start"

PHP-сервер

PHP также имеет встроенный веб-сервер, начиная с версии php 5.4.0:

php -S localhost:8000

Lighttpd

Lighttpd - это очень легкий веб-сервер общего назначения. Здесь мы рассмотрим его установку на OSX с помощью HomeBrew. В отличие от других серверов, обсуждаемых выше, lighttpd - это полноценный сервер, готовый к работе.

1. Установка через homebrew

brew install lighttpd

2. Создайте конфигурационный файл lighttpd.conf в каталоге, где вы хотите запустить свой веб-сервер. Образец можно найти здесь.

3. В файле conf измените server.document-root на каталог, из которого вы хотите обслуживать файлы.

4. Начните с:

lighttpd -f lighttpd.conf

5. Перейдите по адресу http://localhost:3000/, и он будет обслуживать статические файлы из выбранной вами директории.

IIS

Если вы используете Microsoft IIS в качестве веб-сервера, пожалуйста, добавьте настройки типа MIME относительно расширения .fbx перед загрузкой.

File name extension: fbx        MIME Type: text/plain

По умолчанию IIS блокирует загрузку файлов .fbx, .obj. Вам необходимо настроить IIS так, чтобы эти файлы можно было загружать.

Другие простые альтернативы можно обсудить на Stack Overflow здесь.

Добавить комментарий

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

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.