Dans ce tutoriel, nous allons étudier la fonction Slerp de Quaternion dans Unity, qui nous permet de passer d’une orientation initiale à une orientation finale sur une période de temps spécifiée, en effectuant des rotations fluides.


La version vidéo de ce tutoriel n’est actuellement pas disponible dans cette langue.


Transcription de la vidéo

Bonjour à tous !

Dans ce tutoriel, nous allons étudier la fonction Slerp de Quaternion dans Unity, qui nous permet de passer d’une orientation initiale à une orientation finale sur une période de temps spécifiée, en effectuant des rotations fluides.

Dans ce tutoriel, je suppose que vous êtes déjà familiers avec Time.deltaTime, que j’ai abordé dans une vidéo tutorielle publiée précédemment. Si vous ne connaissez pas encore Time.deltaTime, je vous recommande vivement de regarder cette vidéo avant de continuer.

Ce tutoriel a été enregistré avec Unity 2022. Cependant, la fonction Slerp est disponible depuis plusieurs versions et continuera probablement à l’être dans les futures versions.

Une rotation de l’orientation A vers l’orientation B, et plus généralement une interpolation entre la valeur A et la valeur B sur une période donnée, peut se produire de différentes manières : les valeurs peuvent suivre une progression linéaire, une progression sphérique ou d’autres types de progressions, y compris personnalisées.

Dans la vidéo, je montre quelques exemples d’interpolation, en particulier la rotation d’un cube de 90 degrés autour de son axe vertical. C’est un exemple simple, mais il permet de comprendre efficacement le concept.

Le temps de rotation est mappé dans l’intervalle [0,1], où à l’instant 0 nous avons la valeur initiale, et à l’instant 1 nous avons la valeur finale. Les valeurs intermédiaires de l’intervalle correspondent aux valeurs données par l’interpolation choisie.

Dans les exemples, les cubes tournent tous de 90 degrés en 5 secondes. Cependant, à la quatrième seconde de l’animation, ce qui correspond au moment 0.8 dans l’intervalle [0,1], les différents cubes auront des orientations différentes parce que leurs interpolations sont différentes.

Lorsqu’on effectue des rotations, comme dans notre cas, l’interpolation sphérique est préférable à l’interpolation linéaire car le résultat est plus agréable visuellement.

Dans Unity, l’interpolation sphérique est calculée avec la fonction Slerp, la lettre S signifiant Spherical, tandis que l’interpolation linéaire est calculée avec la fonction Lerp, la lettre L signifiant Linear.

Comme mentionné précédemment, Slerp fait partie de la classe Quaternion, qui permet de spécifier des orientations et des rotations dans l’espace 3D à l’aide des quaternions, un concept mathématique que je n’expliquerai pas dans ce tutoriel.

Je me limiterai à dire qu’ils sont utilisés pour exprimer des orientations, et j’espère que les mathématiciens me pardonneront cette simplification, puis je vous montrerai comment utiliser la fonction Slerp.

Slerp est utilisée pour passer d’une orientation A à une orientation B.

Elle prend trois paramètres : l’orientation initiale, l’orientation cible et le moment dans l’intervalle [0,1] auquel nous voulons connaître l’orientation, autrement dit le moment auquel nous voulons évaluer l’interpolation.

Slerp renvoie un quaternion représentant l’orientation évaluée à l’instant spécifié.

Ainsi, lorsque nous écrivons :

Quaternion.Slerp(A, B, 0.2);

nous demandons à Unity de récupérer l’orientation que l’objet doit avoir à un cinquième de la rotation nécessaire pour passer de l’orientation A à l’orientation B, puisque 0.2 correspond à un cinquième de 1.

Si nous voulons que l’animation dure 1 seconde, nous pouvons utiliser Time.deltaTime dans Update, car l’intervalle d’interpolation de 0 à 1 peut être parfaitement converti en une animation d’une seconde en utilisant Time.deltaTime dans Update, comme je l’ai montré dans le tutoriel vidéo sur Time.deltaTime.

En revanche, pour effectuer l’animation sur un nombre arbitraire de secondes, nous devons diviser Time.deltaTime par cette valeur. Nous allons en parler plus en détail avec un exemple pratique.

La plupart du temps, l’orientation initiale est l’orientation de l’objet, c’est-à-dire transform.rotation, puisque la rotation est exprimée en quaternions.

Calculer l’orientation cible, par exemple en ajoutant un angle en degrés à l’orientation initiale, peut être problématique. Cependant, nous allons également aborder ce point dans l’exemple pratique. Passons enfin à la pratique.

Dans la vidéo, je montre une scène contenant un modèle 3D.

Plus précisément, le modèle se compose de quatre éléments : le cadre de la porte, les deux panneaux de la porte et une poignée.

Bien que le pivot du panneau avec la poignée ait été initialement positionné au niveau des charnières dans mon modèle original, ce qui permettait une rotation correcte, Unity l’a déplacé légèrement vers l’avant pour une raison quelconque.

Pour résoudre ce problème, j’ajoute un objet Empty comme enfant du cadre et je le positionne sur l’une des charnières du panneau que je souhaite animer.

Ensuite, je fais du panneau de la porte un enfant de cet Empty.

Ce nouvel objet Empty aura besoin d’un script de rotation, que nous créons immédiatement, en le nommant par exemple "doorOpening".

En particulier, nous voulons que le panneau s’ouvre automatiquement au début du jeu, en tournant de 90 degrés autour de son axe vertical LOCAL, qui dans ce cas est l’axe Z.

L’orientation initiale est donnée par transform.rotation.

Par commodité, et pour rendre le code plus flexible, je déclare également une variable de type Quaternion appelée "startRotation" et je l’initialise dans Start avec :

startRotation = transform.rotation;

Le quaternion représentant l’orientation finale doit être égal à l’orientation initiale plus une rotation de 90 degrés autour de l’axe Z local. Mais comment définir cette rotation en quaternions ?

La fonction Quaternion.Euler vient à notre aide. Elle prend trois paramètres : les angles de rotation en degrés autour des trois axes X, Y et Z.

Nous définissons donc le quaternion de la rotation à effectuer comme suit :

Quaternion rotationToBePerformed;

et nous l’initialisons dans Start avec :

rotationToBePerformed = Quaternion.Euler(0f, 0f, 90f);

Ce quaternion représente l’opération à effectuer, mais ce n’est pas encore l’orientation finale.

Nous devons la calculer en ajoutant cette valeur à l’orientation initiale.

Et voici la partie délicate : pour ajouter la rotation à effectuer à l’orientation initiale, les deux quaternions doivent être multipliés.

Nous définissons donc le quaternion final ainsi :

Quaternion targetRotation;

et nous l’initialisons dans Start avec :

targetRotation = startRotation * rotationToBePerformed;

Passons maintenant à la fonction Update, qui est appelée à chaque frame du jeu, et commençons à écrire :

transform.rotation = Quaternion.Slerp(startRotation, targetRotation

et nous nous arrêtons ici car nous n’avons pas encore défini de variable pour le temps d’évaluation de l’interpolation.

Cette variable doit commencer à 0. Nous pouvons donc la définir et l’initialiser en dehors de Update avec :

float evaluation = 0f;

Puis l’utiliser comme troisième paramètre de la fonction Quaternion.Slerp.

De plus, puisque sa valeur doit augmenter à chaque frame, nous écrivons dans Update :

evaluation += Time.deltaTime;

Nous savons que la valeur finale d’évaluation sera 1.0. Cette animation durera donc exactement une seconde, puisque nous incrémentons evaluation avec Time.deltaTime à chaque frame.

En lançant le jeu, nous remarquons que l’Empty tourne autour de son axe vertical, mais que le panneau ne s’ouvre pas.

Cela se produit parce que j’avais initialement défini cet objet comme Static, car je ne prévoyais pas de l’animer et je voulais que Unity calcule l’illumination globale. Maintenant que je veux l’animer, je décoche la case Static dans l’Inspector et je confirme l’opération pour les objets enfants, comme la poignée.

En relançant le jeu, cette fois nous verrons la porte s’ouvrir avec une interpolation fluide en une seconde.

Comment définir maintenant une durée d’animation différente ?

La réponse est simple : l’incrément de evaluation à chaque frame doit être égal à Time.deltaTime divisé par la durée de l’animation.

Avec uniquement Time.deltaTime, l’animation dure une seconde. Donc, pour faire durer l’animation, par exemple, 5 secondes, nous devons augmenter evaluation d’un cinquième de Time.deltaTime à chaque frame.

Définissons donc une variable :

float openingDuration = 5f;

car nous voulons que l’animation dure 5 secondes. Puis modifions l’instruction concernant evaluation dans la méthode Update comme suit :

evaluation += (Time.deltaTime / openingDuration);

Enregistrez le script, revenez dans l’éditeur Unity et lancez le jeu pour observer le résultat. Cette fois, l’animation sera effectuée en 5 secondes.

Avec cet exemple pratique, vous pouvez voir comment utiliser Quaternion.Slerp pour interpoler en douceur entre deux orientations sur une durée spécifique.

Vous pouvez adapter ce script à différents scénarios ou objets afin d’obtenir des rotations et des animations fluides dans vos projets Unity.

Pour résumer, dans ce tutoriel nous avons vu comment exprimer la rotation à effectuer en quaternions, comment obtenir le quaternion cible en multipliant le quaternion de départ par la rotation à effectuer, et comment utiliser la fonction Slerp pour réaliser des rotations avec interpolation sphérique, avec des durées variables et une vitesse d’exécution constante indépendamment du frame rate grâce à Time.deltaTime.

J’espère que ce tutoriel vous a été utile. À bientôt !

Ce site a pour seul objectif de présenter certains de mes travaux, sans aucune intention promotionnelle. Veuillez noter que je ne recherche actuellement - et ne répondrai pas - à aucune demande de travaux personnalisés, de conseil ou de toute autre forme de collaboration professionnelle.


POLITIQUE GENERALE DE CONFIDENTIALITE ET D'UTILISATION DES COOKIES