Espejos de rotación slerping

9

Giro mi personaje del juego para mirar al objetivo usando el siguiente código:

        transform.rotation = Quaternion.Slerp(startQuaternion, lookQuaternion, turningNormalizer*turningSpeed/10f)

startQuaternion es la rotación actual del personaje cuando se le da un nuevo objetivo.

lookQuaternion es la dirección que debe mirar el personaje y está configurado de esta manera:

    destinationVector = currentWaypoint.transform.position - transform.position;
    lookQuaternion = Quaternion.LookRotation(destinationVector, Vector3.up);

turnNormalizer solo se Time.deltaTimeincrementa y turningSpeedes un valor estático dado en el editor.

El problema es que mientras el personaje gira como debería la mayoría de las veces, tiene problemas cuando tiene que hacerlo cerca de 180 grados. Luego, a veces se agita y refleja la rotación:

ingrese la descripción de la imagen aquí

En esta imagen mal dibujada, el personaje (a la derecha) comienza a girar hacia el círculo a la izquierda. En lugar de simplemente girar hacia la izquierda o hacia la derecha, comienza este "baile de espejo":

  1. Comienza a girar hacia el nuevo revestimiento.
  2. Luego, de repente, se ajusta al mismo ángulo pero en el otro lado y sigue girando

Hace este "reflejo" tanto tiempo hasta que mira al objetivo. ¿Es esto una cosa con cuaterniones, slerping / lerping u otra cosa?

EDITAR1: Aparentemente, el problema no surge de la rotación misma. El problema más probable es que el personaje se mueva hacia la cara mientras gira. Al limitar el ángulo, entre la orientación y el objetivo, cuando se permite que el personaje se mueva, se reduce y, a veces, se elimina la rotación de fluctuación / reflejo.

Por supuesto, esto plantea más preguntas, ¿por qué el personaje no puede moverse y rotar al mismo tiempo sin problemas? Código utilizado para el movimiento:

transform.Translate(Vector3.forward * runningSpeed/10f * Time.deltaTime);
Esa
fuente
¿Se está actualizando 'lookQuaternion' en cada cuadro? Si es así, entonces mi suposición sería que algunas pequeñas inexactitudes conducen a una especie de inquietud en la que el jugador `` supera '' la rotación de la mirada y, por lo tanto, la nueva dirección para mirar está justo al otro lado de `` directamente detrás '' ... .
Steven Stadnicki

Respuestas:

5

Cada orientación en el espacio 3D se puede representar mediante 2 cuaterniones de unidades distintas qy -q(componentes negados q). Por ejemplo, la orientación representada por la matriz de identidad 3x3 Ise puede representar por 2 cuaterniones:

 q:  { 0,  0,  0},  1
-q:  {-0, -0, -0}, -1

Ambos representan la misma orientación en el espacio 3D, su producto de punto es exactamente -1, cada uno de ellos en el otro hemisferio, exactamente en los lados opuestos de la hiperesfera.

El resultado que observa cuando el slerp toma el arco más largo para rotar, es cuando se slerping entre 2 cuaterniones que no se encuentran en el mismo hemisferio. Si eso sucede, solo niega uno de ellos antes de hacerlos, entonces el slerp tomará el arco más corto.

El producto punto es una herramienta fácil para saber si eso sucede. Si el producto escalar de ambos cuaterniones es menor que 0, entonces no se encuentran en el mismo hemisferio. Por lo tanto, si el producto escalar de ambos es menor que 0, solo por componentes, niegue el otro cuaternión antes de probarlo.

Maik Semder
fuente
Me pregunto si te entendí correctamente cuando lo intenté con esto. if(Quaternion.Dot (lookQuaternion, startQuaternion) < 0) { startQuaternion = Quaternion.Inverse(startQuaternion); }Pero no corrigió el problema. Lo siento por el mal formato, parece que no puedo domar esta sección de comentarios.
Esa
Casi, pero no Inverse, esa es una operación diferente a Negate. if(Quaternion.Dot (lookQuaternion, q) < 0) { q.x = -q.x; q.y = -q.y; q.z = -q.z; q.w = -q.w; }No uso C #, pero por el aspecto del docu, parece que también podría usar la función Negate directamente.
Maik Semder
if(Quaternion.Dot (lookQuaternion, startQuaternion) < 0) { startQuaternion = Quaternion.Negate(startQuaternion); }
Maik Semder
Me temo que esto no solucionó el problema. He actualizado la pregunta.
Esa
Sí, eso es probablemente una mezcla de diferentes errores. Simplifique la configuración de su prueba, pruebe una cosa a la vez, no la traducción y la rotación al mismo tiempo. Primero asegúrese de que uno funcione, luego el otro, y luego ambos juntos. Primero, concéntrese solo en la rotación, use algunos valores de orientación bien conocidos, como comenzar a 170 grados, bajar a cero, ver dónde sale mal y publicarlo aquí
Maik Semder
1

Bueno, su problema es porque esos dos vectores que forman sus cuaterniones hacen 180 grados, entonces la pregunta que debe hacerse al interpolar qué arco se supone que debe tomar. el arco superior o el inferior ??

Esto es lo que básicamente causa la duplicación, cada vez que está interpolando está tomando el revés mientras mantiene el ángulo.

De acuerdo a este enlace .

Cuando theta es de 180 grados, el resultado no está definido porque no hay una dirección más corta para rotar, no creo que esta situación se maneje correctamente todavía, sería mejor si elegimos algún eje arbitrario que sea normal a qa o qb, lo haría Aprecio cualquier idea sobre la mejor manera de hacer esto.

Lo que debe hacer es interpolar su cuaternión inicial con un cuaternión intermedio (para determinar qué arco tomar) y, cuando se encuentre, use el cuaternión intermedio para continuar al cuaternión objetivo real.

concepto3d
fuente
1

El problema que sospecho que está viendo no tiene nada que ver con su código, sino que es un problema fundamental con la interpolación a lo largo de la superficie de una esfera (en este caso, para viewDirection). Entre (casi) dos puntos en una esfera hay un gran círculo único; por ejemplo, al fijar arbitrariamente nuestro punto de "inicio" en el polo norte, el gran círculo sería el meridiano en el que se encuentra el punto final. La interpolación de un punto a otro se mueve a lo largo de este gran círculo.

Ahora, para la mayoría de los puntos en una esfera, los puntos cercanos corresponden a grandes círculos cercanos; por ejemplo, los meridianos en los que se encuentran Los Ángeles y Phoenix están bastante cerca uno del otro. Pero cuando el punto de destino es la antípoda del punto original, el polo sur al polo norte del punto de inicio, ya no hay un solo gran círculo a través de ambos, sino que todos los grandes círculos a través de uno pasan por el otro. Lo que es peor, esto significa que los puntos cerca del polo sur no son "la mayoría de los puntos"; dos puntos cerca uno del otro y ambos cerca del polo sur pueden tener meridianos muy divergentes.

Sospecho que lo que estás viendo es una manifestación de esta inestabilidad en el meridiano, o en otras palabras, el arco de interpolación. Cuando el objetivo de la mirada está directamente detrás del personaje, entonces cosas como la imprecisión de primer orden en su 'integración de Euler' de la posición del personaje, y la forma en que cambia la dirección de la mirada cuadro a cuadro, conducirán a estos cambios diferentes arcos de interpolación de un cuadro a otro, y esto probablemente conducirá al 'escalonamiento' que estás viendo.

En cuanto a qué hacer con él, lo mejor que se me ocurre es no volver a calcular la dirección de la mirada del "objetivo" en cada cuadro; en su lugar, use el mismo para un lapso de varios cuadros, luego calcule uno nuevo y use eso para varios cuadros, etc. Si es necesario, incluso puede interpolar de un objetivo al siguiente en el lapso de unos pocos cuadros para que La dirección del movimiento no cambia abruptamente.

Steven Stadnicki
fuente