Como lo expusieron Nathan Reed y Teodron, la receta para rotar un vector v por un cuaternión de longitud unitaria q es:
1) Crear un cuaternión puro p de v . Esto simplemente significa agregar una cuarta coordenada de 0:
p = ( vX, vy, vz, 0 ) ⇔ p = ( v , 0 )
2) Multiplíquelo previamente con q y multiplíquelo posteriormente con el conjugado q * :
pags′= q× p × q∗
3) Esto dará como resultado otro cuaternión puro que se puede volver a convertir en un vector:
v′=(p′x,p′y,p′z)
Este vector v′ es v girado por q .
Esto está funcionando pero lejos de ser óptimo . Las multiplicaciones de cuaterniones significan toneladas y toneladas de operaciones. Tenía curiosidad sobre varias implementaciones como esta , y decidí encontrar de dónde provenían. Aquí están mis hallazgos.
También podemos describir q como la combinación de un vector tridimensional u y un s escalar :
q= ( uX, uy, uz, s ) ⇔ q= ( u , s )
Por las reglas de multiplicación cuaternión , y como el conjugado de un cuaternión de longitud unitaria es simplemente inverso, obtenemos:
pags′= 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 escalar (elipses) da como resultado cero, como se detalla aquí . Lo interesante es la parte del vector, también conocido como nuestro vector girado v ' . Se puede simplificar usando algunas identidades vectoriales básicas :
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 )
Esto ahora es mucho más óptimo ; dos productos de puntos, un producto cruzado y algunos extras: alrededor de la mitad de las operaciones. Lo que daría algo así en el código fuente (suponiendo una biblioteca matemática vectorial genérica):
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);
}