Salut à tous !
J’étudie l’animation du célèbre jeu DOOM selon http://fabiensanglard.net/doom_fire_psx/ , qui consiste à générer du feu.
Une version complète du code de l’auteur est : https://github.com/fabiensanglard/DoomFirePSX/blob/master/flames.html
Première approche : mise en place des grands principes, et simplification du feu (car remplacé par un simple dégradé de couleurs)
-
Mettre en place un jeu de couleurs rempli de façon précise : ce jeu définit un dégradé qui ressemble à du feu. Il y a 36 couleurs du blanc au noir, et parmi elles il y a du jaune, de l’orange et du rouge. Cet ensemble ne contient pas de doublon.
-
Itérer une première fois sur les pixels du canvas. Ici le but est de colorer en noir tous les pixels (i.e. : la dernière couleur de l’ensemble).
-
Itérer une deuxième fois sur le canvas. Cette fois, nous devons colorer en blanc les pixels de la première ligne du bas (i.e. : la première couleur de l’ensemble).
-
Itérer à nouveau sur le canvas, mais seulement à partir de la deuxième ligne du bas (incluse), pas à partir de la première ligne du bas (qui est ainsi exclue). Pour chaque pixel itéré, on modifie sa couleur de cette façon : on prend la couleur de son pixel inférieur direct, on trouve l’index de cette couleur dans l’ensemble des couleurs, on ajoute 1 à cet index : on obtient un autre index qu’on appelle i2, on trouve la couleur dont l’index est i2, puis on applique cette couleur sur ce pixel itéré.
Une fois l’exécution terminée, il y aura plusieurs dégradés, chacun contenant 36 lignes (soit 36 couleurs).
Zoom
Nota: cette partie précisément a été temporairement annulée dans mon implémentation. Ainsi, j’ai bien actuellement plusieurs dégradés dans mon canvas.
Mon but est d’obtenir un unique dégradé faisant toute la hauteur de mon canvas. Du coup j’ai divisé cette dernière par le nombre de couleurs disponibles dans mon jeu de couleurs (36), et j’ai fait en sorte de changer de couleurs au moment de peindre dans mon canvas qu’au bon moment (chaque fois que je dépasse le résultat de cette division).
Pour l’instant ça fonctionne, j’obtiens bien mon dégradé qui va du blanc au noir et chacune de ses lignes est épaisse telle que l’ensemble de ses lignes remplit bien toute la hauteur (et, précisons-le accessoirement, toute la largeur) de mon canvas.
Nota: cette partie précisément a été temporairement annulée dans mon implémentation. Ainsi, j’ai bien actuellement plusieurs dégradés dans mon canvas.
Pour que ça ressemble vraiment à du feu
Le programme expliqué par http://fabiensanglard.net/doom_fire_psx/ va plus loin que ça évidemment : il fait usage du pseudo-aléatoire par deux fois, pour obtenir un truc qui ne ressemble pas à un simple dégradé mais bel et bien à du feu.
L’idée est la suivante. Pour le pixel en cours d’itération :
-
On récupère l’index de la couleur du pixel situé juste en-dessous. Puis, on récupère la couleur, dans le jeu de couleurs, dont l’index est cet index + un nombre aléatoire impliquant un léger décalage (d’au maximum 2 cases si je me souviens bien). Ainsi, on peut modéliser l’accélération de la variation de la température des particules.
-
Et, de manière supplémentaire, on considère le pixel situé un petit peu à gauche du pixel en cours d’itération. "Un petit peu" = en fonction du même nombre aléatoire de la puce N°1. C’est ce pixel situé un peu à gauche qui se verra attribué la couleur récupérée en puce N°1. Ainsi, on peut modéliser le déplacement horizontal vers la gauche des flammes.
On voit donc que c’est un travail en triangle (car on prend le pixel en cours d’itération, celui juste en-dessous et celui qui est un peu à sa gauche).
Pseudo-aléatoire utilisé pour modéliser l’accélération de la variation de la température des particules
Un nombre aléatoire est généré, compris entre 0 et 3 tous deux inclus et est utilisé ici :
firePixels[src - FIRE_WIDTH ] = pixel - (rand & 1);
On introduit donc une légère variation au niveau de la couleur à appliquer.
Pseudo-aléatoire utilisé pour modéliser le déplacement horizontal vers la gauche des flammes.
En supplément de ce qu’on vient de voir, du pseudo-aléatoire utilisé sur les pixels, par ligne est aussi utilisé.
Ce même nombre aléatoire est ré-utilisé ici :
var dst = src - rand + 1;
firePixels[dst - FIRE_WIDTH ] = pixel - (rand & 1);
Ici, un léger décalage est effectué horizontalement.
Questions
-
Alors déjà j’aimerais savoir si je ne me suis pas trompé dans la compréhension de ce programme : il est vrai que l’auteur n’apporte pas beaucoup d’explications, ne détaille pas certaines variables pourtant cruciales…
-
J’ai essayé d’implémenter ça, en utilisant deux boucles imbriquées pour parcourir le canvas et en utilisant les valeurs de celui-ci directement. L’auteur quant à lui n’utilise pas d’imbrication de boucle (cf.
spreadFire(y * FIRE_WIDTH + x);
). Sa façon de voir les choses est donc un peu différente de la mienne, et je ne souhaite pas pour autant rallier la sienne. Or il s’avère que… j’ai un petit souci avec mon programme tel qu’il est fait actuellement. Toutefois, afin de ne pas écrire un pavé ici, je préférerais qu’on valide ce que j’ai écrit plus haut, ensuite seulement je montrerais ce que j’ai fait et vous demanderai pourquoi ça ne marche pas.
Voilà voilà, si vous avez le temps n’hésitez pas à lire les explications de l’auteur et à répondre à ma première question du coup !
Merci d’avance et bonne année !!!