¿Cómo puedo rotar sobre un punto arbitrario en 3D (en lugar del origen)?

15

Tengo algunos modelos que quiero rotar usando cuaterniones de la manera normal, excepto que en lugar de la rotación sobre el origen, quiero que se desplace ligeramente. Sé que no dices, en el espacio 3d, que giras alrededor de un punto; dices que giras alrededor de un eje. Así que lo estoy visualizando como girando sobre un vector cuya cola no se encuentra en el origen local.

Todas las transformaciones afines en mi motor de renderización / física se almacenan usando SQT (escala, cuaternión, traducción; una idea tomada del libro Game Engine Architecture ). Así que construyo una matriz cada cuadro a partir de estos componentes y lo paso al sombreador de vértices. En este sistema, se aplica la traducción, luego la escala, luego la rotación.

En un caso específico, necesito traducir un objeto en el espacio mundial, escalarlo y rotarlo alrededor de un vértice no centrado en el origen local del objeto.

Pregunta: Dadas las limitaciones de mi sistema actual descrito anteriormente, ¿cómo puedo lograr una rotación local centrada en un punto que no sea el origen? Votación automática a cualquiera que pueda describir cómo hacer esto usando solo matrices también :)

notlesh
fuente
Los cuaterniones ya describen una rotación sobre un eje arbitrario; ¿Tiene problemas para construir tal cuaternión a partir de los datos que tiene?
Martin Sojka
3
En serio, ¿podrían las personas que votaron por las respuestas realmente leerlas ? Di un método, una fórmula eficiente e incluso una demostración. Sin embargo, la única respuesta votada, si bien proporciona información valiosa (y también información claramente errónea), no presenta ninguna de estas preguntas y ni siquiera responde la pregunta.
sam hocevar
@MartinSojka, se trata de un punto arbitrario, no un eje arbitrario.
notlesh
@SamHocevar Ambas respuestas fueron útiles. Elegí el tuyo porque era más exhaustivo y me ayudó a llegar a una solución. Gracias a los dos.
notlesh
Ah, lo siento, lo confundí con Dual Quaternions (esos también te dan la traducción "gratis"). Escribiré lo que quise decir en una respuesta más tarde; tal vez a otros les resulte útil, especialmente porque puede reducir sus tres componentes a uno solo, aunque un poco más complejo.
Martin Sojka

Respuestas:

17

En breve

Solo necesita cambiar T en su formulario SQT.

Reemplace el vector de traducción vcon v' = v-invscale(p-invrotate(p))donde vestá el vector de traducción inicial, pes el punto alrededor del cual desea que ocurra la rotación, invrotatey invscaleson las inversas de su rotación y escala.

Demostración rápida

Deje pser el punto alrededor del cual aplica la rotación r. Deje que ssean sus parámetros de escala y vsu vector de traducción. La transformación final de la matriz es en T(p)R(r)T(-p)S(s)T(v)lugar de R(r)S(s)T(v).

Lo que quieres son nuevos parámetros de transformación v', r'y s'tal que la transformación de matriz final sea R(r')S(s')T(v')y tengamos:

T(p)R(r)T(-p)S(s)T(v) = R(r')S(s')T(v')

El comportamiento en el infinito indica que los parámetros de rotación y los parámetros de escala no pueden cambiar (esto podría demostrarse). Así tenemos r = r'y s = s'. Por lo tanto v', el único parámetro que falta es su nuevo vector de traducción:

T(p)R(r)T(-p)S(s)T(v) = R(r)S(s)T(v')

Si estas matrices son iguales, sus inversas son iguales:

T(-v)S(-s)T(p)R(-r)T(-p) = T(-v')S(-s)R(-r)

Esto es especialmente cierto para el origen O:

T(-v)S(-s)T(p)R(-r)T(-p)O = T(-v')S(-s)R(-r)O

Al escalar y rotar el origen se obtiene el origen, donde obtenemos así:

T(-v)S(-s)T(p)R(-r)(-p) = -v'

v'es el nuevo vector de traducción que está buscando que le permite almacenar su transformación en forma SQT. Probablemente sea posible simplificar el cálculo; pero al menos no se aumenta el almacenamiento requerido .

sam hocevar
fuente
Gracias por la explicación. Por cierto, ¿sabes de algún recurso donde podría leer más sobre trucos de representación SQT?
pachanga
Corríjame si me equivoco, pero parece que otra solución sería almacenar su Quaternion de manera normal, y si necesita tener en cuenta la traducción alrededor de un punto / eje arbitrario, luego construir la matriz Q con esto incluido, simplemente extraiga el vector de traducción desde esta matriz (última columna, generalmente) y agréguela al vector de Traducción de objetos, luego deseche su matriz temporal.
johnbakers
15

Todas las fórmulas de rotación canónicas utilizadas para derivar sus matrices de rotación son para la rotación sobre el origen. Si, en cambio, desea aplicar esa rotación alrededor de un punto específico, primero debe compensar el origen o, de manera equivalente, mover el objeto para que el punto sobre el que desea rotar esté en el origen.

Considere el caso 2D primero, porque es más simple y la técnica se escala. Si tuviera un cubo de ancho 2 centrado en el origen y quisiera rotarlo 45 grados sobre su centro, sería una aplicación trivial de la matriz de rotación 2D .

Pero si, en cambio, quisiera rotarlo alrededor de su esquina superior derecha (ubicada en 1,1), primero tendría que traducirlo para que esa esquina estuviera en el origen. Esto se puede lograr con una traducción de -1,-1. Luego puede rotar el objeto como antes, pero debe seguirlo traduciéndolo (por 1,1). Entonces, en general, para lograr la matriz de rotación Rpara una rotación de raproximadamente el punto Pque haces:

R = translate(-P) * rotate(r) * translate(P)

donde translatey rotateson las matrices canónicas de traslación / rotación, respectivamente. Resulta que esto se escala trivialmente a 3D, lo que con la excepción de tener que suministrar un eje a la rotación también: siempre puede elegir las matrices canónicas de rotación de los ejes X, Y o Z, pero eso sería aburrido. Querrá usar la matriz arbitraria de rotación de eje-ángulo . Tu final Ren 3D es así:

R = translate(-P) * rotate(a,r) * translate(P)

donde aes un vector unitario que representa el eje de rotación y Pahora es un punto 3D en el espacio modelo que representa el punto de rotación.

Como suele suceder, los cuaterniones pueden ser convertidos a y de las representaciones de la matriz, por lo que podría hacer su concatenación de esa manera si así lo elige. O simplemente puede dejar todo como matrices (los cuaterniones tienen algunas ventajas agradables, como ser más fácil de interpolar de una manera sensata, pero si lo necesita o no, depende de usted).

También:

Así que lo estoy visualizando como girando sobre un vector cuya cola no se encuentra en el origen local.

Estrictamente hablando, mientras que los vectores se pueden usar para representar posiciones al considerarlos como desplazamientos desde un origen, los vectores no tienen posiciones en sí mismos, por lo que es un poco inusual visualizar uno como tal.


fuente
Gracias, esta es una buena respuesta. Sin embargo, no se ajusta a las restricciones de mi sistema. Debería haber incluido en mi pregunta, "¿es posible hacer esto dadas estas restricciones?", Y creo que la respuesta es que no, ya que esto requiere dos traducciones y solo proporciono una. ¿Es esta una deficiencia inevitable del uso de SQT como una representación de transformaciones afines?
notlesh 01 de
Se adapta perfectamente a tus limitaciones. La matriz R (producida como translate-rotate-translate-back) es su matriz de rotación. Reemplace Q con R en su sistema "SQT" para que tenga el paradigma de escala-rotación-traducción más común, y listo. Esa última traducción es independiente de las dos traducciones intermedias realizadas para producir la rotación deseada.
¿Estás proponiendo que reemplace el cuaternión con una matriz? ¡Eso es 12 bytes más por objeto (8 si lo almaceno como una matriz 4x3)! Sin embargo, silenciaré al optimista en mí y le daré un giro. (Eso en realidad probablemente no equivaldrá a un aumento de 2kb en la huella ...) Gracias por sus respuestas.
notlesh
Podrías, también podrías convertir entre ellos, construir el cuaternión de rotación de esa manera y volver a conectarte a tu sistema existente.
1
@SamHocevar: Alternativamente, cualquier combinación de los mismos se puede expresar como un solo tornillo .
Martin Sojka