Este é o primeiro de dois tutoriais sobre como orientar um objeto em direção a outro no Unity. Especificamente, veremos como fazer o modelo 3D de uma câmera de vigilância se orientar automaticamente em direção ao Player, acompanhando seus movimentos dentro da cena.
A versão em vídeo deste tutorial não está disponível atualmente neste idioma.
Transcrição do vídeo
Olá a todos!
Este é o primeiro de dois tutoriais sobre como orientar um objeto em direção a outro no Unity. Especificamente, veremos como fazer o modelo 3D de uma câmera de vigilância se orientar automaticamente em direção ao Player, acompanhando seus movimentos dentro da cena.

Este tutorial foi criado usando Unity 2022 e está dividido em duas partes.
Na primeira parte, vamos analisar o problema e abordá-lo utilizando o método Rotate para obter uma rotação instantânea da câmera.
Na segunda parte, utilizaremos quaternions e o método Slerp para criar rotações mais suaves e graduais.
Vamos analisar o problema a ser resolvido antes de passar para a implementação.
A câmera pode girar apenas em torno do seu eixo vertical local, portanto podemos reduzir o problema ao plano 2D. Para tornar esse aspecto mais compreensível, estou enquadrando a cena a partir da visualização TOP em modo Orthogonal.

Tanto o modelo 3D da câmera de vigilância quanto o Player possuem, como todos os game objects, coordenadas de Position XYZ que identificam sua posição na cena.
Não estamos interessados na coordenada position.y, porque a câmera só pode girar em torno desse eixo LOCAL, então consideraremos apenas as coordenadas de posição x e z, como se os dois objetos estivessem no mesmo plano, com o mesmo valor para suas coordenadas y.
No nosso caso, além disso, a câmera de vigilância pode ser considerada como a origem do sistema de referência, ou seja, como a origem em um plano cartesiano, no ponto 0,0.
Não só isso, mas também podemos considerar a direção enquadrada pela câmera, que neste caso corresponde ao eixo LOCAL Y negativo, como um dos eixos cartesianos.
Podemos então identificar a direção que conecta a câmera virtual à posição do Player na cena. Isso é simplesmente um vetor, que neste caso também consideraremos apenas em duas dimensões, ou seja, GLOBAL X e Z.
Conclui-se, portanto, que a rotação que queremos aplicar à Surveillance Camera é dada pelo ângulo que separa a orientação do asset, ou seja, seu eixo local Y negativo, e o vetor ideal que conecta a Surveillance Camera ao Player. Ao encontrar esse ângulo, teremos a rotação a ser aplicada ao modelo 3D em torno do seu eixo vertical local.

Temos muita sorte: existe uma função matemática chamada arco tangente de dois argumentos, implementada pelo método Atan2 em Mathf, que calcula exatamente esse ângulo recebendo como parâmetro o vetor direção, dado pela diferença entre as coordenadas dos dois pontos.
Especificamente, Atan2 considera o ângulo entre o eixo X do plano cartesiano e o vetor direção entre a origem e o alvo.
No nosso caso, a origem é dada pelas coordenadas X e Z do modelo 3D da Surveillance Camera, portanto as coordenadas do alvo x e y serão dadas pelas diferenças de coordenadas entre a câmera de vigilância e o Player, enquanto o eixo X coincide com o eixo local Y negativo da Surveillance Camera.
A função recebe os dois parâmetros em ordem inversa. No plano cartesiano, de fato, temos atan2(y, x). No nosso caso, considerando o sistema de referência do Unity, onde o eixo x é lateral, o eixo z é frontal e o eixo y é vertical, que não consideramos aqui, escreveremos atan2(x, z).
A documentação online do Unity informa que Mathf.Atan2 recebe as coordenadas y e x, que no nosso caso serão x e z, e retorna como valor float o ângulo em radianos cujo tangente é y dividido por x.

A função Rotate no Unity requer um ângulo de rotação EM GRAUS, então teremos que levar em conta essa diferença de unidade de medida, e a conversão necessária, ao escrever o código.
Agora que analisamos o problema e sua solução, vamos passar para a primeira implementação: rotação instantânea com Rotate.
Primeiro, crio um novo script C# chamado LookAtObject para ser associado à câmera de vigilância real. Digo câmera de vigilância real porque esse asset é, na verdade, composto por três elementos: uma base para ser fixada na parede, um elemento pivot e a câmera.
Estamos interessados em fazer a câmera girar em torno do SEU eixo vertical, ou seja, em torno do seu eixo vertical LOCAL.
No universo virtual do Unity, o eixo vertical GLOBAL é o eixo y, mas cada objeto pode ter seu próprio sistema de referência LOCAL. No caso do modelo 3D da câmera de vigilância, esse é o eixo Z LOCAL, como podemos ver ao alternar para o modo de exibição LOCAL no editor do Unity.

Essa distinção introduz uma leve complexidade no nosso projeto. Precisaremos calcular o ângulo de rotação no plano global da cena, utilizando as coordenadas X e Z dos objetos, e depois realizar a rotação em torno do eixo vertical local do asset.
Primeiro, criamos uma referência ao objeto a ser seguido, criando uma variável Transform chamada objectA, que associaremos ao Player no Inspector.
[SerializeField] private Transform objectA;

Feito isso, podemos ir diretamente para Update para implementar a solução discutida anteriormente. Lembro que o eixo vertical LOCAL da câmera é o seu eixo Z.
Precisamos de apenas três linhas de código.
Na primeira, calcularemos o ângulo que separa a orientação atual da câmera daquela que ela deveria ter, para apontar para o objeto.
Na segunda, calcularemos a quantidade de rotação a ser realizada em torno do eixo Z local da câmera para alcançar a orientação desejada.
Na terceira, realizaremos a rotação efetiva com o método Rotate, ao qual precisaremos fornecer dois parâmetros: o vetor vertical local e a quantidade de rotação a ser realizada em torno desse vetor.
Vamos começar calculando o ângulo entre a orientação da Surveillance Camera e aquela que ela deveria ter, usando a função Atan2 de Mathf, que retorna um valor em radianos que converteremos para graus.
Vimos que, no plano 2D, Atan2 recebe dois parâmetros: a diferença entre as coordenadas Y e a diferença entre as coordenadas X dos dois pontos, alvo e observador, nessa ordem.
No nosso cenário, com o sistema de coordenadas global do Unity, onde X e Z estão no plano 2D enquanto o Y GLOBAL identifica o eixo vertical da cena, precisaremos escrever:
float theta = Mathf.Atan2((objectA.transform.position.x - transform.position.x), (objectA.transform.position.z - transform.position.z)) * Mathf.Rad2Deg;
Feito isso, podemos passar para a segunda instrução, o cálculo da rotação a ser realizada, em graus, que pode ser feito facilmente com:
float deltaAngle = Mathf.DeltaAngle(transform.eulerAngles.z, theta);
onde transform.eulerAngles.z representa a orientação atual da câmera de vigilância, enquanto theta representa a orientação, calculada na etapa anterior, que ela deve assumir.
A terceira e última instrução nos permite girar a Surveillance Camera:
transform.Rotate(Vector3.forward, deltaAngle);
Observe que usei Vector3.forward, que identifica o eixo Z LOCAL do objeto, como vetor em torno do qual realizar a rotação. Isso ocorre porque, no caso específico desse modelo 3D, o eixo Z LOCAL não é o que indica frente e trás, mas sim o eixo vertical local do objeto.
Salve o script, volte ao editor do Unity e pressione Play para avaliar o resultado final.
NOTA. Se você perceber que a Surveillance Camera não está apontando para o alvo, verifique se os valores iniciais de XYZ Rotation da Surveillance Camera estão definidos como 0 no Inspector e tente novamente.


Recapitulando, nesta primeira parte analisamos o problema a ser resolvido e vimos como considerar os dois objetos no mesmo plano, como calcular o vetor direção e, principalmente, como aplicá-lo ao caso específico da Surveillance Camera, levando em conta seu sistema de referência local.
Em seguida, aplicamos uma rotação instantânea ao objeto, fazendo com que ele aponte para o Player a cada frame do jogo, utilizando a função Rotate.
Na próxima parte, veremos como calcular os quaternions de rotação e usar a função Slerp para girar o objeto de forma mais lenta e suave.