Usando Quaternions: ¿Qué puedo hacer con ellos? (sin las matemáticas)


24

Soy un desarrollador de juegos y no estudié matemáticas. Así que solo quiero usar Quaternions como herramienta. Y para poder trabajar con rotación 3D, es necesario usar Quaternions (o Matrixes, pero quedémonos en Quaternions aquí en esta pregunta). Creo que es importante que muchos desarrolladores los usen. Es por eso que quiero compartir mi conocimiento y espero llenar los huecos que tengo. Ahora....

Entonces, por lo que entendí:

Un Quaternion puede describir 2 cosas:

  1. La orientación actual de un objeto 3d.
  2. La transformación de rotación que un Objeto podría hacer. (rotaciónCambio)

Puedes hacer con un Quaternion:

Multiplicaciones:

  1. Quaternion endOrientation = Quaternion rotacionCambio * Quaternion currentOrientation;

    Entonces, por ejemplo: mi objeto 3D se gira 90 ° hacia la izquierda, y mi rotación que multiplico es una rotación de 180 ° hacia la derecha, al final mi objeto 3D 90 ° se gira hacia la derecha.

  2. Quaternion rotacionCambio = Quaternion endRotation * Quaternion.Inverse (startRotation);

    Con esto obtienes un rotación de cambio, que se puede aplicar a otra orientación.

  3. Vector3 endPostion = Quaternion rotacionCambio * Vector3 currentPosition;

    Entonces, por ejemplo: mi objeto 3D está en posición (0,0,0) y mi rotación que multiplico es una rotación de 180 ° a la derecha, mi posición final es algo así como (0, -50,0). Dentro de ese Quaternion hay un Eje, y una rotación alrededor de ese eje. Gira su punto alrededor de ese eje Y Grados.

  4. Vector3 rotatedOffsetVector = Quaternion rotacionCambio * Vector3 currentOffsetVector;

    Por ejemplo: mi dirección de inicio muestra ARRIBA - (0,1,0), y mi rotación que multiplico es una rotación de 180 ° a la derecha, mi dirección de finalización se muestra hacia abajo. (0, -1,0)

Mezcla (Lerp y Slerp):

  1. Quaternion currentOrientation = Quaternion.Slerp (startOrientation, endOrientation, interpolator)

    si el interpolador es 1: currentOrientation = endOrientation

    si el interpolador es 0: currentOrientation = startOrientation

    Slerp interpola más preciso, Lerp interpola más performant.

Mis preguntas):

¿Todo lo que expliqué hasta ahora es correcto?

¿Es eso "todo" lo que puedes hacer con Quaternions? (obviamente no)

¿Qué más puedes hacer con ellos?

¿Para qué sirven el producto Dot y el producto Cross entre 2 Quaternions?

Editar:

Pregunta actualizada con algunas respuestas


Digamos que no tiene 2, sino ndiferentes orientaciones (actitudes, poses, etc.). Luego puede promediarlos usando pesos, generalizando efectivamente slerp / lerp. También puede convertir un cuaternión en un rotor, lo que equivale a aplicar una velocidad angular durante un cierto período de tiempo a un cuerpo rígido. Por lo tanto, también puede describir la integración de la velocidad angular con cuaterniones. También puede estimar cuán diferentes son las dos orientaciones (calcule la longitud del arco atravesado por los dos cuaterniones en la hiperesfera).
Teodron

Y sí, a primera vista, su razonamiento es correcto (su comprensión de los cuaterniones es bastante buena para una persona no técnica). Esto es inapropiado para un comentario, pero felicidades! Ni siquiera los dotados técnicamente conocen todos los usos de quaternion, aunque los usan solo como herramientas de ingeniería de software para un propósito.
teodron

44
"Y para poder trabajar con rotación 3D, es necesario usar Quaternions" No puedo enfatizar lo falso que es esta oración. Puedes usar los ángulos de Euler o Tait-Bryan para el desarrollo del juego, el único problema es el bloqueo del cardán. Si quieres ser un desarrollador de juegos, necesitarás matemáticas en un punto, aprende.
Bálint

1
"desarrollador de juegos" y "no estudiar matemáticas" es un oxímoron.
Margaret Bloom

2
Aprecio lo que intentas hacer con la pregunta, pero las respuestas deben estar en una respuesta, no en la pregunta. Haga una respuesta "resumida" si cree que vale la pena cotejarlas.
Básico

Respuestas:


23

Multiplicación

Al menos en términos de la implementación de Unity de Quaternions, el orden de multiplicación descrito en la pregunta no es correcto. Esto es importante porque la rotación 3D no es conmutativa .

Entonces, si quiero rotar un objeto rotationChangecomenzando desde él currentOrientation, lo escribiría así:

Quaternion newOrientation = rotationChange * currentOrientation;

(es decir. Las transformaciones se apilan hacia la izquierda, igual que la convención de matriz de Unity. La rotación más a la derecha se aplica primero / en el extremo "más local")

Y si quisiera transformar una dirección o un vector de desplazamiento mediante una rotación, lo escribiría así:

Vector3 rotatedOffsetVector = rotationChange * currentOffsetVector;

(Unity generará un error de compilación si haces lo contrario)

Mezcla

Para la mayoría de los casos, puedes salirte con la rotación de Lerping Esto se debe a que el ángulo utilizado "debajo del capó" en un cuaternión es la mitad del ángulo de rotación, lo que lo hace sustancialmente más cercano a la aproximación lineal de Lerp que algo así como una Matriz (¡que en general no Lerp bien!). Mira alrededor de 40 minutos en este video para obtener más explicaciones .

El único caso en el que realmente necesita Slerp es cuando necesita una velocidad constante en el tiempo, como la interpolación entre fotogramas clave en una línea de tiempo de animación. Para los casos en los que solo le importa que una salida sea intermedia entre dos entradas (como mezclar capas de una animación), generalmente Lerp sirve bastante bien.

¿Qué más?

El producto de puntos de dos unidades de cuaterniones da el coseno del ángulo entre ellos, por lo que puede usar el producto de puntos como una medida de similitud si necesita comparar rotaciones. Sin embargo, esto es un poco oscuro, por lo que para un código más legible a menudo usaría Quaternion.Angle (a, b) en su lugar, que expresa más claramente que estamos comparando ángulos, en unidades familiares (grados).

Estos tipos de métodos de conveniencia que Unity proporciona para Quaternions son súper útiles. En casi todos los proyectos uso este al menos algunas veces :

Quaternion.LookRotation(Vector3 forward, Vector3 up)

Esto genera un cuaternión que:

  • gira el eje z + local para apuntar exactamente a lo largo del forwardargumento vectorial
  • gira el eje local y + para apuntar lo más cerca posible del upargumento vectorial, si se proporciona, o (0, 1, 0)si se omite

La razón por la que "arriba" solo se "acerca lo más posible" es que el sistema está sobredeterminado. Enfrentando z + a forwardusa hasta dos grados de libertad (es decir, guiñada y cabeceo), por lo que solo nos queda un grado de libertad (rodar).

A menudo encuentro que quiero algo con las propiedades de exactitud opuestas: quiero que y + local apunte exactamente a lo largo up, y z + local se acerque lo más posible a forwardla libertad restante.

Esto surge, por ejemplo, cuando trato de formar un marco de coordenadas relativo a la cámara para la entrada de movimiento: quiero que mi dirección local hacia arriba permanezca perpendicular al piso o superficie inclinada normal, por lo que mi entrada no intenta hacer un túnel del personaje en el terreno o levitarlos fuera de él.

También puede obtener esto si desea que la torreta de un tanque mire hacia un objetivo, sin despegarse del cuerpo del tanque cuando apunta hacia arriba / abajo.

Podemos construir nuestra propia función de conveniencia para hacer esto, utilizando LookRotationpara el trabajo pesado:

Quaternion TurretLookRotation(Vector3 approximateForward, Vector3 exactUp)
{
    Quaternion rotateZToUp = Quaternion.LookRotation(exactUp, -approximateForward);
    Quaternion rotateYToZ = Quaternion.Euler(90f, 0f, 0f);

    return rotateZToUp * rotateYToZ;
}

Aquí primero rotamos local y + a z +, y local z + a y-.

Luego, rotamos el nuevo z + hacia nuestra dirección hacia arriba (de modo que el resultado neto es local y + apunta directamente a lo largo exactUp), y el nuevo y + lo más cerca posible a la dirección negada hacia adelante (por lo que el resultado neto es local z + puntos lo más cerca posible a lo largo approximateForward)

Otro método práctico de conveniencia es Quaternion.RotateTowards, que a menudo uso así:

Quaternion newRotation = Quaternion.RotateTowards(
                             oldRotation, 
                             targetRotation,
                             maxDegreesPerSecond * Time.deltaTime
                         );

Esto nos permite acercarnos targetRotationa una velocidad constante y controlable, independientemente de la velocidad de fotogramas, importante para las rotaciones que afectan el resultado / la imparcialidad de la mecánica del juego (como girar el movimiento de un personaje o tener una torreta en el jugador). El ingenuo Lerping / Slerping en esta situación puede conducir fácilmente a casos en los que el movimiento se vuelve más ágil a velocidades de cuadro altas, lo que afecta el equilibrio del juego. (Eso no quiere decir que estos métodos sean incorrectos: hay formas de usarlos correctamente sin cambiar la equidad, solo requiere cuidado. RotateTowardsOfrece un atajo conveniente que se encarga de esto por nosotros)


Consejo: Agregue & t = 40m al final de la URL del video para que salte directamente allí (opcionalmente, por ejemplo, 40m5s). Los productos de punto Quaternion también son útiles cuando se trata de mundos de juego esféricos, o más ampliamente cuando se orientan trozos de esferas giratorias.
Luke Briggs el

@Luke Briggs: El punto esférico del mundo del juego parece que valdría la pena explicarlo en su propia respuesta (especialmente con los diagramas) si lo desea. :)
DMGregory

Gran idea: son las 3 de la mañana aquí (¡así que creo que saldría un poco galimatías!), Pero estaría feliz de hacer algo mañana (¡si lo recuerdo!)
Luke Briggs el

1
Editar: Me dejo llevar pensando en una respuesta, ¡así que el desafío fue aceptado! Al menos lo marcaré como un corte áspero para que la gente pueda darse cuenta de la quemadura nocturna que se produjo: P
Luke Briggs

¡Aquí vamos! Intenté cubrirlo en un sentido gráfico general sobre la base de que su respuesta ya cubre muy bien las funciones subyacentes. ¡Hora de dormir un poco, creo!
Luke Briggs el

14

¿Dónde se usa el producto dot?

En Unity, uno de los usuarios más comunes del producto punto es cada vez que verifica si dos cuaterniones son iguales a través de ==o !=. Unity calcula el producto punto para verificar la similitud en lugar de comparar directamente los valores internos x, y, z, w. Vale la pena tener esto en cuenta, ya que hace que la llamada sea más cara de lo que cabría esperar.

También lo usamos en un caso de uso interesante.

Diversión con productos de punto cuaternión: mundos esféricos y orbitales

Las simulaciones de planetas enteros e incluso sistemas solares completos se están volviendo cada vez más comunes. Para lograr esto en tiempo real, también necesitamos el producto de punto cuaternión. Muchos de ellos. El producto de punto cuaternión está muy infrautilizado pero ciertamente tiene sus usos. ¡Echemos un vistazo!

En primer lugar, tenemos toda una serie de rotaciones a considerar:

  1. (Opcionalmente) La estrella alrededor del centro galáctico
  2. El planeta alrededor de la estrella.
  3. La inclinación del planeta
  4. El giro del planeta
  5. La posición de las celdas de la cuadrícula cercanas (rotadas alrededor del núcleo del planeta) *
  6. Múltiples planos orbitales

Combínalos todos juntos y terminarás con mucha complejidad (¡y muchos números enormes!). Cuando el espectador está de pie en la superficie del planeta, no queremos que se precipiten a una velocidad loca por nuestro espacio en el mundo del juego. En realidad preferiríamos que estuvieran estacionarios y en algún lugar cerca del origen; en su lugar, mueva el universo alrededor del jugador.

Planeta giratorio

Es importante destacar que, para que podamos obtener el giro y la inclinación del planeta correctos en este escenario, necesitamos bloquear el poste en el eje para que solo pueda oscilar hacia arriba / abajo en la imagen de arriba (es decir, hacia arriba mientras el jugador viaja norte). Ahí es donde entra un producto de punto cuaternión. Si no usáramos un producto de punto aquí y, en su lugar, también multiplicamos la inclinación, esto sucedería:

'Planetas' inclinados incorrectamente

Observe cómo los polos de nuestros 'planetas' en órbita siempre se inclinan hacia la estrella. Esto no es lo que sucede en realidad: la inclinación está en una dirección fija .

Sin ir demasiado lejos del tema, aquí hay un resumen rápido:

  • En una esfera, una orientación también describe claramente una posición de superficie.
  • Tenemos muchas rotaciones para combinar.
  • Describe todo como rotación; la posición del espectador también. Esto ayuda a aumentar el rendimiento ya que finalmente terminamos haciendo menos operaciones.
  • El ángulo entre rotaciones (nuestro producto de puntos) ayuda a medir la longitud y funciona particularmente bien para lidiar con las inclinaciones.

Al obtener solo el ángulo, dejamos caer algo de esa rotación no deseada . Al mismo tiempo, también terminamos con una medición de longitud que es útil tanto para la navegación como para el clima local.

* Los planetas se construyen a partir de muchas celdas de cuadrícula . Solo se muestran los cercanos.


2
Esto hace un gran trabajo preparando la escena y motivando el problema, pero todavía estoy un poco confuso sobre cómo las matemáticas del producto de punto cuaternión (es decir, el producto escalar dot(a, b) = a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.wen lugar de la composición de cuaternión que usaríamos para encadenar juntos) rotaciones) nos ayudarían a resolver este problema. Con mucho gusto votaré si puedes explicar esto un poco más tarde (no quiero mantenerte alejado de tu slerp ... ¡quiero decir dormir!)
DMGregory

@DmGregory la respuesta corta es tilt es la extraña; todo se compone muy bien, excepto ese (el planeta parecería tambalearse alrededor de su estrella). ¡(Con suerte!) Agregaré más contexto mañana!
Luke Briggs el

@DMGregory He agregado información adicional (¡no pude dormir!), Con suerte eso lo aclarará.
Luke Briggs el

1
Lo siento si estoy siendo un poco denso, pero después de volver a leer varias veces todavía no sé cómo usaría el producto de puntos en una fórmula para lograr la transformación que estás describiendo. ¿Sería capaz de agregar un pequeño pseudocódigo que establezca las operaciones que realiza explícitamente?
DMGregory

@DMGregory No estoy familiarizado con los cuaterniones, pero si se trata de rotaciones en una esfera, entonces no se trata de composiciones de rotación. Esto está utilizando geometría esférica con vectores para calcular el vector normal para una "línea" en la superficie de una esfera, también conocida como cualquier circunferencia. Una vez más, la respuesta no tiene mucho sentido ni esta pregunta, pero creo que están usando geometría esférica.
El gran pato el
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.