avatar

Кватернионы и вращение векторов с их помощью. Часть 3.

опубликовал в Программирование
В последней части этого вводного курса( Часть 1, Часть 2) по кватернионам, мы попробуем получить парочку полезных функций для работы с кватернионами, и взвесим все за и против использования кватернион в целом.

Полная функция Кватерниона из углов Эйлера.

В прошлой части мы определили функцию позволяющую перемножать кватернионы и вычислять кватернион поворота вокруг одной оси. Теперь используя эти функции, получим функцию поворота на углы Эйлера.

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
1
4769
  • 3 комментария

    avatar
    Вы пожалуйста в каждой статье делайте ссылки на предыдущие — что бы не было так читателям мучительно больно их все искать — PLZ
    avatar
    Окей сейчас поправлю)
    Чтобы оставить комментарий необходимо .