Effet de vague avec GLSL et SFML
Bonjour,
Aujourd’hui je vais vous montrer comment créer un effet de vague en C++ avec la librairie SFML.
Pour commencer on va se créer une application de test, comme vous êtes chanceux je vous donne le code source directement.
// SFML Library #include <SFML/System.hpp> #include <SFML/Graphics.hpp> #include <conio.h> int main() { // Chargement d'une image de fond sf::Image Image; if (!Image.LoadFromFile("image.jpg")) { _getch(); return EXIT_FAILURE; } sf::Sprite Sprite(Image); // Chargement de l'effet sf::PostFX Effect; if (!Effect.LoadFromFile("wave.sfx")) { _getch(); return EXIT_FAILURE; } // Creation de la fenêtre de rendu sf::RenderWindow App(sf::VideoMode(1024, 768, 32), "SFML Post Effect"); // Initialisation du temps float iTime = 0.0f; // Game loop while (App.IsOpened()) { // On incrémente le temps écoulé depuis la dernière frame iTime += App.GetFrameTime(); // Affiche l'image de fond App.Draw(Sprite); // Gestion des évènements sf::Event Event; while (App.GetEvent(Event)) { // Fermeture de la fenêtre if (Event.Type == sf::Event::Closed) { App.Close(); } // Clique de souris if (Event.Type == sf::Event::MouseButtonPressed) { iTime = 0.0f; // - - - Passage des paramètres à notre postfx } } // - - - Passage des paramètres à modifier à chaque frames Effect.SetTexture("tex", NULL); // Affiche notre postfx App.Draw(Effect); // Affiche la fenêtre App.Display(); } }
Il est assez simple et bien commenté, tout ce que l’on fait dans ce code c’est charger une image de fond ainsi qu’un fichier d’effet. Dans la boucle principale on affiche nos différents éléments et au cas ou l’on appuie sur un bouton de la souris on passe de nouveaux paramètres à notre PostFX. Les lignes de codes permettant de passer des paramètres devront être complétées par la suite.
Etape 1: Appliquer un effet sur le framebuffer
Pour l’instant un seul paramètre est passé depuis notre application C++ : « tex » avec comme valeur NULL, « tex » est le nom de la variable que l’on retrouvera dans notre fichier d’effet et NULL veut dire que l’on travaille sur la totalité du framebuffer.
Voici le contenu de notre fichier wave.sfx :
sampler2D tex effect { gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0); }
Pour l’instant j’obtiens donc une superbe fenêtre avec une image de fond.
Copyright Hélène Villeneuve pour la superbe photo de noix ^^
Notre code GLSL contient pour l’instant une ligne qui change la couleur de notre pixel.
Comme les paramètres sont tous à 0 il ne se passe rien, mais vous pouvez essayer de changer ceux-ci en sachant que les éléments de notre vecteur 4 définissent les paramètres suivants : composante de rouge, vert, bleu et alpha; Tous paramétrables de 0 à 1.
Etape 2 : Temporiser et paramétrer l’effet
On va passer de nouveaux paramètres à notre effet dans le code C++, on va donner une position qui sera celle de la souris lorsque l’on clique, le temps écoulé depuis le début de l’effet et la taille de la vague.
On va donc ajouter les valeurs suivantes : « time » qui sera la variable iTime de notre code cpp; « center » qui sera la position de la souris et wavesize qui sera la taille de la vague.
Voici donc les valeurs à ajouter dans notre code cpp :
// - - - Passage des paramètres à notre postfx Effect.SetParameter("wavesize", 20.0f); Effect.SetParameter("center", Event.MouseButton.X / 1024.0f, 1.0 - Event.MouseButton.Y / 768.0f); // - - - Passage des paramètres à modifier à chaque frames Effect.SetTexture("tex", NULL); Effect.SetParameter("time", iTime);
Le fichier « .sfx » devra prendre en compte les nouveaux paramètres, et temporiser l’effet en calculant la distance entre le pixel courant et le centre de l’effet en fonction du temps écoulé :
sampler2D tex vec2 center float time float wavesize // 1 big -> 40 small effect { // On récupère les coordonnées du pixel courant vec2 uv = gl_TexCoord[0].st; // On calcul la distance entre le pixel courant et le centre de la vague float distance = distance(uv, center); // Le pixel doit il être modifié (se trouve il dans le cercle de la vague) if ((distance <= (time + 1.0 / wavesize)) && (distance >= (time - 1.0 / wavesize))) { gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); // pixel devient rouge } else { discard; // on ne fait rien } }
On obtient maintenant de magnifiques cercles rouges lorsque l’on clique avec la souris.
Une petite subtilité : les coordonnées de la souris ont comme point de référence le coin supérieur gauche avec comme valeur maximum la taille maximale de la fenêtre alors que les coordonnées d’un pixel en GLSL sont comprises entre 0 et 1 avec comme point de référence le coin inférieur gauche de la fenêtre.
Pour s’adapter aux coordonnées GLSL on doit donc diviser par la taille de la fenêtre comme je l’ai fait dans le code cpp ci-dessus.
Etape 3 : Calculer l’effet de vague
La partie qui vous intéresse certainement le plus, l’effet de vague. Pour ça rien de plus simple il suffit de récupérer la texture d’un pixel avoisinant en fonction de l’intensité de la vague.
Pour ça pas de secrets, je vous donne une formule magique, maintenant c’est à vous de créer les vôtres. Cette formule incrémente notre vecteur de position d’une valeur comprise entre 0 et X en fonction de la position du pixel dans la zone d’effet et du taux de déformation voulu.
Voila le code final de notre .sfx :
sampler2D tex vec2 center float time float intensity // 1.0 big -> 0.0 small float wavesize // 1 big -> 40 small effect { // On récupère les coordonnées du pixel courant vec2 uv = gl_TexCoord[0].st; // On calcul la distance entre le pixel courant et le centre de la vague float distance = distance(uv, center); // Le pixel doit il être modifié (se trouve il dans le cercle de la vague) if ((distance <= (time + 1.0 / wavesize)) && (distance >= (time - 1.0 / wavesize))) { // Différence entre la distance et le temps float diff = (distance - time); // Calcul de l'effet de vague uv = uv + (normalize(uv - center) * (diff * (1.0 - pow(abs(diff*wavesize), intensity)))); // Récupération de la texture du pixel gl_FragColor = texture2D(tex, uv); } else { discard; } }
Si vous avez des question n’hésitez pas à laisser un commentaire.
Pour les paresseux voici le code source.
Bonne journée et à une prochaine fois






