Come esposto Nathan Reed e teodron, la ricetta per ruotare un vettore v di un quaternione di lunghezza unitaria q è:
1) Creare un quaternione puro p di v . Questo significa semplicemente aggiungere una quarta coordinata di 0:
p = ( vX, vy, vz, 0 ) ⇔ p = ( v , 0 )
2) Pre-moltiplicarlo con q e post-moltiplicarlo con il coniugato q * :
p'= q× p × q*
3) Ciò si tradurrà in un altro quaternione puro che può essere convertito in un vettore:
v'= ( p'X, p'y, p'z)
Questo vettore v' è v ruotato di q .
Funziona ma non è ottimale . Le moltiplicazioni del quaternione significano tonnellate e tonnellate di operazioni. Ero curioso di conoscere varie implementazioni come questa e ho deciso di trovare da dove provenissero. Ecco i miei risultati.
Possiamo anche descrivere q come la combinazione di un vettore tridimensionale u con uno scalare s :
q= ( uX, uy, uz, s ) ⇔ q= ( u , s )
Secondo le regole della moltiplicazione del quaternione , e poiché il coniugato di un quaternione di lunghezza unitaria è semplicemente inverso, otteniamo:
p'= qp q*= ( u , s ) ( v , 0 ) ( - u , s )= ( s v + u × v , - u ⋅ v ) ( - u , s )= ( ( - u ⋅ v ) ( - u ) + s ( s v + u × v ) + ( s v + u × v ) × ( - u ) , ... ) = ( ( u ⋅ v ) u + s2v + s ( u × v ) + s v × ( - u ) + ( u × v ) × ( - u ) , ... )
La parte scalare (ellissi) risulta in zero, come dettagliato qui . La cosa interessante è la parte vettoriale, AKA il nostro vettore ruotato v ' . Può essere semplificato utilizzando alcune identità vettoriali di base :
v'= ( u ⋅ v ) u + s2v + s ( u × v ) + s ( u × v ) + u × ( u × v )= ( u ⋅ v ) u+ s2v + 2 s ( u × v ) + ( u ⋅ v ) u - ( u ⋅ u ) v= 2 ( u ⋅ v ) u + ( s2- u ⋅ u ) v + 2 s ( u × v )
Questo è ora molto più ottimale ; due prodotti a punti, un prodotto incrociato e alcuni extra: circa la metà delle operazioni. Che darebbe qualcosa del genere nel codice sorgente (supponendo una libreria matematica vettoriale generica):
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);
}