Кватернионы и вращение векторов с их помощью. Часть 3.
JazzyJohn
опубликовал в
Программирование
Полная функция Кватерниона из углов Эйлера.
В прошлой части мы определили функцию позволяющую перемножать кватернионы и вычислять кватернион поворота вокруг одной оси. Теперь используя эти функции, получим функцию поворота на углы Эйлера.
Quaternion QuaternionFromEulerFull(float roll, float pitch, float yaw){
Quaternion result,qx,qy,qz;
Vector vx = { 1, 0, 0 }, vy = { 0, 1, 0 }, vz = { 0, 0, 1 };
qx = QuaternionFromEuler(vx, roll);
qy = QuaternionFromEuler(vy, pitch);
qz = QuaternionFromEuler(vz, yaw);
result =QuaternionMultiply(qx,qy);
result =QuaternionMultiply(result ,qz);
return result ;
}
SLERP
Давайте попробуем реализовать SLERP(Spherical Linear intERPolation) функцию. Такая функция позволяет выполнять плавную интерполяцию между двумя кватернионами, причем такая интерполяция происходит вдоль кратчайшей дуги.
SLERP(t) = (p sin((1–t)a) + q sin(ta)) / sin(a),
где q и p кватернионы,
t изменяется от 0 до 1,
a – угол между двумя кватернионами который определен следующим образом
cos(a)= (q,p)/(|q|*|p|), что для единичных кватернионов соответствует cos(a)= (q,p).
void Slerp(Quaternion * q, Quaternion * p, float t)
{
Quaternion result
float p1[4];
double omega, cosom, sinom, scale0, scale1;
// косинус угла
cosom = q->x*p->x + q->y*p->y + q->z*p->z + q->w*p->w;
if ( cosom <0.0 )
{
cosom = -cosom;
p1[0] = - p->x; p1[1] = - p->y;
p1[2] = - p->z; p1[3] = - p->w;
}
else
{
p1[0] = p->x; p1[1] = p->y;
p1[2] = p->z; p1[3] = p->w;
}
if ( (1.0 - cosom) > DELTA )
{
// стандартный случай (slerp)
omega = acos(cosom);
sinom = sin(omega);
scale0 = sin((1.0 - t) * omega) / sinom;
scale1 = sin(t * omega) / sinom;
}
else
{
// если маленький угол - линейная интерполяция
scale0 = 1.0 - t;
scale1 = t;
}
Result.x = scale0 * q->x + scale1 * p1[0];
result.y = scale0 * q->y + scale1 * p1[1];
result.z = scale0 * q->z + scale1 * p1[2];
result.w = scale0 * q->w + scale1 * p1[3];
}
Кватернионы и DirectX.
Большая часть функций, которые мы разбирали в этих статьях, реализованы в библиотеке DirectX, вот краткий перечень полезных функций для работы с кватернионами:
Определение квантерниона:
typedef struct D3DXQUATERNION {
FLOAT x,y,z,w;
} D3DXQUATERNION;
Перемножение:
D3DXQUATERNION* D3DXQuaternionMultiply(
_Inout_ D3DXQUATERNION *pOut,
_In_ const D3DXQUATERNION *pQ1,
_In_ const D3DXQUATERNION *pQ2
);
Скалярное произведение:
FLOAT D3DXQuaternionDot(
_In_ const D3DXQUATERNION *pQ1,
_In_ const D3DXQUATERNION *pQ2
);
Модуль кватерниона
FLOAT D3DXQuaternionLength(
_In_ const D3DXQUATERNION *pQ
);
Slerp
D3DXQUATERNION* D3DXQuaternionSlerp(
_Inout_ D3DXQUATERNION *pOut,
_In_ const D3DXQUATERNION *pQ1,
_In_ const D3DXQUATERNION *pQ2,
_In_ FLOAT t
);
Кватернион из углов Эйлера
D3DXQUATERNION* D3DXQuaternionRotationYawPitchRoll(
_Inout_ D3DXQUATERNION *pOut,
_In_ FLOAT Yaw,
_In_ FLOAT Pitch,
_In_ FLOAT Roll
);
Кватернион из матрицы поворота
D3DXQUATERNION* D3DXQuaternionRotationMatrix(
_Inout_ D3DXQUATERNION *pOut,
_In_ const D3DXMATRIX *pM
);
За и против использования кватернионов.
Основным минусом кватернионов, является их не наглядность: бросив взгляд на углы Эйлера почти сразу возможно представить, как и куда повернут объект. Посмотрев же на компоненты кватерниона,, понять что-то достаточно сложно.Плюсов много:
1)Отсутствие такого явления как шарнирный замок(Gimbal lock)
2) Удобство интерполяции по кратчайшей дуге.
3) Удобство перемножения, а следовательно переходов от одной системы отсчета в другую
4) Малый объем занимаемой памяти, 4 компонента, вместо 9 если использовать матрицы поворота, а следовательно более быстрые операции нормализации.
Если углы Эйлера, можно приравнять к школьной программе вращения, то кватернионы это уже область ВУЗА. Но это не значит, что их стоит использовать повсеместно. Если Ваша задача сделать простые повороты (как в шутере от первого лица или 2D платформере), вполне хватит углов Эйлера и матриц поворота. Если же Вы делаете космический или авиа симулятор, где каждый объект повернут как угодно, и надо просчитывать вращения, друг относительно друга, кватернионы определенно упростят Вашу работу.
На этом цикл статей по кватернионам, я заканчиваю, надеюсь, он был полезен, и читатели открыли для себя или узнали больше о достаточно удобном инструменте взаимодействия с 3-х мерным пространством.
Спасибо за Внимание.
P.S.
В этой статье использовались материалы, полученные из следующих источников
The Matrix and Quaternions FAQ
Vectors, Vertices, and Quaternions (Direct3D 9)
Кватернионы в программировании игр.
3 комментария