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);
}
vprime = v + ((cross(u, v) * s) + cross(u, cross(u, v)) * 2.0f
¿Es esta una optimización similar? Se ve algo similar, pero no es lo mismo: solo usa productos cruzados, no productos de punto. El código fuente original se puede encontrar en el archivo type_quat.inl del repositorio GLM oficial en eloperator*
que toma un cuaternión y un vector (vec<3, T, Q> operator*(qua<T, Q> const& q, vec<3, T, Q> const& v)
)En primer lugar, q ^ (- 1) no es -q / magnitud (q); es q * / (magnitud (q)) ^ 2 (q * es el conjugado; eso niega todos los componentes excepto el real). Por supuesto, puede omitir la división por la magnitud si todos sus cuaterniones ya están normalizados, lo que normalmente sería en un sistema de rotación.
En cuanto a la multiplicación con un vector, simplemente extiende el vector a un cuaternión estableciendo el componente real de un quat en cero y sus componentes ijk en el xyz del vector. Luego haces las multiplicaciones de quaternion para obtener v ', y luego extraes los componentes ijk nuevamente. (La parte real de v 'siempre debe salir a cero, más o menos algún error de punto flotante).
fuente
Primera observación:
q
lo contrario de no es-q/magnitude(q)
, eso es completamente incorrecto. Las rotaciones con cuaterniones implican que estos equivalentes de números complejos 4D tienen una norma unitaria, por lo tanto, se encuentran en la esfera de la unidad S3 en ese espacio 4D. El hecho de que un quat sea unitario significa que su norma esnorm(q)^2=q*conjugate(q)=1
y eso significa que la inversa del quat es su conjugado.Si una unidad de cuaternión se escribe como
q=(w,x,y,z)
= (cos (t), sin (t) v ), entonces su conjugado esconjugate(q)=(w,-x,-y,-z)
= (cos (t), - sin (t) v ), donde t es la mitad del ángulo de rotación y v es el eje de rotación (como un vector unitario, por supuesto).Cuando ese tipo de Hamilton decidió jugar con equivalentes de números complejos en dimensiones superiores, también se topó con algunas propiedades agradables. Por ejemplo, si empleas un cuaternión completamente puro
q=(0,x,y,z)
(¡sin parte escalar w !), Puedes considerar esa basura como un vector (¡en realidad es un quat sobre lo que la gente podría llamar el ecuador de la esfera S3, que es una esfera S2! ! - cosas alucinantes si consideramos cuán técnicamente discapacitados nos parecen las personas del siglo XIX hoy en día a los vaqueros de los teléfonos móviles. Así que Hamilton tomó ese vector en su forma quat:v=(0,x,y,z)
e hizo una serie de experimentos considerando las propiedades geométricas de los quats.dónde
Observación: q * (0, v) * conj (q) tiene que ser otro quat de la forma (0, v '). No pasaré por toda esa explicación aparentemente complicada de por qué sucede esto, pero si gira un cuaternión imaginario puro (¡o un vector en nuestro caso!) A través de este método, debe obtener un tipo de objeto similar: quat imaginario puro. y tomas su parte imaginaria como resultado. Ahí lo tienes, el maravilloso mundo de las rotaciones con cuaterniones en una cáscara de nuez (ty).
NOTA : a cualquiera que salte con esa frase usada en exceso: ¡los quats son buenos porque evitan el bloqueo de cardán ... ¡primero deben desbloquear su imaginación! Los quats son un mero aparato matemático "elegante" y se pueden evitar por completo mediante el uso de otros enfoques, el que encuentro completamente geométricamente equivalente es el enfoque de ángulo del eje.
CÓDIGO : la biblioteca de C ++ que imagino es bastante simplista, pero tiene todas las operaciones de matriz, vector y quat que un experimentador de gráficos 3D debería necesitar sin tener que perder más de 15 minutos para aprenderlo. Puede probar las cosas que escribí aquí usando eso en 15 minutos si no eres un novato en C ++. ¡Buena suerte!
fuente
Aquí hay una forma alternativa de transformar un vector por un cuaternión. Es la forma en que MS lo hace en el marco xna. http://pastebin.com/fAFp6NnN
fuente
Traté de resolver esto a mano y se me ocurrió la siguiente ecuación / método:
Agradecería que alguien revisara mt deriviation. Utilicé http://pastebin.com/8QHQqGbv . Sugeriría copiar a un editor de texto que admita el desplazamiento lateral.
en mi notación usé q ^ (- 1) para significar conjugado, y no inverso, y diferentes identificadores, pero espero que sea seguible. Creo que la mayoría tiene razón, especialmente cuando al probar que la porción real del vector desaparecería.
fuente