Este es el primero de dos tutoriales sobre cómo orientar un objeto hacia otro en Unity. En concreto, veremos cómo hacer que el modelo 3D de una cámara de vigilancia se oriente automáticamente hacia el Player, siguiendo sus movimientos dentro de la escena.
La versión en video de este tutorial no está disponible actualmente en este idioma.
Transcripción del video
¡Hola a todos!
Este es el primero de dos tutoriales sobre cómo orientar un objeto hacia otro en Unity. En concreto, veremos cómo hacer que el modelo 3D de una cámara de vigilancia se oriente automáticamente hacia el Player, siguiendo sus movimientos dentro de la escena.

Este tutorial fue creado con Unity 2022 y está dividido en dos partes.
En la primera parte analizaremos el problema y lo abordaremos utilizando el método Rotate para obtener una rotación instantánea de la cámara.
En la segunda parte utilizaremos los cuaterniones y el método Slerp para crear rotaciones más suaves y graduales.
Antes de pasar a la implementación, analicemos el problema que debemos resolver.
La cámara solo puede rotar alrededor de su eje vertical local, por lo que podemos reducir el problema al plano 2D. Para hacer este aspecto más comprensible, estoy encuadrando la escena desde la vista TOP en modo Orthogonal.

Tanto el modelo 3D de la cámara de vigilancia como el Player tienen, como todos los game objects, coordenadas de posición XYZ que identifican su ubicación en la escena.
No nos interesa la coordenada position.y, porque la cámara solo puede rotar alrededor de ese eje LOCAL, por lo que consideraremos únicamente las coordenadas position.x y position.z, como si los dos objetos estuvieran en el mismo plano, con el mismo valor para sus coordenadas y.
En nuestro caso, además, la cámara de vigilancia puede considerarse como el origen del sistema de referencia, es decir, el origen de un plano cartesiano en el punto 0,0.
No solo eso, sino que también podemos considerar la dirección encuadrada por la cámara, que en este caso corresponde al eje Y LOCAL negativo, como uno de los ejes cartesianos.
Podemos entonces identificar la dirección que conecta la cámara virtual y la posición del Player en la escena. Esto es simplemente un vector, que en este caso también consideraremos solo en dos dimensiones, es decir, X y Z GLOBAL.
Por lo tanto, la rotación que queremos aplicar a la cámara de vigilancia está dada por el ángulo que separa la orientación del asset, es decir, su eje Y local negativo, y el vector ideal que conecta la cámara con el Player. Al encontrar este ángulo, tendremos la rotación que debe aplicarse al modelo 3D alrededor de su eje vertical local.

Tenemos mucha suerte: existe una función matemática llamada arcotangente de dos argumentos, implementada por el método Atan2 en Mathf, que calcula exactamente este ángulo tomando como parámetro el vector dirección, dado por la diferencia entre las coordenadas de los dos puntos.
En concreto, Atan2 considera el ángulo entre el eje X del plano cartesiano y el vector dirección entre el origen y el objetivo.
En nuestro caso, el origen está dado por las coordenadas X y Z del modelo 3D de la cámara de vigilancia, por lo que las coordenadas objetivo x y y estarán dadas por las diferencias entre las coordenadas de la cámara y las del Player, mientras que el eje X coincide con el eje Y local negativo de la cámara.
La función toma los dos parámetros en orden inverso. En el plano cartesiano tenemos atan2(y, x). En nuestro caso, considerando el sistema de referencia de Unity, donde el eje X es lateral, el eje Z es frontal y el eje Y es vertical y no lo consideramos aquí, escribiremos atan2(x, z).
La documentación online de Unity indica que Mathf.Atan2 recibe las coordenadas y y x, que en nuestro caso serán x y z, y devuelve como valor float el ángulo en radianes cuya tangente es y dividido por x.

La función Rotate en Unity requiere un ángulo de rotación EN GRADOS, por lo que tendremos que tener en cuenta esta diferencia de unidades de medida y la conversión necesaria al escribir el código.
Ahora que hemos analizado el problema y su solución, pasemos a la primera implementación: rotación instantánea con Rotate.
Primero creo un nuevo script C# llamado LookAtObject para asociarlo a la cámara de vigilancia real. Digo cámara de vigilancia real porque este asset está compuesto en realidad por tres elementos: una base para colocar en la pared, un pivot y la cámara.
Nos interesa que la cámara rote alrededor de SU eje vertical, es decir, alrededor de su eje vertical LOCAL.
En el universo virtual de Unity, el eje vertical GLOBAL es el eje Y, pero cada objeto puede tener su propio sistema de referencia LOCAL. En el caso del modelo 3D de la cámara de vigilancia, este corresponde al eje Z LOCAL, como podemos ver al cambiar al modo de visualización LOCAL en el editor de Unity.

Esta distinción introduce una ligera complejidad en el proyecto. Tendremos que calcular el ángulo de rotación en el plano global de la escena utilizando las coordenadas X y Z de los objetos y luego realizar la rotación alrededor del eje vertical local del asset.
Primero, creemos una referencia al objeto que se debe seguir creando una variable Transform llamada objectA que asociamos con el Player en el Inspector.
[SerializeField] private Transform objectA;

Una vez hecho esto, podemos ir directamente a Update para implementar la solución comentada anteriormente. Recuerdo que el eje vertical LOCAL de la cámara es su eje Z.
Necesitamos solo tres líneas de código.
En la primera calcularemos el ángulo que separa la orientación actual de la cámara de la que debería tener para apuntar al objeto.
En la segunda calcularemos la cantidad de rotación que se debe realizar alrededor del eje Z local de la cámara para alcanzar la orientación deseada.
En la tercera realizaremos la rotación efectiva con el método Rotate, al que debemos pasar dos parámetros: el vector vertical local y la cantidad de rotación que se debe aplicar alrededor de ese vector.
Comencemos calculando el ángulo entre la orientación de la cámara de vigilancia y la que debería tener utilizando la función Atan2 de Mathf, que devuelve un valor en radianes que convertiremos a grados.
Hemos visto que en el plano 2D Atan2 recibe dos parámetros: la diferencia entre las coordenadas Y y la diferencia entre las coordenadas X de los dos puntos, en el orden objetivo y observador.
En nuestro escenario, con el sistema de coordenadas global de Unity, donde X y Z están en el plano 2D y Y GLOBAL identifica el eje vertical de la escena, escribiremos:
float theta = Mathf.Atan2((objectA.transform.position.x - transform.position.x),(objectA.transform.position.z - transform.position.z)) * Mathf.Rad2Deg;
De esta forma convertimos el resultado a grados.
Luego pasamos a la segunda instrucción, es decir, calcular la rotación que se debe realizar en grados:
float deltaAngle = Mathf.DeltaAngle(transform.eulerAngles.z, theta);
donde transform.eulerAngles.z representa la orientación actual de la cámara de vigilancia, mientras que theta representa la orientación que debe asumir.
La tercera y última instrucción permite rotar la cámara de vigilancia:
transform.Rotate(Vector3.forward, deltaAngle);
Observa que he utilizado Vector3.forward, que identifica el eje Z LOCAL del objeto, como vector alrededor del cual realizar la rotación. Esto se debe a que, en el caso específico de este modelo 3D, el eje Z LOCAL no indica el frente y la parte trasera sino el eje vertical LOCAL del objeto.
Guarda el script, vuelve al editor de Unity y presiona Play para evaluar el resultado final.
NOTA. Si observas que la cámara de vigilancia no apunta hacia el objetivo, asegúrate de que los valores iniciales de XYZ Rotation de la cámara estén configurados en 0 en el Inspector e inténtalo nuevamente.


En resumen, en esta primera parte hemos analizado el problema, visto cómo considerar los dos objetos en el mismo plano, cómo calcular el vector dirección y, sobre todo, cómo aplicarlo al caso específico de la cámara de vigilancia teniendo en cuenta su sistema de referencia local.
Luego aplicamos una rotación instantánea al objeto, haciendo que apunte al Player en cada frame del juego utilizando la función Rotate.
En la siguiente parte veremos cómo calcular los cuaterniones de rotación y utilizar la función Slerp para rotar el objeto de forma más lenta y suave.