Pour le premier tutorial de ce blog, j'ai décider de commencer doucement, mais agréablement :
En effet, pendant qu’AnalogGuru s'occupera des tuto plutôt pour "débutant", je me ferais les trucs un peu plus poussés. En fait pas forcément, mais je n'expliquerai pas chaque lignes de mon code : D
Pour en revenir au sujet de l'article, rappelez vous des vielles démo 96k où vous avez pus voir des boules de plasma virevolter, parfois sous un petit air de ray tracing ! Et bien, ce soir, même si nous n'allons pas coder de metaballs en 3D, ( car pour que ça puisse tourner, il est nécessaire d'utiliser un algo fort puissant mais assez chiant à mettre en œuvre ( peut être un prochain tuto :-D), : les marching cube) nous allons tout de même réaliser un bel effet 2D ce qui simplifiera grandement les calculs.
Attention, je tiens juste à prévenir ceux qui sont allergique aux maths, les première partie, est relativement compliqué à mettre en pratique, donc pour ceux qui ne veulent pas forcément comprendre le concepte mais juste obtenir un résultat, rdv à la partie III !
I - Théorie :
Note : Désolé pour la gueule des formules, mais le site ne prend pas en charge le code LaTeX et je serais obliger de les ecrire comme ça jusqu'à trouver une solution !
Les metaballs ont été introduites il y a fort longtemps dans la scène démo. Pour faire l’analogie avec la vie courante, imaginez ces bonnes vieilles lampes à plasma, celles devant lesquelles on a tous badé quelques minutes en imaginant de la lave en fusion ! Et bien aujourd’hui, nous allons faire de même en 2D pour le moment, mais c’est un bon début !
Pour créer ces boules de cire et de pétrole avec nos petits pixels, nous devons introduire quelques notions mathématiques.
En effet, ici notre écran sera un champ scalaire (qu’est ce qu’un champ scalaire ? C’est une entité mathématique qui associe une valeur à chaque point du plan). La valeur des différents points sera modifiée par le potentiel de chacune de nos metaball. Le potentiel des metaballs est une sorte de rayonnement qui s’atténue relativement vite avec la distance. Pour calculer ce potentiel, nous utiliserons la fonction inverse qui nous donnera plus ou moins ceci :

Après ce cours de maths au combien difficile : codons !
II - Approche naïve du programme :
Je me justifie juste sur le titre : Approche « naïve ». Le mot « naïve » est seulement utilise pour justifier que nous allons donc appliquer la théorie telle quelle et laisser tomber toute optimisation pour le moment.
Ainsi, pour chaque pixel de notre viewport (la zone de rendu), nous allons calculer la distance entre le centre de notre metaball, et le pixel courant. Pour ceux qui n’aurais aucune envie de réfléchir :
Soit D la distance entre le centre de notre metaball, et le pixel courant,
A(X ;Y) est le point courant,
et C(Xc ;Yc) le centre de notre metaball
=> D = Sqrt((X-Xc)² + (Y-Yc)²)
Puis nous allons calculer le potentiel en ce point. Le principe est simple. La valeur α maximale est 255 et c’est celle au centre de la metaball. Le but est de trouver une valeur normalisée du potentiel (c'est-à-dire >= 0 et <= 1).
Soit P le potentiel et DMax la distance maximale possible :
P = | D/DMax –1 |
Ainsi, la composante α à pour valeur en A : 255 * P.
Je n’ai pas codé cette approche, car elle est très simple et ne permet pas de produire des rendus temps réels. En effet, de nombreux calculs complexes sont necessaires ( racine, division, mise au carré etc.), et ce, pour chaque point ! Ce qui, pour une résolution de 800x600 nous obligerai à faire ce calcule 480 000 fois, pour une seule image, c'est-à-dire 14 400 000 fois pour 30 images par secondes !
Optimisons donc !
III - Une sacrée optimisation :
En réfléchissant un peu, qu’est ce qu’une metaball ? Une forme dont la valeur alpha diminue avec la distance. Alors pourquoi ne pas précalculer l’image de cette metaball ? Vous l’avez compris, nous allons non plus considérer nos metaballs comme des objets mathématiques, mais comme des textures, et au lieu d’utiliser un blending classique, nous allons utiliser une modulation additive. C'est-à-dire que le device va simplement ajouter les valeurs α au pixel courant, et la clamper (c’est-à-dire, la borner) entre 0 et 255.
Ainsi, nous obtenons un résultat très facilement grâce à un simple spritebatch, et sans aucunes formules mathématiques En effet, il suffit juste d'afficher la texture précalculée du metaball avec la couleur désirée, avec le blending en additif et de faire bouger tout ca, rien de plus simple !
La mise en oeuvre est simple, reportez vous aux tuto XNA pour apprendre à charger et afficher une texture, cependant, la seule petite difficulté est de placer le blending en Additif.
C'est simple, au rendu, régler le spritebatch comme ceci :
[CODE]
SprBatch.Begin(SpriteBlendMode.Additive);
Sinon, la texture de la metaball est dispo dans le code source, ou pour les flemmard du DL
ici ( ne vous inquiétez pas si vous ne voyez rien, c'est du blanc sur un fond blanc, mais après le rendu modulé ( Cf tuto...), la couleur change biensûr.
Je n'ai pas traiter les collisions, ou les animations des metaballs car ces deux sujets feront l'objets de 2 gros tutos
!
Sinon, pour toutes les petits problèmes : le code source est dispo
ici. L'exe quant à lui :
ici !
Un petit screen pour vous donner le resultat attendu quand même :
Enfin ,n'hésitez pas à pauser des questions en commentaires, ou à faire des critiques (constructives si possible) +++
Commentaires