Neste tutorial, vamos estudar a função Slerp da classe Quaternion no Unity, que nos permite fazer a transição de uma orientação inicial para uma orientação final ao longo de um período de tempo especificado, realizando rotações suaves.
A versão em vídeo deste tutorial não está disponível atualmente neste idioma.
Transcrição do vídeo
Olá a todos!
Neste tutorial, vamos estudar a função Slerp da classe Quaternion no Unity, que nos permite fazer a transição de uma orientação inicial para uma orientação final ao longo de um período de tempo especificado, realizando rotações suaves.
Neste tutorial, vou assumir que você já está familiarizado com Time.deltaTime, que abordei em um vídeo tutorial publicado anteriormente. Caso você ainda não conheça Time.deltaTime, recomendo fortemente assistir a esse vídeo antes de continuar com este.
Este tutorial foi gravado utilizando o Unity 2022. No entanto, a função Slerp já está disponível em várias versões e provavelmente continuará disponível nas próximas versões.
Uma rotação da orientação A para a orientação B, e de forma mais geral uma interpolação entre o valor A e o valor B ao longo de um período de tempo especificado, pode acontecer de diferentes maneiras: os valores podem seguir uma progressão linear, uma progressão esférica ou outros tipos de progressões, incluindo progressões personalizadas.
No vídeo, estou mostrando alguns exemplos de interpolação, especificamente a rotação de um cubo em 90 graus em torno do seu eixo vertical. É um exemplo simples, mas transmite o conceito de forma eficaz.
O tempo de rotação é mapeado dentro do intervalo [0,1], em que no instante 0 temos o valor inicial e no instante 1 temos o valor final. Os valores intermediários dentro do intervalo correspondem aos valores fornecidos pela interpolação escolhida.
Nos exemplos, todos os cubos giram 90 graus em 5 segundos. No entanto, no quarto segundo da animação, que corresponde ao momento 0.8 no intervalo [0, 1], os diferentes cubos terão orientações distintas porque suas interpolações são diferentes.

Ao realizar rotações, como no nosso caso, a interpolação esférica é preferível à interpolação linear porque o resultado é mais agradável visualmente.
No Unity, a interpolação esférica é calculada usando a função Slerp, em que o S inicial significa Spherical, enquanto a interpolação linear é calculada usando a função Lerp, em que o L inicial significa Linear.
Como mencionado anteriormente, Slerp faz parte da classe Quaternion, que permite especificar orientações e rotações no espaço 3D usando quaternions, um conceito matemático que NÃO explicarei neste tutorial.
Vou me limitar a dizer que eles são usados para expressar orientações e espero que os matemáticos me perdoem por essa simplificação, e mostrar como utilizar a função Slerp.
Slerp é usada para fazer a transição da orientação A para a orientação B.
Ela recebe três parâmetros: a orientação inicial, a orientação de destino e o momento dentro do intervalo [0, 1] no qual queremos conhecer a orientação, ou seja, o instante em que queremos avaliar a interpolação.
Slerp retorna um quaternion que representa a orientação avaliada no instante especificado.
Portanto, quando escrevemos:
Quaternion.Slerp(A, B, 0.2);
estamos pedindo ao Unity que obtenha a orientação que o objeto deve ter em um quinto da rotação necessária para passar da orientação A para a orientação B, já que 0.2 corresponde a um quinto de 1.
Se quisermos que a animação dure 1 segundo, podemos usar Time.deltaTime no método Update, porque o intervalo de interpolação de 0 a 1 pode ser perfeitamente convertido em uma animação de um segundo usando Time.deltaTime em Update, como mostrei no vídeo tutorial sobre Time.deltaTime.
Por outro lado, para realizar a animação ao longo de um número arbitrário de segundos, devemos dividir Time.deltaTime por essa quantidade. Vou explicar isso com mais detalhes em breve por meio de um exemplo prático.
Na maioria das vezes, a orientação inicial é a orientação do objeto, ou seja, transform.rotation, já que a rotação é expressa em quaternions.
Calcular a orientação de destino, por exemplo adicionando um ângulo em graus à orientação inicial, pode ser problemático. No entanto, também veremos isso em breve no exemplo prático. Bem, vamos finalmente para um exemplo prático!
No vídeo, estou mostrando uma cena com um modelo 3D.

Especificamente, o modelo é composto por 4 elementos: o batente da porta, as duas folhas da porta e uma maçaneta.
Embora o pivot da folha da porta com a maçaneta estivesse inicialmente localizado nas dobradiças no meu modelo original, permitindo que a rotação acontecesse corretamente, por algum motivo o Unity o deslocou um pouco para frente.
Para resolver esse problema, adiciono um Empty como filho do batente e o posiciono em uma das dobradiças da folha da porta que quero animar.
Em seguida, torno a folha da porta filha desse Empty.
Esse novo Empty precisará de um script de rotação, que vamos criar imediatamente, chamando-o por exemplo de "doorOpening".
Em particular, queremos que a folha da porta se abra automaticamente no início do jogo, girando 90 graus em torno do seu eixo vertical LOCAL, que neste caso é o eixo Z.

A orientação inicial é dada por transform.rotation.
Por conveniência, e para tornar o código mais flexível, também declaro uma variável do tipo Quaternion chamada startRotation e a inicializo no método Start com:
startRotation = transform.rotation;
O quaternion que representa a orientação final deve ser igual à orientação inicial mais uma rotação de 90 graus em torno do eixo Z local. Mas como definimos essa rotação em Quaternions?
A função Quaternion.Euler nos ajuda, pois recebe três parâmetros: os ângulos de rotação em graus em torno dos três eixos XYZ.
Então definimos o quaternion da rotação a ser realizada como:
Quaternion rotationToBePerformed;
e o inicializamos no método Start com:
rotationToBePerformed = Quaternion.Euler(0f, 0f, 90f);
Esse quaternion representa a operação a ser realizada, mas ainda não é a orientação final.
Precisamos calculá-la somando esse valor à orientação inicial.
E aqui está a parte mais delicada: para adicionar a rotação a ser realizada à orientação inicial, os dois quaternions devem ser MULTIPLICADOS entre si.
Então definimos o quaternion final como:
Quaternion targetRotation;
e o inicializamos no método Start com:
targetRotation = startRotation * rotationToBePerformed;
Vamos agora para o método Update, que é executado a cada frame do jogo, e começamos a escrever:
transform.rotation = Quaternion.Slerp(startRotation, targetRotation
e paramos aqui porque ainda não definimos uma variável para o tempo de avaliação da interpolação.
Essa variável deve começar em 0, então podemos defini-la e inicializá-la fora do Update com:
float evaluation = 0f;
em seguida, podemos utilizá-la como o terceiro parâmetro da função Quaternion.Slerp.
Além disso, como seu valor deve aumentar a cada frame, escrevemos no método Update:
evaluation += Time.deltaTime;

Sabemos que o tempo final de avaliação da rotação será 1.0, então essa animação durará exatamente um segundo, já que estamos incrementando evaluation com Time.deltaTime a cada frame.
Agora, ao iniciar o jogo, vamos perceber que o Empty gira em torno do seu eixo vertical, mas a folha da porta não se abre.
Isso acontece porque inicialmente eu havia marcado esse objeto como Static, já que não esperava animá-lo e queria que o Unity calculasse a iluminação global. No entanto, agora quero animá-lo, então desmarco a opção Static no Inspector e confirmo a operação para os objetos filhos, como a maçaneta.
Iniciando o jogo novamente, desta vez veremos a porta abrindo com interpolação suave em um segundo.

Como podemos agora definir uma duração diferente para a animação?
A resposta é bastante simples: o incremento de evaluation a cada frame deve ser igual a Time.deltaTime dividido pela duração da animação.
Usando apenas Time.deltaTime, a animação dura um segundo. Portanto, para fazer a animação durar, por exemplo, 5 segundos, precisamos aumentar evaluation em um quinto de Time.deltaTime a cada frame.
Então vamos definir uma variável:
float openingDuration = 5f;
porque queremos que a animação dure 5 segundos. Em seguida, atualizamos a instrução referente a evaluation no método Update da seguinte forma:
evaluation += (Time.deltaTime / openingDuration);

Salve o script, volte ao editor do Unity e inicie o jogo para observar o resultado. Desta vez, a animação será executada em 5 segundos.
Com este exemplo prático, você pode ver como usar Quaternion.Slerp para interpolar suavemente entre duas orientações em uma duração específica.
Você pode adaptar esse script para diferentes cenários ou objetos a fim de obter rotações e animações suaves nos seus projetos no Unity.
Resumindo, neste tutorial vimos como expressar a rotação a ser realizada em quaternions; como obter o quaternion de destino, que é dado pelo quaternion inicial multiplicado pela rotação a ser realizada; como usar a função Slerp para realizar rotações com interpolação esférica, com durações variáveis e velocidade de execução constante, independentemente da taxa de quadros, graças ao Time.deltaTime.
Espero que este tutorial tenha sido útil para você. Até a próxima!