Quaternion — это математическая структура, используемая для описания вращений в трёхмерном пространстве без проблем, связанных с Gimbal Lock (блокировкой осей). В Three.js кватернионы реализованы через класс THREE.Quaternion. Они позволяют плавно интерполировать вращения и комбинировать их, сохраняя стабильность и корректность во всех ориентациях.
Кватернион представляет собой четыре компонента: x, y, z, w, где w — скалярная часть, а x, y, z — векторная часть. Основная формула:
[ q = w + xi + yj + zk]
В Three.js доступна и удобная работа с кватернионами через методы
setFromAxisAngle, setFromEuler,
multiply, slerp и другие.
const quaternion = new THREE.Quaternion(); // по умолчанию идентичный (без вращения)
Можно задать вращение вокруг произвольной оси:
const axis = new THREE.Vector3(0, 1, 0); // ось Y
const angle = Math.PI / 4; // 45 градусов
quaternion.setFromAxisAngle(axis, angle);
Для применения к объекту используется свойство
object.quaternion:
mesh.quaternion.copy(quaternion);
При этом не требуется использовать матрицы напрямую, что упрощает работу с вращениями и предотвращает накопление ошибок.
Хотя кватернионы обеспечивают стабильное вращение, иногда удобнее задавать вращение через углы Эйлера. В Three.js это делается через класс THREE.Euler:
const euler = new THREE.Euler(Math.PI / 2, 0, 0, 'XYZ');
mesh.quaternion.setFromEuler(euler);
Важно помнить, что последовательность осей (‘XYZ’, ‘YXZ’ и т.д.) влияет на результат. Использование кватернионов полностью устраняет эффекты Gimbal Lock, которые возникают при последовательной работе с углами Эйлера.
Комбинирование вращений через кватернионы производится методом
multiply:
const q1 = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(1,0,0), Math.PI/4);
const q2 = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0,1,0), Math.PI/4);
const qCombined = q1.clone().multiply(q2); // сначала q1, затем q2
mesh.quaternion.copy(qCombined);
Метод multiply не коммутативен: порядок умножения влияет
на итоговое вращение.
Для плавного перехода между двумя ориентациями используется slerp (spherical linear interpolation):
const startQuat = new THREE.Quaternion().setFromEuler(new THREE.Euler(0, 0, 0));
const endQuat = new THREE.Quaternion().setFromEuler(new THREE.Euler(Math.PI/2, Math.PI/2, 0));
THREE.Quaternion.slerp(startQuat, endQuat, mesh.quaternion, 0.5); // 50% между start и end
Slerp обеспечивает равномерное вращение по кратчайшему пути на 4D-сфере кватернионов, предотвращая резкие рывки и перекручивание объектов.
Кватернионы позволяют вращать объект относительно его локальной системы координат без накопления ошибок. Пример вращения вокруг локальной оси Y:
const axis = new THREE.Vector3(0, 1, 0); // локальная ось
const angle = 0.01; // небольшое приращение
const deltaQuat = new THREE.Quaternion().setFromAxisAngle(axis, angle);
mesh.quaternion.multiply(deltaQuat); // применение инкрементного вращения
Использование локальных осей через кватернионы делает анимации и
управление камерой более предсказуемыми по сравнению с поворотами через
rotation.x/y/z.
Для управления камерой без блокировки осей удобно использовать кватернионы:
const cameraQuat = new THREE.Quaternion();
cameraQuat.setFromEuler(new THREE.Euler(pitch, yaw, 0, 'YXZ'));
camera.quaternion.copy(cameraQuat);
Комбинация pitch и yaw через кватернионы
предотвращает ситуацию, когда камера теряет одну степень свободы (Gimbal
Lock) при вертикальном вращении.
setFromAxisAngle(axis, angle) — установка вращения
вокруг произвольной оси.setFromEuler(euler) — преобразование из углов
Эйлера.multiply(q) — комбинирование вращений.slerp(qb, t) — интерполяция кватернионов.normalize() — нормализация кватерниона для
предотвращения искажения вращений.inverse() — получение обратного вращения.dot(q) — скалярное произведение, полезно для
определения близости ориентаций.rotation и
quaternion может приводить к непредсказуемым
результатам.Кватернионы являются фундаментальной частью современного 3D-программирования. В Three.js их использование позволяет создавать стабильные, плавные и предсказуемые вращения объектов и камеры, избегая ограничений классической модели Эйлера и Gimbal Lock.