Ce code source sert à titre d'exemple, et dérive de celui donné dans le tutoriel sur les PostFX.
float radius
float time
vec2 coo
vec3 color
texture framebuffer
effect
{
vec4 pxlcolor = framebuffer(_in);
float dist = distance(vec2(gl_FragCoord), coo);
if(dist < radius)
{
float coef = cos(-3.5*time + 10.0*dist/radius);
coef = ((1.0 / sqrt(radius - dist + 1.0) + coef*coef))/2.0;
gl_FragColor = vec4(color, 1.0) * coef + pxlcolor * (1.0 - coef);
}
else
{
gl_FragColor = pxlcolor;
}
}
Ici, on prend l'exemple d'un rond pour lequel on fixe une couleur (color), une position du centre (coo) et un rayon (radius). On tient aussi compte du temps écoulé depuis le lancement du programme (time), éventuellement, si on espère avoir une animation. Le but est de calculer la transparence du rond en chaque pixel (coef), et de le fondre avec l'écran. On s'assure que le calcul renvoie une valeur dans [0,1], on applique ce coefficient à la couleur du rond, et son complémentaire au pixel de l'écran. Puis on somme, comme suggéré dans le tutoriel. Si en revanche le pixel n'est pas dans la zone de traitement, on lui donne affecte uniquement la couleur du pixel de l'écran.
En règle générale, on travaille sur des intervalles simples. Ainsi, on met “dist” à l'échelle en le divisant par “radius”, ou bien on fait une soustraction, selon les cas et les besoins. Ensuite, on calcule aisément (et on remet encore à l'échelle si besoin, dans [0,1]) :
- Le cosinus permet de donner un effet d'ondulation ou de stries, effet renforcé par la prise en compte du paramètre de temps. Le coefficient devant le rapport “dist/radius” détermine le nombre de vagues simultanées dans le rond. Le coefficient devant “time”, lui, détermine la vitesse (valeur absolue) et la direction (signe) des vagues. Il agit comme un offset. La mise au carré du cosinus évite les nombres négatifs, double le nombre de vagues et les atténue. On peut aussi écrire ”(cos(…) + 1)/2” plutôt que “cos(…)²” pour avoir un autre type d'effet en gardant la positivité.
- Le classique “x → 1/(a - x)” (fonction à connaître bien sûr) remplace avantageusement n'importe-quel calcul linéaire ou polynomial lorsqu'il faut accentuer les bords du rond en gardant une bonne transparence à l'intérieur. Evidemment cela dépend du but visé, et le but de ce code était de dessiner un bouclier semi-transparent pour un jeu vidéo, sans trop gêner la visibilité à l'intérieur. Il faut cependant faire attention. En effet, le domaine de cette fonction est [0, a] → [0, +infini[ (a étant “radius” dans notre cas), ce qui est embêtant quand on veut un résultat entre 0 et 1. Il suffit d'empêcher le dénominateur d'être inférieur à 1, et pour cela il suffit de lui ajouter 1, d'où la forme “1/(a - x + 1)” (on est bien sûrs que x < a). Il reste enfin la racine, qui a l'effet inverse du carré, à savoir accentuer la couleur du rond (quand je disais que ça remplaçait avantageusement d'autres types de calculs pour y voir clair à l'intérieur du rond, ce n'était pas exagéré).
Finalement, on peut superposer ces deux effets avec une bête moyenne arithmétique, mais ce n'est qu'une possibilité parmi tant d'autres (au hasard, la moyenne géométrique de a et b : “sqrt(a*b)”), du moment qu'on atterrit bien entre 0 et 1.