Quaternions
Cómo utilizar el sistema de cuaternión para gestionar la rotación de los objetos del juego.
En
Unity, la rotación de un
Trasform se guarda como un
Quaternion (cuaternio). Funcionan de manera similar a los vectores pero tienen cuatro componentes:
x, y, z y
w. Estos componentes son interdependientes y trabajan juntos para definir cualquier rotación que un objeto pueda necesitar.
Una de las cosas más importantes que debemos recordar cuando estamos usando cuaternios es que desde que los componentes
x, y, z y
w funcionan juntos, nunca deberías ajustarlos individualmente.
Afortunadamente,
Unity tiene muchas funciones integradas para hacer la administración de los cuaternios muy fácil.
El sistema para administrar las rotaciones con el que probablemente estás familiarizado se llama Ángulos de Euler. Los valores rotacionales que se muestran en el
Inspector usan este sistema, porque es un poco más fácil de entender.
La rotación de los Ángulos de Euler se basa en una rotación alrededor de cada uno de los ejes: horizontal, vertical y z. Quizás te preguntes por qué
Unity utiliza cuaternios si los Ángulos de Euler son fáciles de entender, especialmente desde que
Unity convierte los cuaternos a Ángulos de Euler para el
Inspector.
Basta decir que los Ángulos de Euler están sujetos a algo llamado el bloqueo de cardán, el que puede prevenir que los incrementos rotacionales funcionen correctamente. Afortunadamente, desde que
Unity guarda las rotaciones como cuaternios, los mismos que no están sujetos al bloqueo de cardán, no tenemos ese problema.
Vamos a echarle un vistazo a algunas de las funcionalidades que están disponibles a través de la clase Quaternion.
Vamos a empezar con la función
LookRotation(). Aquí tenemos la configuración de una escena con un personaje y una esfera. El personaje tiene un script anexado llamado
LookatScript.
La esfera tiene un script anexado llamado
MotionScript. El
MotionScript. simplemente mueve el objeto de un lado al otro. basado en el ingreso del eje horizontal.
public class MotionScript : MonoBehaviour
{
public float speed = 3f;
void Update()
{
transform.Translate(Input.GetAxis("Horizontal") * speed * Time.deltaTime, 0, 0);
}
}
LookAtScript tiene un campo público para un
Transform target. y en la función
Update() vamos a usar
LookRotation() para hacer que el objeto rote y esté de cara al objetivo.
public class LookAtScript : MonoBehaviour
{
public Transform target;
void Update()
{
Vector3 relativePos = target.position - transform.position;
transform.localRotation = Quaternion.LookRotation(relativePos);
}
}La función
LookRotation() toma un
Vector3. Regresa una rotación cuaternio alineada con el
Vector3 que se pasó.
Al calcular el vector relativo entre el objeto y el objetivo:
Vector3 relativePos = target.position - transform.position;podemos hacer que el eje z del objeto rote hacia el objetivo.
transform.localRotation = Quaternion.LookRotation(relativePos);Esto funciona de manera similar a
transform.LookAt(), pero al usar cuaternos se configura la rotación explícitamente.
También vale la pena recalcar que podemos pasar un segundo
Vector3 a la función. Este
Vector3 le dice a la función hacia qué dirección se considera arriba.
transform.localRotation = Quaternion.LookRotation(relativePos /*forward*/, vector3.Up /*upwards*/);En el
Editor Unity, iniciamos nuestra escena. Podemos ver que no importa a dónde movamos la esfera, el personaje se torna hacia ella.
La próxima función a la que queremos echarle un vistazo es la función
Slerp(). Slerp es una abreviación de Spherical Interpolation (interpolación polar). Es muy similar a la función
Lerp(), la misma que es una abreviación de Linear Interpolation (interpolación linear).
La gran diferencia entre las dos es que Lerp hará una interpolación pareja entre dos cuaternos mientras que es
Slerp() hará una interpolación en una curva. El resultado es que
Lerp() proveerá un cambio parejo a través del tiempo, mientras que
Slerp() comenzará y terminará despacio y será más rápida a la mita
Aquí tenemos una escena con otro personaje y otra esfera. El personaje no tiene ningún script anexado. La esfera tiene un
GravityScript anexado a ella. Esta escena usa
Slerp() y un poco de arranque para obtener un efecto de gravedad orbital.
public class GravityScript : MonoBehaviour
{
public Transform target;
void Update()
{
Vector3 relativePos = (target.position + new Vector3(0, 1.5f, 0)) - transform.position;
Quaternion rotation = Quaternion.LookRotation(relativePos);
Quaternion current = transform.localRotation;
transform.localRotation = Quaternion.Slerp(current, rotation, Time.deltaTime);
transform.Translate(0, 0, 3 * Time.deltaTime);
}
}En el script
GravityScript hemos configurado algo similar al
LookAtScript de antes. Otra vez, tenemos un campo público para nuestro
Transform objetivo.
public Transform target;También estamos calculando el vector relativo entre el objeto y el objetivo. Aunque esta vez estamos agregando un
offset para representar la altura de la esfera.
Vector3 relativePos = (target.position + new Vector3(0, 1.5f, 0)) - transform.position;También estamos calculando la
LookRotation() como antes, excepto que esta vez no estamos guardándola en la rotación del
Transform del objeto. En su lugar estamos guardándola en una variable tipo cuaternio llamada rotation.
Quaternion rotation = Quaternion.LookRotation(relativePos);Luego, guardamos la rotación local del objeto en una variable cuaternio llamada
current.
Quaternion current = transform.localRotation;Después de eso usamos la función
Slerp() para rotar el objeto despacio para que mire hacia el objetivo.
transform.localRotation = Quaternion.Slerp(current, rotation, Time.deltaTime);La función
Slerp() lee la rotación actual, la rotación resultado y la velocidad que deben interpolar o girar. El hecho de que la rotación no ocurra inmediatamente,
sino que ocurra a medida que pase el tiempo, es la clave para hacer que este ejemplo funcione.
Después de que rotemos el objeto ligeramente hacia el objetivo, lo movemos hacia adelante un poco.
transform.Translate(0, 0, 3 * Time.deltaTime);En el
Editor Unity, iniciamos la escena y vemos el resultado. La esfera siempre está moviéndose hacia adelante y girando para estar de frente al objetivo, el mismo que es este caso es el personaje. Esto nos da un efecto orbital muy regular y agradable.
Lo último que veremos es la propiedad
identity (identidad) de la clase
Quaternion. El configurar un cuaterno a quaternion.identity efectivamente configurará su rotación Euler a 0, 0, 0 o sin rotación.
public class SomeClass : MonoBehaviour
{
private void Start()
{
transform.localRotation = Quaternion.identity;
}
}Hay más funciones en la clase
Quaternion que puedes encontrar en la documentación vinculada en la parte inferior.
Lo más importante que debes recordar de esta lección es que los
Quaternion son la mejor manera de lidiar con la rotación y que nunca deberías alterar sus componentes independientemente. Siempre habrá algún tipo de funcionalidad que puedas usar en vez de eso.
Apoya el contenido de mi blog a través de:
Fuente: