Comme Nathan Reed et teodron l'ont exposé, la recette pour faire tourner un vecteur v par un quaternion q de longueur unitaire est:
1) Créez un quaternion pur p à partir de v . Cela signifie simplement ajouter une quatrième coordonnée de 0:
p=(vx,vy,vz,0)⇔p=(v,0)
2) Pré-multipliez-le avec q et post-multipliez-le avec le conjugué q * :
p′=q×p×q∗
3) Cela se traduira par un autre quaternion pur qui peut être transformé en vecteur:
v′=(p′x,p′y,p′z)
Ce vecteur v′ est v tourné de q .
Cela fonctionne mais loin d'être optimal . Les multiplications du quaternion signifient des tonnes et des tonnes d'opérations. J'étais curieux de connaître diverses implémentations comme celle-ci et j'ai décidé de trouver d'où elles venaient. Voici mes découvertes.
On peut aussi décrire q comme la combinaison d'un vecteur tridimensionnel u et d'un scalaire s :
q=(ux,uy,uz,s)⇔q=(u,s)
Selon les règles de la multiplication du quaternion , et comme le conjugué d'un quaternion de longueur unitaire est simplement son inverse, nous obtenons:
p′=qpq∗=(u,s)(v,0)(−u,s)=(sv+u×v,−u⋅v)(−u,s)=((−u⋅v)(−u)+s(sv+u× v)+(sv+u×v)×(−u),…)=((u⋅v)u+s2v+s(u×v)+sv×(−u)+(u×v)×(−u),…)
La partie scalaire (ellipses) donne zéro, comme détaillé ici . Ce qui est intéressant, c'est la partie vectorielle, AKA notre vecteur pivoté v ' . Il peut être simplifié à l'aide de quelques identités vectorielles de base :
v′=(u⋅v)u+s2v+s(u×v)+s(u×v)+u×(u×v)=(u⋅v)u+s2v+2s(u×v)+(u⋅v)u−(u⋅u)v=2(u⋅v)u+(s2−u⋅u)v+2s(u×v)
C'est maintenant beaucoup plus optimal ; deux produits scalaires, un produit croisé et quelques extras: environ la moitié des opérations. Ce qui donnerait quelque chose comme ça dans le code source (en supposant une bibliothèque mathématique vectorielle générique):
void rotate_vector_by_quaternion(const Vector3& v, const Quaternion& q, Vector3& vprime)
{
// Extract the vector part of the quaternion
Vector3 u(q.x, q.y, q.z);
// Extract the scalar part of the quaternion
float s = q.w;
// Do the math
vprime = 2.0f * dot(u, v) * u
+ (s*s - dot(u, u)) * v
+ 2.0f * s * cross(u, v);
}