Tengo dos vectores uy v. ¿Hay alguna forma de encontrar un cuaternión que represente la rotación de u a v?
math
vector
quaternions
sdfqwerqaz1
fuente
fuente
crossproduct
no será válido en estos casos, por lo que primero debe verificardot(v1, v2) > 0.999999
ydot(v1, v2) < -0.999999
, respectivamente, y devolver un quat de identidad para vectores paralelos, o devolver una rotación de 180 grados (sobre cualquier eje) para vectores opuestos.sqrt((v1.Length ^ 2) * (v2.Length ^ 2))
simplifica av1.Length * v2.Length
. No pude obtener ninguna variación de esto para producir resultados sensibles.Solución vectorial a mitad de camino
Se me ocurrió la solución que creo que Imbrondir estaba tratando de presentar (aunque con un error menor, que probablemente fue la razón por la que sinisterchipmunk tuvo problemas para verificarlo).
Dado que podemos construir un cuaternión que represente una rotación alrededor de un eje así:
Y que el punto y el producto cruzado de dos vectores normalizados son:
Al ver que se puede lograr una rotación de u a v girando por theta (el ángulo entre los vectores) alrededor del vector perpendicular, parece que podemos construir directamente un cuaternión que represente dicha rotación a partir de los resultados del punto y los productos cruzados. ; sin embargo, tal como está, theta = ángulo / 2 , lo que significa que hacerlo daría como resultado el doble de la rotación deseada.
Una solución es calcular un vector a mitad de camino entre u y v , y usar el punto y el producto cruzado de u y el vector de mitad de camino para construir un cuaternión que represente una rotación del doble del ángulo entre u y el vector de mitad de camino , lo que nos lleva hasta v !
Hay un caso especial, donde u == -v y un vector único a mitad de camino se vuelve imposible de calcular. Esto es de esperar, dadas las infinitas rotaciones del "arco más corto" que pueden llevarnos de u a v , y simplemente debemos rotar 180 grados alrededor de cualquier vector ortogonal a u ( ov ) como nuestra solución de caso especial. Esto se hace tomando el producto cruzado normalizado de u con cualquier otro vector que no sea paralelo a u .
A continuación, se muestra un pseudocódigo (obviamente, en realidad, el caso especial tendría que tener en cuenta las inexactitudes del punto flotante, probablemente al comparar los productos punto con un umbral en lugar de un valor absoluto).
También tenga en cuenta que no hay un caso especial cuando u == v (se produce el cuaternión de identidad; compruébelo usted mismo).
La
orthogonal
función devuelve cualquier vector ortogonal al vector dado. Esta implementación utiliza el producto cruzado con el vector de base más ortogonal.Solución de cuaternión a medio camino
Esta es en realidad la solución presentada en la respuesta aceptada, y parece ser marginalmente más rápida que la solución vectorial a mitad de camino (~ 20% más rápido según mis mediciones, aunque no confíe en mi palabra). Lo agrego aquí en caso de que otros como yo estén interesados en una explicación.
Esencialmente, en lugar de calcular un cuaternión utilizando un vector de mitad de camino, puede calcular el cuaternión que da como resultado el doble de la rotación requerida (como se detalla en la otra solución) y encontrar el cuaternión a mitad de camino entre eso y cero grados.
Como expliqué antes, el cuaternión para duplicar la rotación requerida es:
Y el cuaternión para la rotación cero es:
Calcular el cuaternión a mitad de camino es simplemente una cuestión de sumar los cuaterniones y normalizar el resultado, al igual que con los vectores. Sin embargo, como también ocurre con los vectores, los cuaterniones deben tener la misma magnitud, de lo contrario el resultado se desviará hacia el cuaternión con la magnitud mayor.
Un cuaternión construida a partir del punto y el producto vectorial de dos vectores tendrá la misma magnitud que los productos:
length(u) * length(v)
. En lugar de dividir los cuatro componentes por este factor, podemos escalar el cuaternión de identidad. Y si se preguntaba por qué la respuesta aceptada aparentemente complica las cosas con el usosqrt(length(u) ^ 2 * length(v) ^ 2)
, es porque la longitud al cuadrado de un vector es más rápida de calcular que la longitud, por lo que podemos guardar unsqrt
cálculo. El resultado es:Y luego normaliza el resultado. El pseudocódigo sigue:
fuente
El problema, como se dijo, no está bien definido: no existe una rotación única para un par de vectores dado. Considere el caso, por ejemplo, donde u = <1, 0, 0> y v = <0, 1, 0> . Una rotación de u a v sería una rotación pi / 2 alrededor del eje z. Otra rotación de u a v sería una rotación pi alrededor del vector <1, 1, 0> .
fuente
¿Por qué no representar el vector usando cuaterniones puros? Quizás sea mejor si los normaliza primero.
q 1 = (0 u x u y u z ) '
q 2 = (0 v x v y v z )'
q 1 q rot = q 2
Pre-multiplique con q 1 -1
q rot = q 1 -1 q 2
donde q 1 -1 = q 1 conj / q norma
Esto se puede considerar como "división a la izquierda". La división derecha, que no es lo que quieres es:
q rot, right = q 2 -1 q 1
fuente
No soy muy bueno en Quaternion. Sin embargo, luché durante horas con esto y no pude hacer que la solución Polaris878 funcionara. Intenté pre-normalizar v1 y v2. Normalizando q. Normalizando q.xyz. Sin embargo, todavía no lo entiendo. El resultado todavía no me dio el resultado correcto.
Al final, aunque encontré una solución que lo hizo. Si ayuda a alguien más, aquí está mi código de trabajo (python):
Se debe hacer un caso especial si v1 y v2 son paralelos como v1 == v2 o v1 == -v2 (con cierta tolerancia), donde creo que las soluciones deberían ser Quaternion (1, 0,0,0) (sin rotación) o Quaternion (0, * v1) (rotación de 180 grados)
fuente
quat = diffVectors(v1, v2); assert quat * v1 == v2
.angle
obtiene su valor de un producto escalar.Algunas de las respuestas no parecen considerar la posibilidad de que el producto cruzado pueda ser 0. A continuación, el fragmento utiliza la representación del eje del ángulo:
Se
toQuaternion
puede implementar de la siguiente manera:Si está utilizando la biblioteca Eigen, también puede hacer:
fuente
toQuaternion(axis, ang)
-> olvidó especificar qué esang
angle
que forma parte de la representación eje-ángulo del cuaternión, medido en radianes.Desde el punto de vista del algoritmo, la solución más rápida se ve en pseudocódigo
Asegúrese de que necesita cuaterniones de unidad (normalmente, es necesario para la interpolación).
NOTA: Los cuaterniones sin unidad se pueden usar con algunas operaciones más rápido que la unidad.
fuente