Трансформация объектов (часть 2)
В предыдущем уроке мы начали разбираться с тем, как можно трансформировать объекты в three.js, научились перемещать их и изменять размер. Если ты это пропустил, то советую вернуться!
В этом уроке мы разберем всевозможные варианты вращения объектов, узнаем что такое кватернионы и исследуем то, как можно объединять объекты на сцене в группы, для проведение общей трансформации!
Вращение объектов
Вращение немного более сложный тип трансформации, относительно перемещения и масштабирования. Существует два способа реализовать вращение.
Можно использовать изменение вполне очевидного свойства rotation, но можно изменять и менее очевидное свойство quaternion. Three.js поддерживает оба варианта и изменение одного из этих свойств будет изменять другое.
Свойство rotation
Свойство rotation так же как и position или scale хранит внутри себя свойства x, y, z, но представлены эти свойства не от класса Vector3, а от класса Euler . Когда вы меняете параметры x, y, z объекта типа Euler , то вы можете представить, что проводите палку через центр вашего объекта вдоль оси, а потом начинаете вращать объект вокруг этой палки.
Значение переменных, отвечающих за вращение выражены в радианах. То есть, если вы хотите, чтобы объект совершил половину оборота, то изменить значение переменной нужно примерно на 3.1415969...
Я надеюсь вы помните что такое число π. В нативном JavaScript можно использовать приближенное значение этого числа Math.PI.
Сейчас давайте возьмем тот код, который у нас получился в конце прошлого урока его можно посмотреть тут , закомментируем часть, которая добавляет масштабирование и добавить вращение по двум осям:
mesh.rotation.x = Math.PI * 0.25; mesh.rotation.y = Math.PI * 0.25;
В итоге должно получиться что-то вот такое:
Достаточно просто, верно? В целом да, но вот если мы начнем с вами комбинировать различные вращения, то можем получить очень неожиданные результаты. Почему? А все потому, что если вы, например, вращаете вокруг оси x, то и направление остальных осей тоже меняется.
Вращение применяется к осям в следующем порядке: x, y, z. Мы можем изменить этот порядок, используя функцию object.rotation.reorder('yxz').
Принцип работы класса Euler достаточно просто понять, но проблема с очередностью применения изменений может создать достаточно много неожиданного результата. Именно поэтому существует другое решение - класс Quaternion.
Свойство quaternion
Свойство quaternion - также отвечает за вращение, но с более тонким математическим подходом, который в итоге решает проблему очередности.
Мы не будем сильно углубляться в то, как работают кватернионы, в целом нужно знать две вещи:
- Под капотом кватернионов работает математика с чудесами матричных преобразований
- Изменяя свойство
rotation- вы так же изменяете свойствоquaternion
Ты посмотри на это!
Класс Object3D имеет замечательный метод под названием lookAt(...) , который может заставить объект посмотреть на что-то. Тут не нужна сложная математика, потому что объект просто повернем свою ось -z в направлении указанной цели.
Это можно использовать для того, чтобы повернуть камеру к объекту, направить пушку лицом к врагу или переместить клаз в персонажа на какой-то объект.
Параметр, который мы передаем в этот метод должен быть Vector3.
Давайте попробуем его использовать:
camera.lookAt(new THREE.Vector3(0, - 1, 0));
Кажется, что куб уехал наверх, но на самом деле это камера смотрит немного ниже куба.
В качестве параметра можно также передавать свойства объекта, например, position. Сейчас это не даст нам никакого результата, потому что куб и так находится в центре сцены:
camera.lookAt(mesh.position);
Комбинирование трансформаций
Вы можете объединять изменение position, rotation, quaternion, и scale в любом порядке. Результат будет одинаковый - это что-то вроде стейта объекта.
Давайте попробуем объединить все те трансформации, которые мы насобирали в этих двух уроках:
// Передвижение куба mesh.position.x = -1; mesh.position.y = -0.8; mesh.position.z = 0.4; // Масштабирование куба mesh.scale.x = 0.5; mesh.scale.y = 2; mesh.scale.z = 0.7; // Вращение куба mesh.rotation.x = Math.PI * 0.25; mesh.rotation.y = Math.PI * 0.25;
Группировка объектов
В какой-то момент вы, возможно, захотите сгруппировать объекты. Допустим, вы строите дом со стенами, дверями, окнами, крышей, кустами и т.д.
Когда вы думаете, что закончили, вы осознаете, что дом слишком мал, и вам приходится изменять масштаб каждого объекта и обновлять их положение.
Хорошей альтернативой было бы сгруппировать все эти объекты в контейнер и масштабировать этот контейнер.
Это можно сделать при помощи класса Group.
Создайте объект класса Group и добавьте его на сцену. Дальше, когда вы будете создавать объекты, то вы можете добавлять их не на сцену, а в эту группу используя метод add(...).
Давайте закомментируем вызов метода lookAt(...) и код всех трансформаций, вместо нашего прошлого создадим три куба, объединим их в группу и применим трансформации к ней.
/** * Группировка обхектов */ const group = new THREE.Group(); group.scale.y = 0.7; group.rotation.x = 0.5; scene.add(group); const cube1 = new THREE.Mesh(geometry, material); cube1.position.x = - 1.2; group.add(cube1); const cube2 = new THREE.Mesh(geometry, material); cube2.position.x = 0; group.add(cube2); const cube3 = new THREE.Mesh(geometry, material); cube3.position.x = 1.2; group.add(cube3);
Ну что же, на этом сегодня все, тут вы можете найти код, который у нас получился, а дальше мы перейдем с вами к изучению анимации! Не забывайте подписываться на телеграм канал, чтобы не пропустить новые статьи и уроки, пока ✌️