Элементы управления
В предыдущем уроке мы разобрались с тем, какие виды камер существуют в three.js
. Если ты это пропустил, то советую вернуться!
Анимация сцены это здорово, но иногда хочется иметь возможность взаимодействовать с объектами на сцене при помощи элементов управления, поэтому в этой статье мы разберем как же можно добавить такой функционал в наше приложение three.js
.
Код на начало урока живет тут.
И так, сейчас наша сцена выглядит вот так:
Пользовательские элементы управления
Сейчас мы хотим управлять камерой с помощью мыши. Прежде всего, мы хотим знать координаты мыши. Мы можем сделать это если накинем addEventListener
на событие mousemove
.
// Курсор window.addEventListener('mousemove', (event) => { console.log(event.clientX, event.clientY); });
Координаты будут находиться в аргументе callback-функции как event.clientX
и event.clientY.
Мы могли бы использовать эти значения, но я рекомендую нормализовать их.
Под 'нормализовать' я подразумеваю установить амплитуду равную 1 и настроить значение, которое может быть как отрицательным, так и положительным.
Если мы сосредоточимся только на значении x
, это будет означать, что:
- если ваш курсор находится в крайнем левом углу
canvas
, вы должны получить-0,5
- если ваш курсор находится в центре
canvas
, вы должны получить0
- если ваш курсор находится в крайнем правом углу
canvas
, вы должны получить0,5
Хотя это не является обязательным, полезно иметь такие чистые значения.
Как и в случае с переменной size
, мы создадим переменную курсора со свойствами x
и y
по умолчанию, а затем обновим эти свойства в колбеке события mousemove
:
// Курсор const cursor = { x: 0, y: 0, }; window.addEventListener('mousemove', (event) => { cursor.x = event.clientX / sizes.width - 0.5; cursor.y = event.clientY / sizes.height - 0.5; });
Разделение event.clientX
на size.width
даст нам значение от 0 до 1 (если мы держим курсор над canvas
), а вычитание 0,5 даст вам значение от -0,5 до 0,5.
Теперь у вас есть позиция мыши, сохраненная в переменной объекта курсора, и вы можете обновить позицию камеры в функции тика анимации:
const tick = () => { // Трансформация камеры cursor.x = event.clientX / sizes.width - 0.5; cursor.y = event.clientY / sizes.height - 0.5; // Отрисовываем renderer.render(scene, camera); // Вызываем функцию анимации в следующем фрейме window.requestAnimationFrame(tick); }; tick();
Как видите, это работает, но движения осей кажутся неправильными.
Вы можете просто инвертировать cursor.x
при его обновлении, добавив -
перед всей формулой (не забудьте круглые скобки):
window.addEventListener('mousemove', (event) => { cursor.x = -(event.clientX / sizes.width - 0.5); cursor.y = event.clientY / sizes.height - 0.5; });
А еще, вы можете увеличить амплитуду, умножив cursor.x
и cursor.y
и попросить камеру посмотреть на наш куб, используя метод lookAt(...)
:
Мы можем пойти еще дальше, выполнив полный поворот камеры вокруг кубика с помощью функций Math.sin(...)
и Math.cos(...)
.
sin
и cos
, когда их комбинируют и используют под одним и тем же углом, позволяют нам двигать вещи по кругу. Чтобы сделать полный оборот, этот угол должен иметь амплитуду, умноженную на 2 π. Просто чтобы вы знали, полный оборот называется «тау», но у нас нет доступа к этому значению в JavaScript, и вместо этого мы должны использовать π.
const tick = () => { // ... camera.position.x = Math.sin(cursor.x * Math.PI * 2) * 2; camera.position.z = Math.cos(cursor.x * Math.PI * 2) * 2; camera.position.y = cursor.y * 3; camera.lookAt(mesh.position); // ... } tick();
Хотя это хорошее начало для управления камерой, three.js
интегрировал несколько классов, называемых элементами управления, которые помогут вам сделать то же самое и многое другое, но немного проще.
Встроенные элементы управления
Если вы наберете «controls» в документации Three.js, вы увидите, что существует множество готовых элементов управления. Мы будем использовать только один из них до конца курса, но может быть интересно узнать их роль остальных.
DeviceOrientationControls
DeviceOrientationControls автоматически получит ориентацию устройства, если ваше устройство, ОС и браузер позволяют это, и соответствующим образом повернет камеру. Вы можете использовать его для создания виртуальной реальности, если у вас есть подходящее оборудование.
FlyControls
FlyControls позволяет перемещать камеру, как будто вы находитесь на космическом корабле. Вы можете вращаться по всем трем осям, двигаться вперед и назад.
FirstPersonControls
FirstPersonControls похож на FlyControls, но с фиксированной осью вверх. Вы можете видеть это от лица летящей птицы, которая не может крутиться вокруг своей оси.
PointerLockControls
PointerLockControls использует JavaScript API. Этот API скрывает курсор, удерживает его в центре и продолжает отправлять движения в колбеках события mousemove. С помощью этого API вы можете создавать игры FPS прямо в браузере. Хотя этот класс звучит очень многообещающе, если вы хотите создать такое взаимодействие, то вам придется самостоятельно управлять положением камеры и игровой физикой.
OrbitControls
OrbitControls очень похож на пользовательские элементы управления. Вы можете вращать точку левой кнопкой мыши, перемещать ее вбок правой кнопкой мыши и увеличивать или уменьшать масштаб с помощью колеса.
TrackballControls
TrackballControls похож на OrbitControls, но он не имеет ограничений по вертикальному углу. Вы можете продолжать вращаться и делать вращения с камерой, даже если сцена переворачивается.
TransformControls
TransformControls не имеет ничего общего с камерой. Вы можете использовать его, чтобы добавить управление к объекту для его перемещения.
DragControls
Как и TransformControls, DragControls не имеет ничего общего с камерой. Вы можете использовать его для перемещения объектов на плоскости, обращенной к камере, путем перетаскивания их.
Мы будем использовать только OrbitControls, но не стесняйтесь тестировать и другие классы.
OrbitControls
Давайте уберем часть, где мы обновляем камеру в функции tick
.
Во-первых, нам нужно создать элемент класса OrbitControls. Хотя вы можете подумать, что здесь можно использовать THREE.OrbitControls
, вы, к сожалению, ошибаетесь.
Класс OrbitControls является частью тех классов, которые недоступны по умолчанию в переменной THREE
. Это решение помогает уменьшить вес библиотеки. И здесь на помощь приходит наша сборка Webpack
.
Класс OrbitControls может быть недоступен в переменной THREE, но он по-прежнему находится в папке зависимостей.
Чтобы импортировать его, вы должны указать путь внутри папки /node_modules/
, то есть /three/examples/jsm/controls/OrbitControls.js
:
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
Теперь вы можете создать объекты с помощью класса OrbitControls
(без THREE
.) и обязательно сделать это после создания камеры.
Чтобы это работало, вы должны указать камеру и canvas
, который будет обрабатывать события мыши в качестве параметров:
// Controls const controls = new OrbitControls(camera, canvas);
Теперь вы можете перетаскивать куб, вращать его и изменять размер при помощи мыши.
Это намного проще, чем наш пользовательский код, и в нем больше элементов управления. Но пойдем немного дальше.
Damping
Если вы читали документацию OrbitControls, там есть упоминания о демпфировании. Демпфирование сглаживает анимацию, добавляя какие-то формулы ускорения и трения.
Чтобы включить демпфирование, установите для свойства enableDamping
элементов управления значение true
.
Для правильной работы элементы управления также необходимо обновлять в каждом кадре, вызывая control.update()
. Вы можете сделать это в функции тика анимации:
Можно заметить, что управление стало намного более плавным.
Вы можете использовать многие другие методы и свойства для настройки элементов управления, таких как скорость вращения, скорость масштабирования, ограничение масштабирования, ограничение угла, сила демпфирования и привязки клавиш.
Когда использовать встроенные элементы управления
Хотя эти элементы управления удобны, они имеют ограничения. Если вы слишком полагаетесь на них, вам может понадобиться изменить работу класса неожиданным образом.
Во-первых, обязательно перечислите все функции, которые вам нужны из этих элементов управления, а затем проверьте, может ли класс, который вы собираетесь использовать, обрабатывать все эти функции.
Если нет, вам придется сделать это самостоятельно.
На этом сегодня все, мы разобрали подробнее какие бывают камеры в three.js
, надеюсь вам это было полезно!
🤖 Чтобы не пропустить новые уроки подпишись на телеграм канал!
🚀 Код для данного урока вы можете найти тут.
Полноэкранный режим и изменение размера ->