В трёхмерной графике вращения объектов представляют одну из наиболее
сложных задач из-за ограничений эйлеровых углов: возникновения эффекта
блокировки кардана (gimbal lock), нестабильности интерполяции и
неоднозначности представления ориентации. В CesiumJS для устойчивого
описания вращений используется математическая конструкция кватернионов,
реализованная в классе Cesium.Quaternion.
Кватернион в контексте CesiumJS представляет четырёхкомпонентный вектор:
Он описывает вращение в трёхмерном пространстве без потери устойчивости при композиции и интерполяции.
Любое вращение может быть представлено как поворот вокруг единичной оси на заданный угол. В кватернионной форме это выражается через:
CesiumJS использует нормализованную форму кватерниона, где длина равна 1, что обеспечивает корректную композицию вращений.
Базовое создание осуществляется через
Cesium.Quaternion.fromAxisAngle:
const axis = Cesium.Cartesian3.normalize(
new Cesium.Cartesian3(0, 0, 1),
new Cesium.Cartesian3()
);
const angle = Cesium.Math.toRadians(45);
const q = Cesium.Quaternion.fromAxisAngle(axis, angle, new Cesium.Quaternion());
Внутренне происходит преобразование ось–угол в четырёхмерную форму с использованием тригонометрических функций половинного угла.
В CesiumJS кватернионы часто используются для задания ориентации
сущностей (Entity.orientation) или моделей
(ModelMatrix).
Типичный сценарий включает установку ориентации объекта в сцене:
const position = Cesium.Cartesian3.fromDegrees(30, 50, 1000);
const heading = Cesium.Math.toRadians(90);
const pitch = Cesium.Math.toRadians(0);
const roll = Cesium.Math.toRadians(0);
const hpr = new Cesium.HeadingPitchRoll(heading, pitch, roll);
const orientation = Cesium.Transforms.headingPitchRollQuaternion(
position,
hpr,
new Cesium.Quaternion()
);
viewer.entities.add({
position: position,
orientation: orientation,
model: {
uri: "model.glb"
}
});
Здесь HeadingPitchRoll преобразуется во внутренний
кватернион, учитывающий локальную систему координат ENU
(East-North-Up).
CesiumJS предоставляет набор операций, обеспечивающих композицию и модификацию вращений.
Композиция вращений выполняется через умножение:
const result = Cesium.Quaternion.multiply(q1, q2, new Cesium.Quaternion());
Порядок множителей критически важен, так как операция некоммутативна:
q1 * q2 ≠ q2 * q1Результат соответствует последовательному применению вращений.
После операций композиции может возникать численная погрешность. Для восстановления корректной формы используется нормализация:
Cesium.Quaternion.normalize(q, q);
Нормализованный кватернион гарантирует сохранение единичной длины и стабильность дальнейших вычислений.
Обратное вращение определяется через сопряжение (conjugate) для единичных кватернионов:
const inverse = Cesium.Quaternion.conjugate(q, new Cesium.Quaternion());
Это соответствует вращению в противоположную сторону без изменения оси.
Линейная интерполяция углов приводит к искажениям скорости вращения. В CesiumJS применяется сферическая интерполяция (Slerp — Spherical Linear Interpolation), обеспечивающая равномерное движение по гиперсфере единичных кватернионов.
const result = Cesium.Quaternion.slerp(
qStart,
qEnd,
0.5,
new Cesium.Quaternion()
);
Параметр интерполяции:
Slerp обеспечивает постоянную угловую скорость и отсутствие артефактов вращения.
Кватернионы тесно связаны с матрицами вращения
Cesium.Matrix3 и Cesium.Matrix4.
Преобразование кватерниона в матрицу:
const matrix3 = Cesium.Matrix3.fromQuaternion(q, new Cesium.Matrix3());
И обратное преобразование:
const qFromMatrix = Cesium.Quaternion.fromRotationMatrix(
matrix3,
new Cesium.Quaternion()
);
Матрицы удобны для линейных преобразований, но кватернионы обеспечивают более стабильную интерполяцию и композицию вращений.
В CesiumJS вращения часто определяются относительно локальной системы координат:
Функция Cesium.Transforms.eastNorthUpToFixedFrame строит
матрицу преобразования из глобальной системы координат в локальную ENU.
Кватернионы могут быть получены из этой матрицы для задания ориентации
объектов в локальном пространстве.
const enu = Cesium.Transforms.eastNorthUpToFixedFrame(position);
const orientation = Cesium.Quaternion.fromRotationMatrix(
Cesium.Matrix3.fromMatrix4(enu, new Cesium.Matrix3()),
new Cesium.Quaternion()
);
Углы Heading-Pitch-Roll представляют последовательные вращения вокруг локальных осей:
CesiumJS преобразует их в кватернион через промежуточные вычисления с учётом порядка вращений, что устраняет неоднозначность, характерную для Эйлеровых углов.
При анимации объектов часто используется последовательное накопление вращений:
const delta = Cesium.Quaternion.fromAxisAngle(axis, angleStep, new Cesium.Quaternion());
Cesium.Quaternion.multiply(current, delta, current);
Cesium.Quaternion.normalize(current, current);
Такая схема применяется для симуляции непрерывного вращения без накопления ошибок, характерных для матричных преобразований.
Кватернионы часто применяются в свойствах
SampledProperty, где ориентация изменяется во времени:
const property = new Cesium.SampledProperty(Cesium.Quaternion);
property.addSample(time1, q1);
property.addSample(time2, q2);
property.addSample(time3, q3);
CesiumJS автоматически интерполирует между значениями, используя сферическую интерполяцию, обеспечивая плавные переходы ориентации в анимации сцены.
При длительных цепочках вращений возникают численные отклонения, связанные с накоплением ошибок округления. Нормализация кватернионов после операций умножения и интерполяции поддерживает устойчивость представления.
Особое значение имеет сохранение единичной нормы:
Кватернионы используются не только для объектов сцены, но и для управления камерой. Вращение камеры вокруг точки наблюдения часто выражается через последовательность кватернионных преобразований, обеспечивая стабильное вращение без ограничения углов Эйлера и без потери ориентации при экстремальных наклонах.