# Les moteurs de rendu des FPS en 2.5 D/Les généralités : le rendu 2D

Les tout premiers First Person Shooters, comme DOOM, Wolfenstein 3D, et autres jeux des années 1990 avaient un rendu relativement simpliste et anguleux. Et contrairement à ce que voient nos yeux, le rendu n'était pas toujours en 3D. Le moteur de ces jeux disposait de deux méthodes de rendu assez simples :
* un rendu purement 2D, pour le HUD, l'arme, les ennemis et les items ;
* un rendu en 2.5D ou en 3D pour les murs.
Quelques moteurs utilisaient un moteur en 3D, avec rendu d'objets en polygones, comme le moteur d'Ultima Underworld, mais ils sont plus rares. Le rendu des murs est de loin la portion la plus compliquée du moteur. Aussi, nous allons d'abord parler du reste dans ce chapitre. Cependant, nous verrons que le rendu s'effectue ne plusieurs étapes, qui se font dans un ordre différent de celui du chapitre. L'ordre de ce rendu s'explique assez facilement quand on connait comme est effectué le rendu d'un jeu en 2 pure. Et je précise bien en 2D pure, car le principe de la 2.5D est assez similaire.
La base d'un rendu en pure 2D, comme un jeu Mario, superpose des images 2D pré-calculées les unes au-dessus des autres. Par exemple, on peut avoir une image pour l’arrière-plan (le décor), une image pour le monstre qui vous fonce dessus, une image pour le dessin de votre personnage, etc. On distingue généralement l'image pour l'arrière-plan, qui prend tout l'écran, des images plus petites qu'on superpose dessus et qui sont appelées des sprites. Le rendu des sprites doit s'effectuer de l'image la plus profonde (l'arrière-plan), vers les plus proches (les sprites qui se superposent sur les autres) : on parle d'algorithme du peintre.
Dans un FPS en 2.5D, l'idée est de calculer séparément une image pour l'environnement, le décor, une image avec les ennemis, une image avec l'arme en avant-plan et une autre image sur le HUD. Le HUD est à l'avant-plan et prédomine tout le reste, ce qui fait qu'il doit être dessiné en dernier. L'arme est située juste après le HUD, elle est tenue par le personnage et se situe donc devant tout le reste : elle est dessinée en second. Pour l'environnement et les ennemis, tout dépend de la pièce dans laquelle on est et de la position des ennemis. Mais il est plus pratique de rendre le décor et de dessiner les ennemis dessus, l'environnement servant d'arrière-plan.
Le rendu s'effectue donc comme ceci :
* d'abord le rendu des murs, du plafond et du sol ;
* puis le rendu des ennemis et items ;
* puis le rendu de l'arme ;
* et enfin le rendu du HUD.

## Le rendu du HUD

Le HUD est simplement rendu en 2D, car le HUD est fondamentalement une structure en 2D. Il est mis à jour à chaque fois que le joueur tire (compteur de munitions), perd de la vie, prend de l'armure, etc. Il est idéalement rendu à la toute fin du rendu, son sprite étant superposé à tout le reste. La raison à cela est que le HUD est plein, et non transparent. J'explique.
Un HUD de FPS normal ressemble à ce qu'il y a dans le screenshot à droite : quelques chiffres et icônes superposées sur le reste du rendu. On voit l'icône pour la vie, sa valeur, idem pour l'armure et les munitions. Mais entre les icônes et les chiffres, on voit la scène, l'eau, la texture du sol, etc. Le HUD a donc des parties transparentes, dans le sens où seuls les chiffres et icônes sont visibles/opaques.
Mais dans Wolfenstein 3D, et dans d'autres jeux du même genre, on a la même chose que ce qui est illustré dans l'animation de droite. Le HUD est un gros rectangle qui prend tout le bas de l'écran. On peut bouger autant qu'on veut, le bas de l'écran associé au HUD reste le même. Le HUD n'a pas de transparence, les textures et l'environnement se se voient pas à travers. Avec cette contrainte, on peut dessiner le HUD et le reste de l'image séparément. Le HUD est donc rendu au tout début du rendu. Cela signifie aussi que l'image calculée est en réalité plus petite. Si le HUD prend 10% de l'écran, alors on a juste à dessiner les 90% restants. Sans cette contrainte, on doit calculer 100% de l'image, pour ensuite superposer un HUD partiellement transparent.

## Le rendu de l'arme

Le rendu de l'arme est assez particulier. Tous les jeux vidéos, même récents, utilisent un rendu séparé pour l'arme et le reste du monde. Pour les jeux en 2.5D, c'est parce que c'est plus simple de procéder ainsi. Pour les jeux en 3D, la raison est que cela évite de nombreux problèmes. Si l'arme était en 3D et était calculée comme le reste du rendu, on aurait des problèmes du genre : l'arme passe à travers les murs quand on se rapproche trop d'eux. Il y a bien des exceptions, mais elles sont assez rares.
Le tout est bien expliqué dans cette vidéo Youtube sur la chaine de "Scrotum de Poulpe" (ca ne s'invente pas, je sais) :
* Le "problème" des mains dans les FPS.
Sur les anciens jeux comme Wolfenstein 3D, DOOM, Duke Nukem et autres, l'arme utilise la technique des sprites qui sera vu dans la section suivante.

## Le rendu des ennemis et items

Les objets sont rendus avec de simples images placées au-dessus du décor, qui ne sont ni plus moins que des sprites. Le meilleur moyen pour s'en rendre compte étant de tourner autour d'un objet : la forme de l'objet ne change pas du tout. Les objets sont de simples pancartes sur lesquelles on plaque une image.
Les ennemis sont généralement animés : ils bougent, ils sont "stun" quand on tire dessus, ils peuvent tirer des projectiles, ils ont une animation de mort, etc. Et il y a une animation pour chaque action. Pareil pour certains objets de l'environnement : pensez aux fameux barils explosifs qui explosent quand on tire dessus ! Le tout est illustré ci-contre, avec quelques exemples. Reste à la simuler avec des sprites. Pour cela, rien de plus simple : chaque animation est toujours la même, elle correspond à une succession de sprites qui est toujours identique. Il suffit de dérouler la bonne succession de sprite et le tour est joué !

### L'ordre de dessin des sprites

Le rendu des sprites se fait une fois que l'environnement a été dessiné, c'est à dire après les murs, le sol et les plafonds. Les sprites des ennemis et items sont donc superposé sur l'arrière-plan calculée par l'étape précédente. Cependant, certains sprites peuvent se recouvrir : il faut impérativement que le sprite le plus proche soit affiché au-dessus de l'autre. Pour cela, les sprites sont superposés suivant l'algorithme du peintre : on commence par intégrer les sprites des objets les plus lointains dans l'image, et on ajoute des sprites de plus en plus proches. Faire cela demande évidemment de trier les sprites à rendre en fonction de la profondeur des objets/ennemis dans le champ de vision (qu'il faut calculer).
Le cas le plus simple est le sprite de l'arme, qui est dessiné en tout dernier, car il est le plus proche du joueur.
Un autre point est qu'il ne suffit pas de superposer un sprites d'item ou d'ennemi pour que cela fonctionne. Cela marche dans un jeu en pure 2D, mais la 3D impose de gérer la profondeur. Rappelons que plus un objet/ennemi est loin, plus il nous parait petit, plus il est petit à l'écran. Les sprites doivent donc être mis à l'échelle suivant la distance : rapetissés pour les ennemis lointains, et zoomés pour les ennemis proches. Pour cela, on utilise une relation mathématique très simple : la loi de Thalès.

### La mise à l'échelle des sprites

Dans un jeu vidéo, et comme dans le monde réel, si on multiplie la distance d'un objet par deux, trois ou quatre, celui-ci devient respectivement deux, trois ou quatre fois plus petit. Dit autrement, un objet de hauteur H situé à une distance D aura une hauteur perçue identique à celle d'un objet de hauteur double/triple/quadruple situé deux/trois/quatre fois plus loin. En clair, pour un objet de hauteur $h_{1}$, situé à une distance $d_{1}$, et un autre objet de hauteur $h_{2}$ et de distance $d_{2}$, les deux auront la même hauteur perçue :
    ${\frac {h_{1}}{d_{1}}}={\frac {h_{2}}{d_{2}}}$
Tout sprite est une image, avec une résolution. Elle a un certain nombre de pixels à l'horizontale, un autre à la verticale. La taille verticale en pixel du sprite dépend du sprite, mettons qu'elle est égale à 50 pixels de large pour 60 de haut. Il s'agit de la taille réelle du sprite déterminée lors de la conception du jeu (aussi bien en vertical et horizontal). Nous allons noter sa taille en vertical comme suit : $T_{s}$.
Cette taille correspond à une distance précise. Pour un sprite 50 pixels de large pour 60 de haut, le sprite aura la même taille à l'écran à une certaine distance, que nous allons noter $D_{s}$.
Maintenant, d'après la relation vue plus haut, on peut calculer la taille affichée à l'écran du sprite, notée H. Pour cela, il suffit de connaitre la distance D, et on a la relation :
    ${\frac {T}{D}}={\frac {T_{s}}{D_{s}}}$
On peut la reformuler comme suit :
    $T=D\times {\frac {T_{s}}{D_{s}}}$
Quelques multiplications, et le tour est joué. Le terme ${\frac {T_{s}}{D_{s}}}$ peut même être mémorisé à l'avance pour chaque sprite, ce qui économise quelques calculs.