Mastodon
Le 1er site en français consacré à l'histoire des jeux vidéo
L'animation pour les nuls
Un petit cours sur l'animation dans le domaine du jeu vidéo qui devrait répondre aux questions que vous vous posez le plus fréquemment à ce sujet.

Les saccades, c'est bien

Pendant ce temps-là, sur micro (enfin, principalement sur PC), les bons programmeurs se sont rendus compte que faire quelque chose comme ça est tout simplement ingérable si l'on veut obtenir un jeu qui tourne comme on le veut sur 30 processeurs, 500 modèles de moniteurs à 12 fréquences de rafraîchissement différentes. Alors, ils ont trouvé une solution simple et élégante : comme tout microprocesseur qui se respecte est capable de mesurer le temps réel, ils codent les vitesses dans leurs programmes en fonction du temps réel et non en fonction des images. Lorsqu'il faut mettre à jour une image, on calcule le temps écoulé depuis la dernière mise à jour, et on en déduit une variation en pixels. L'ordinateur affiche le nombre d'images par seconde qu'il peut, et ce nombre peut être variable sans que ça ait d'effets adverses autres que donner au joueur envie d'acheter une nouvelle carte vidéo.

Par exemple, sur PC, "Le tir de l'arme principale avance de 60 pixels par seconde" :

  • Le PC 1 est capable de fournir 30 images par seconde. A la première image (t = 0), le tir de l'arme principale est à x = 0 pixels. A la deuxième image (soit t = 1/30 s), il est à x = 2 pixels (0 + 60*1/30).
  • Le PC 2 est plus puissant, il tourne à 60 images par seconde. A la première image (t = 0), le tir est à x = 0 pixels. A la deuxième (t = 1/60 s), il est à x = 1 pixel (0 + 60*1/60). A la 3e image (t = 1/30 s), il est à x = 2 pixels (1 + 60*1/60).

Le jeu est plus fluide sur le PC 2, mais il tourne exactement à la même vitesse sur les deux machines : c'est gagné ! L'inconvénient de cette méthode, c'est que lorsque le jeu dépasse les capacités de la machine, il saccade au lieu de ralentir -- ce qui fatigue les yeux plus vite que le ralenti. Les avantages sont tout d'abord que même les très vieux jeux, s'ils ont été programmés correctement, continuent à tourner comme il faut sur les bécanes modernes (c'est par exemple le cas de Prehistorik 2 et des Aventures de Moktar, qui poussent le vice jusqu'à vous accueillir avec un petit "Ce jeu marche toujours en 2005, il a été programmé en 1992 sur un AT à 12 MHz, enjoy oldies !"), et ensuite que le jeu en réseau est rendu possible pour des joueurs dont les configs ne sont pas identiques. En effet, si les jeux utilisaient les frames au lieu d'un timer, il faudrait que tout le monde ralentisse chaque fois qu'une des machines a du mal à suivre (pour ne pas désynchroniser le réseau).

Les limites de l'animation 2D

Il faut que je vous avoue quelque chose. Depuis tout à l'heure je vous fais mon laïus comme quoi le framerate fait tout, que s'il est élevé votre jeu sera fluide un point c'est tout, et... En fait je vous ai menti. Oui, je sais, je n'en suis pas fier. Mais c'était parce que je voulais vous éviter le plus possible de considérer le facteur humain.

numPersos*numActions*60 == myGraphiste.suicide()

Imaginez que vous êtes en train de programmer un jeu 2D. Comme vous avez lu au moins jusqu'ici, vous avez décidé de viser un framerate de 60 images par seconde pour avoir un beau jeu bien fluide. Donc tout va tourner à 60 FPS. Votre personnage principal marchera à 60 FPS, les ennemis aussi, le décor s'animera à 60 FPS... Vous avez entendu le coup de feu, là ? C'était votre graphiste. Le type que vous veniez de charger de dessiner 60 images (des sprites, dans le jargon) pour l'animation du personnage principal en train de faire un pas (un pas par seconde, c'est une vitesse de marche raisonnable). Et puis 60 autres parce qu'il a deux pieds (il aurait l'air ridicule à toujours avancer le même, non ?). Et puis 240 au total parce que vous voulez qu'il ait son pistolet dans la main droite quelle que soit la direction dans laquelle il avance. N'oublions pas, aussi, 120 ou 240 images pour chaque type d'ennemi en train de marcher. Oh, et puis ils peuvent courir, aussi...

Et l'explosion, là, c'est le moyen qu'a trouvé votre machine pour vous dire qu'elle n'avait pas assez de RAM pour stocker tout ça en même temps. Parce que si vos voulez utiliser toutes ces animations, il faut qu'elles soient toutes en RAM simultanément. Alors, si vous développez sur PC ou sur une console moderne, le problème est assez lointain. Mais ici, vous êtes sur Grospixels, et sur Grospixels on est retro jusqu'au bout : vous êtes donc en train de développer un jeu sur Amiga ou Super Nintendo (respectivement 512 ou 64 Ko de RAM). C'est la dèche. En plus, votre graphiste est mort, mais l'esprit du champignon vert à pois blancs le ressuscite et vous accorde une seconde chance. Mais comment trouver un moyen de réduire sa charge de travail, ainsi que l'occupation mémoire des données graphiques, sans que la fluidité du jeu en prenne un gros coup ? De toute évidence, diminuer le framerate cible serait mal parce que tout serait affecté... Mais

d'un autre côté, ce serait quand même bien pratique. La solution est simple :

Faire semblant !

Certains effets profitent automatiquement d'un framerate plus élevé sans demander de ressources supplémentaires : les scrollings, par exemple. Pour en profiter sans avoir à augmenter le niveau de détail de toutes les animations qui, elles, demandent des ressources (humaines et machine) supplémentaires, il suffit de se rappeler comment le framerate d'un jeu peut être inférieur à la fréquence de rafraîchissement de l'écran sur lequel il est affiché. C'est à dire que si un sprite est animé à 30 images par seconde, afficher chaque image pendant deux frames au lieu d'une seule permet de réutiliser l'animation telle quelle dans un jeu à 60 FPS. Le tour est joué ! Bien sûr, rien n'oblige à tout animer à la même vitesse. Dans le cas d'un shoot 'em où le personnage principal est un vaisseau, il est tout à fait possible de ne pas animer celui-ci du tout. Après tout, le Vic Viper ne se déforme pas quand il vole en palier : une petite animation pour la flamme derrière, et à dégager, le sprite du vaisseau, lui, reste identique.

Animation et niveau de détail : le cas Bren McGuire

Reste à savoir comment ces coupes budgétaires affectent l'apparence du jeu. Il n'y a pas de secret : moins une animation est détaillée, moins elle paraît fluide, et ce indépendamment du framerate du jeu dans lequel elle est utilisée. Une petite animation valant mieux qu'un long discours, prenons l'exemple d'un petit monsieur en armure de combat bleue et grise qui veut casser toutes ses dents à La Machine : Bren McGuire, héros des cultissimes Turrican sur Amiga. Ce qu'il y a de bien avec Bren, c'est que ses aventures ont été converties sur plein de supports, et qu'ils n'ont pas tous été aussi bien dotés par Dame Nature que la machine du regretté Jay Miner.

A ma gauche, Turrican 2 sur Amiga, représentant le plus célèbre de la série, et clairement l'un des jeux emblématiques de la machine.
Le jeu tourne à 50 FPS (60 chez les vils Américains, mais c'est avant tout un produit européen), et les 512 kilo-octets de RAM qui équipent l'Amiga dans sa version de base permettent de ne pas rogner trop fort sur les niveaux de détails.
Donc quand Bren marche, il le fait à 50 images par seconde. Le résultat est une démarche fluide et agréable à l'oeil.

A ma droite, Super Turrican sur Super Nintendo. Pas le même jeu, mais une parenté indéniable (surtout dans le premier niveau), et la même animation pour le père McGuire, à un détail près. Les différences techniques entre la SNES et l'Amiga ont été la source d'innombrables débats et dissertations, mais celle qui nous intéresse aujourd'hui est la suivante : la machine de Nintendo ne dispose que de 64 malheureux kilo-octets de RAM. 4 fois moins que l'Amiga, et on s'y sent tout de suite plus à l'étroit. De ce fait, si Super Turrican tourne lui aussi à 60 FPS (50 chez ces chiens galeux d'Européens), Bren McGuire n'y est plus animé qu'à une quinzaine d'images par seconde. L'animation est rigoureusement identique à celle de Turrican 2, sauf que seule une image sur quatre a été gardée.

La comparaison est sans appel : la démarche de Super-Bren est beaucoup plus saccadée et en fait très quelconque (sur consoles 16-bits hors Neo Geo, très peu de personnages sont animés en plus de 15 images par seconde), là où celle d'Ami-Guire était souvent signalée parmi les principaux attraits du jeu.

Et avec des timers, ça donne quoi ?

Depuis tout à l'heure, je vous parle de réduction de détails en affichant chaque étape d'animation pendant plusieurs images. Je raisonne en basant mon échelle de temps sur les frames, ce qui, vous le savez désormais, est mal. Evidemment, c'était pour la bonne cause : simplifier les choses afin de faciliter leur compréhension. Mais maintenant que vous avez saisi le truc, vous aimeriez bien connaître la manière correcte de faire ça. Ce n'est pas très compliqué. Soit une animation de 30 images censée se dérouler en une seconde. Cela signifie qu'indépendamment du framerate du jeu, chacune de ces images doit être utilisée pendant 1/30 seconde. Il suffit donc de connaître où l'on se trouve dans la seconde pour savoir quelle image afficher. Autrement dit (quelques lignes de pseudo-code valent mieux qu'un long discours) :

si 0 <= t < 1/30:
utiliser image 1
si 1/30 <= t < 2/30:
utiliser image 2
si 2/30 <= t < 3/30:
utiliser image 3
[...]
si 29/30 <= t < 30/30:
utiliser image 30

Et le tour est joué ! Rien de bien sorcier, si ?

Et en 3D, c'est différent ?

Ah... 2D contre 3D. L'éternel débat dans lequel tout retrogamer s'est à un moment ou à un autre retrouvé engagé. L'esthétique, l'immersion, le pixel art, le réalisme... De quoi argumenter sans fin, et il y en a qui le font. Sauf qu'ici, on est dans un article technique, et toutes ces considérations émotionnelles purement subjectives, on s'en balance. Et en matière d'animation, la 3D, c'est drôlement plus pratique que la 2D classique. En effet, les problèmes mentionnés dans la section précédente ne s'appliquent pas. Dans un jeu 3D bien programmé (avec des timers, bla bla bla, vous connaissez la rengaine), toute augmentation du framerate se répercute immédiatement et automatiquement sur la fluidité de toutes les animations, sans exception, et sans que ni les programmeurs ni les animateurs n'aient à faire d'efforts. Sacrée différence, hein ? Voyons un peu d'où elle vient.

Bitmap VS vecteurs

En graphisme 2D classique, une image est composée de pixels. Une feuille quadrillée dont on a noirci certains carreaux pour dessiner quelque chose. C'est tout ce que le programme sait de l'image, et du coup il ne peut pas en extrapoler grand-chose. En 3D, par contre (ainsi qu'en 2D dite vectorielle : la Vectrex, pas mal de jeux en Flash...), on travaille avec des vecteurs. C'est à dire qu'au lieu de colorier les pixels individuellement, on décrit la scène sous forme de figures géométriques. On dit au programme qu'il y a par exemple une ligne droite entre les points de coordonnées (0, 1, 5) et (0, 0, 2), et il se charge tout seul de calculer quels pixels noircir pour la tracer. Dans le cas d'un solide tel qu'un disque ou un rectangle, le moteur 3D est même capable d'en remplir la surface tout seul si on lui demande, soit avec une couleur fixe, soit avec une image bitmap (une texture). La majorité des scènes 3D que vous voyez dans les jeux sont composées entièrement de triangles et de quadrilatères.

Modèles 3D et squelettes

L'équivalent tridimensionnel d'un sprite, autrement dit, la représentation graphique d'un objet, s'appelle un modèle 3D. C'est une collection de coordonnées que le moteur 3D utilise pour dessiner des triangles et des quadrilatères, appliquer des textures dessus, et le résultat peut être une caisse en bois, Solid Snake, le Master Chief ou même Lara Croft. En modifiant un peu ces coordonnées, on obtient le même objet avec une forme légèrement différente. Quand l'objet est un personnage et les modifications opérées avec suffisamment de ruse, on obtient le même personnage dans une position différente (avec les bras tendus au-dessus de la tête pour danser le YMCA, par exemple). Donc si l'on enregistre quelque part ces coordonnées modifiées puis que l'on affiche les différentes versions à la même position l'une après l'autre, on obtient une animation. Ceci dit, la plupart du temps, ces modifications de coordonnées se font plus ou moins automatiquement. En effet, en même temps que l'artiste crée son modèle 3D, il définit également un squelette pour le personnage, composé de beaucoup moins de points (en gros, un point par articulation). Il se contente ensuite de modifier la position du squelette, et le logiciel d'animation (ou plus récemment, le jeu lui-même) en déduit tout seul l'agencement des polygones du corps autour de celui-ci.

Interpolation : quand la machine anime toute seule

Considérez l'image suivante :

Une bête ligne, donc. Imaginez que c'est un bout du squelette d'un personnage. Elle est entièrement définie par ses deux extrémités, le reste est dessiné automatiquement par le programme.

On veut la faire bouger ainsi :

La position de départ est en bleu, celle d'arrivée en rouge. L'extrémité du bas ne bouge pas, et celle du haut suit la ligne pointillée verte. En animation traditionnelle, il faudrait dessiner à la main toutes les positions intermédiaires. Mais ici, il suffit de préciser au programme la position de départ, celle d'arrivée et la durée de l'animation. Les phases de l'animation sont entièrement définies par les positions des deux extrémités de la ligne, et comme vous pouvez le voir sur le dessin, il est très facile de calculer automatiquement le mouvement de l'extrémité supérieure pendant l'animation.

Justement, le programme s'en charge tout seul : cela s'appelle l'interpolation. Comme la durée spécifiée est temporelle (et non un nombre d'images), le framerate n'a pas d'importance particulière lors de la création de l'animation. Cependant, à l'exécution, plus elle sera élevée, plus l'animation aura d'étapes intermédiaires et paraîtra donc fluide. Bien entendu, dans un vrai jeu en 3D, aucune scène n'est jamais aussi simple (ou alors c'est que vous donnez dans les jeux vraiment, mais alors vraiment retro). Mais ce qu'il s'y passe n'est qu'une version plus détaillée du mécanisme que je viens de vous décrire. Les modèles de personnages font plusieurs milliers de polygones, et leurs squelettes ont une centaine d'articulations. Mais leur animation est toujours réalisée par la machine qui interpole entre diverses positions "clés" du mouvement. Pour plus de réalisme, il arrive souvent que lesdites positions-clés soient modélisées à partir d'un acteur (motion capture) : il exécute le mouvement réel, et un ordinateur l'enregistre grâce à des capteurs posés sur son corps. Plus qu'à appliquer le résultat au modèle de personnage pour que celui-ci bouge comme l'acteur.

Conclusion

Félicitations, vous êtes arrivé à la fin de cet article. De deux choses l'une :

- Vous êtes tombé dans un profond coma il y a une demi-heure. Votre arrivée à ce niveau du texte est entièrement due à des spasmes incontrôlés de votre majeur droit sur la roulette de votre souris. Si personne n'entend les SOS en morse que vous cliquez convulsivement sur le bouton gauche, vous mourrez de déshydratation dans quelques jours.
- Vous saisissez désormais les bases de l'animation vidéoludique, et vous ne vous êtes pas trop ennuyé pendant mes (longues, je le reconnais) explications. En bonus, vous tenez peut-être même les réponses aux questions que vous vous posiez au début de l'article, ainsi qu'à quelques autres apparues en cours de route.

Je vous avoue espérer que la seconde hypothèse est la bonne. Quoi qu'il en soit, s'il vous reste des questions, n'hésitez pas à venir les poser sur le forum. Je me ferai un plaisir d'y répondre si je peux, et sinon je suis sûr que plein d'autres gens pourrons nous rejoindre dans nos suppositions fumeuses sur le fonctionnement du mécanisme de votre choix.

Wild_Cat
(20 février 2006)
Sources, remerciements, liens supplémentaires :
Merci au site Amiga Chapter One pour les gifs animés de sprites Amiga
Page 2 sur 2
>>>