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;
}
}
Voici un exemple de rendu :

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