1 points par GN⁺ 2024-03-09 | 1 commentaires | Partager sur WhatsApp

Astuce d’animation avec le lissage exponentiel

  • Depuis que j’ai commencé à travailler sur des sujets liés à l’animation, j’utilise presque toujours une technique d’animation simple.
  • Cette technique est utilisée dans de nombreux contextes : rotation et déplacement de caméra, déplacement de personnages dans des jeux au tour par tour, mouvement d’éléments d’interface, lissage des variations de volume dans une bibliothèque audio, etc.
  • Cette technique n’a rien de nouveau, et vous l’avez peut-être déjà entendue ou utilisée, mais je vais en expliquer quelques exemples ainsi que les principes mathématiques.

Bouton bascule

  • Lorsqu’on crée un composant d’interface, imaginons par exemple un bouton bascule.
  • La position de l’interrupteur du bouton bascule est calculée selon l’état : max_x s’il est activé, min_x s’il est désactivé.
  • Cette méthode fonctionne bien, mais sans animation, elle manque un peu de vie.
  • L’animation n’apporte pas seulement un aspect visuel agréable, elle aide aussi l’utilisateur à comprendre ce qui se passe.
  • Au lieu de déplacer instantanément l’indicateur du bouton vers sa nouvelle position, on le fait se déplacer en douceur.
  • Il faut maintenant mettre à jour l’animation, avec l’inconvénient qu’elle semble se déplacer à vitesse constante.
  • On peut y ajouter une fonction d’easing, par exemple 3t^2-2t^3 ou sqrt(t).
  • Les différences entre ces fonctions d’easing se voient mieux lorsqu’on lit l’animation au ralenti.
  • Désormais, au lieu de simplement mettre à jour la position du switch, il faut suivre l’état de l’animation.
  • Avec sqrt, il faut explicitement utiliser une fonction d’easing différente selon la direction de l’animation.
  • La question de savoir ce qui rend le mieux relève des goûts personnels, mais sqrt me paraît le plus réussi. Le mouvement démarre très vite, puis ralentit bien à l’approche de la destination.
  • L’inconvénient de cette version est qu’elle demande une quantité notable de gestion même dans le cas le plus simple, et si l’utilisateur clique au milieu de l’animation, une discontinuité provoque un saut brusque.

Déplacement de caméra

  • Imaginons une situation où la carte et la caméra défilent ou se déplacent dans l’espace.
  • Ici aussi, il est utile d’ajouter de l’animation.
  • Un code d’interpolation à vitesse constante est présenté.
  • Le tremblement qui apparaît une fois l’animation terminée vient du fait que target.x - position.x alterne entre des valeurs positives et négatives.
  • Au lieu de sign(delta), il faut une fonction qui borne le delta.
  • Cette méthode est assez compliquée pour quelque chose de simple.
  • Quand la vitesse de l’animation dépasse le temps nécessaire à son achèvement, le résultat paraît étrange.
  • On pourrait aussi ignorer l’entrée utilisateur tant que l’animation est active, mais cela produit une expérience très frustrante.
  • La solution parfaite, bien sûr, c’est le lissage exponentiel.
  • Le code change à peine par rapport à l’exemple du bouton bascule.

Fonctionnement interne

  • L’article explique ce qu’est 1 - exp(- speed * dt) et comment cela fonctionne.
  • On commence par une version simple : rendre la vitesse de déplacement proportionnelle à la distance entre la position actuelle et la nouvelle position target, afin d’accélérer le mouvement.
  • Cette méthode n’a besoin de conserver aucun état autre que la position actuelle et la position cible, et elle s’ajuste automatiquement même si target change soudainement.
  • Il y a toutefois un petit problème : si speed * dt est supérieur à 1, la position dépasse la cible.
  • Pour corriger cela, on peut borner la valeur à 1.
  • Si speed * dt est trop grand, c’est soit parce que la valeur de speed est trop élevée, soit parce que dt est trop grand.
  • Dans le cas d’une animation, il serait préférable que tout fonctionne parfaitement dès qu’on applique dt.

Équation différentielle (oh non)

  • Une approche en deux étapes est proposée pour résoudre le problème.
  • Le fait que position += (target - position) * speed * dt fonctionne pour de petits dt mais échoue pour de grands dt est un problème typique des méthodes numériques de résolution des équations différentielles.
  • L’article examine ce que résout réellement cette équation.
  • Il explique que position += (target - position) * (1 - exp(- speed * dt)) est la formule correcte pour toutes les valeurs de dt.

Choisir la vitesse

  • On pense généralement l’animation en termes de durée.
  • Avec la formule exponentielle, l’animation n’est techniquement jamais complètement terminée.
  • Le paramètre speed signifie que 1 / speed est le temps nécessaire pour que position se rapproche de target d’un facteur e = 2.71828....

Lissage exponentiel

  • Si l’on cherche « lissage exponentiel », on peut tomber sur une page wiki qui semble totalement sans rapport, mais qui contient en réalité une formule très proche de celle discutée dans ce billet.
  • Si dt est toujours identique et que target change à chaque itération, on peut indexer les valeurs par numéro d’itération et calculer quelque chose comme position[i] = (target[i] - position[i - 1]) * factor.

Titre du dernier paragraphe

  • J’avais cette idée de billet depuis plusieurs mois, et je suis heureux de l’avoir enfin terminé.
  • Merci d’avoir regardé et lu le journal de développement.

Avis de GN⁺

  • Cet article explique la technique du lissage exponentiel utilisée pour rendre les animations plus fluides et plus naturelles. Elle contribue à améliorer l’expérience utilisateur et à rendre les interfaces plus intuitives.
  • Le lissage exponentiel peut aussi être utile pour simuler des mouvements physiques, par exemple en développement de jeux pour rendre plus naturels les déplacements de personnages ou de caméra.
  • Cette technique est particulièrement efficace quand des éléments d’interface changent d’état et qu’il faut représenter visuellement cette transition. Par exemple, elle permet de rendre le mouvement d’un curseur ou d’un interrupteur plus fluide.
  • D’un point de vue critique, le lissage exponentiel peut rendre difficile le contrôle précis de la vitesse et de la durée d’une animation. Cela peut être une limite lorsqu’un designer veut ajuster finement un effet d’animation particulier.
  • Parmi les autres bibliothèques ou frameworks offrant des fonctions similaires, on peut citer GreenSock Animation Platform (GSAP) ou anime.js, qui proposent un contrôle plus fin de l’animation avec diverses fonctions d’easing.
  • Lorsqu’on adopte la technique du lissage exponentiel, il faut trouver un équilibre entre le naturel de l’animation et la précision du contrôle. Son principal avantage est l’amélioration de l’expérience utilisateur ; son inconvénient est que le réglage fin du timing de l’animation peut devenir plus difficile.

1 commentaires

 
GN⁺ 2024-03-09
Commentaires Hacker News
  • Résumé du premier commentaire :

    • Cette méthode est présentée comme une approche sans état (stateless) qui gère de façon cohérente des entrées variées, et non comme une simple courbe d’easing ou une fonction smoothstep().
    • Si l’on a déjà utilisé des transitions CSS, on peut comprendre le problème que cette technique résout.
    • Le lissage exponentiel (exponential smoothing) pose le problème d’approcher la destination sans jamais vraiment l’atteindre.
    • Lors de l’utilisation d’une méthode similaire pour le défilement inertiel (inertial scrolling), il a été jugé utile d’ajouter un terme de frottement (artificiel).
  • Résumé du deuxième commentaire :

    • En tant que développeur de jeux, l’auteur préfère, dans la plupart des cas d’interface, des tweens avec easing et durée prédéfinie.
    • En revanche, cette technique est très utile pour lisser des mouvements continus et imprévisibles, dont le point de départ et d’arrivée n’est pas clairement défini.
    • Le lerp exponentiel est utile mais peu connu, et certains jeux souffrent de problèmes d’animation parce qu’ils utilisent à la place une interpolation linéaire moins précise.
    • Pour ces raisons, le commentaire remercie l’article, car ce type de connaissance spécifique est souvent difficile d’accès.
  • Résumé du troisième commentaire :

    • Le commentaire exprime son désaccord avec l’affirmation de l’auteur selon laquelle la racine carrée (sqrt) serait meilleure qu’une courbe cubique pour un interrupteur à bascule.
    • En considérant le fonctionnement réel d’un interrupteur à bascule, il soutient qu’une fonction cubique est plus appropriée.
    • Il estime que l’article montre bien comment l’animation peut améliorer l’expérience utilisateur.
  • Résumé du quatrième commentaire :

    • Le commentaire admire ces astuces non linéaires simples qui ajoutent du plaisir aux interactions en ligne.
    • Il mentionne qu’elles jouent un rôle important dans la perception des couleurs et que les gens ne comprennent pas toujours naturellement l’accélération.
  • Résumé du cinquième commentaire :

    • Le commentaire dit avoir aimé l’article et mentionne avoir décrit la même technique il y a presque dix ans sous le nom de « lazy-easy ».
    • Il indique continuer à utiliser cette technique lorsqu’il veut des animations fluides sans gestion d’état.
  • Résumé du sixième commentaire :

    • Le commentaire note que les articles sur l’easing semblent devoir être redécouverts à chaque génération.
    • Il se souvient que les sites web expérimentaux de Yugo Nakamura, à la fin des années 1990, comptaient parmi les premiers exemples à utiliser librement l’easing pour produire une sensation organique.
  • Résumé du septième commentaire :

    • Le commentaire propose l’idée d’un bouton bascule qui se déplacerait lentement tant que l’on maintient le toucher ou le clic, puis se verrouillerait rapidement une fois relâché.
    • Il n’est pas certain de la signification UX d’un tel comportement, mais pense que cela pourrait indiquer le moment où un réglage est appliqué ou enregistré.
  • Résumé du huitième commentaire :

    • Le commentaire estime que cette technique est utile pour bien d’autres usages que les interrupteurs.
    • Il mentionne une démo liée à Flickity et souligne que cette technique n’incluait pas plusieurs optimisations nécessaires à une mise en production.
    • Il critique les personnes dans les commentaires en disant qu’elles n’ont pas bien lu l’article ou qu’elles passent à côté de points importants.
  • Résumé du neuvième commentaire :

    • Le commentaire évalue l’article positivement, mais signale que si la démo fonctionne bien dans Chrome, la page se bloque dans Firefox.
  • Résumé du dixième commentaire :

    • Le commentaire estime que les petites animations racontent énormément de choses et représentent la meilleure forme de design émotionnel.