Le langage GLSL offre par défaut de nombreuses fonctions. Parmi ces fonctions, on retrouve beaucoup de fonctions mathématiques qui permettent de calculer à peu près tout et n'importe quoi, mais on retrouve aussi des fonctions indispensables effectuant des tâches bien précises propres aux shaders.
Tout d'abord, vous devez savoir que la plupart des fonctions du GLSL sont surchargées, ce qui facilite leur utilisation, qui devient alors intuitive et un vrai jeu d'enfant. Pour faire simple, je vous préviens d'avance : toutes les fonctions que je vais vous présenter sont surchargées, donc utilisez-les à volonté et dans toutes les circonstances. De plus, l'usage des fonctions prédéfinies du GLSL est
fortement recommandé dans la mesure où la plupart de celles-ci sont directement implantées dans les cartes graphique, ce qui vous permet de tirer parti de toute la puissance de vos cartes et ainsi gagner en performance.
Fonctions de manipulation de vecteurs
Pour comprendre la plupart des fonctions que nous allons étudier ici, je vous recommande la lecture du
chapitre annexe sur les vecteurs.
Normalisation de vecteurs
Le langage GLSL offre une fonction permettant de normaliser un vecteur. Cette fonction s'appelle
normalize().
Elle prend un paramètre (un vecteur) et renvoie ce même vecteur, mais normalisé.
Voici un code pour illustrer la normalisation d'un vecteur
v :
Code : Autre1
2
3
| vec3 v = vec3(0.2, 0.4, 0.6);
v = normalize(v); |
Produit scalaire
Pour calculer le produit scalaire de deux vecteurs en GLSL, rien de plus simple : appelez la fonction
dot(). Cette fonction prend deux paramètres. Ces paramètres sont les deux vecteurs dont on veut connaître le produit scalaire.
dot() renvoie un flottant qui n'est autre que le résultat du produit :
Code : Autre1
2
3
| vec3 v1 = ..., v2 = ...;
...
float res = dot(v1, v2); |
Produit vectoriel
Là encore, une fonction existe, il s'agit de
cross(). Elle prend deux vecteurs en paramètres, et renvoie un vecteur qui est le résultat du produit vectoriel de ses deux paramètres :
Code : Autre1
2
3
| vec3 v1 = ..., v2 = ...;
...
vec3 res = cross(v1, v2); |
Longueur d'un vecteur
Pour connaître la longueur d'un vecteur simplement, utilisez la fonction
length() :
Code : Autre1
| float longueur = length( vec3(2.0, 0.8, 1.6) ); |
Distance entre deux vecteurs
Bien que cette solution soit envisageable :
Code : Autre1
2
3
| vec3 a, b;
...
float d = length( a - b ); |
Il en existe une plus explicite : utiliser la fonction
distance() :
Code : Autre1
2
3
| vec3 a, b;
...
float d = distance( a, b ); |
Et voilà, ça sera tout pour les fonctions de manipulation de vecteurs
En ce qui concerne les additions/soustractions de vecteurs, rappelez-vous le précédent chapitre : les opérateurs en GLSL sont surchargés, par conséquent, vous n'aurez qu'à placer l'opérateur de votre choix entre deux vecteurs, ou entre un vecteur et une valeur.
Code : Autre1
2
3
4
| vec3 v1 = ..., v2 = ...;
vec3 add = v1 + v2; // add = le resultat de l'addition des vecteurs v1 et v2
vec3 mul = v1 * 2.0; // chaque composante de mul = chaque composante de v1 * 2 |
La fonction ftransform()
Voici une fonction qui est souvent utilisée par les programmeurs pour... se faciliter la vie. Notez bien qu'
elle n'est utilisable qu'au sein d'un vertex shader. Souvenez-vous lorsque vous avez créé votre premier vertex shader lors du précédent chapitre. Vous aviez attribué à la variable de sortie
gl_Position le résultat de la multiplication de la position du sommet par les matrices modelview et projection combinées. Voici quel était le code final du vertex shader :
Code : Autre1
2
3
4
| void main(void)
{
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
} |
Ce code est plutôt lourd et long à coder.
Il est cependant remplaçable par celui-ci, qui a l'avantage d'être beaucoup plus léger :
Code : Autre1
2
3
4
| void main(void)
{
gl_Position = ftransform();
} |
Vous me demanderez sans doute quel est l'intérêt de la première méthode, ce à quoi je vous répondrai : quel est l'intérêt de la seconde vous voulez dire ? En fait la fonction
ftransform() a pour effet de vous rendre la position finale du sommet comme si il avait été traité par le
FFP.
Encore quelques fonctions
Je vous montre encore quelques fonctions, et après c'est bon, je vous aurai montré le principal (fonctions les plus utilisées).
Nous allons voir trois fonctions très simples, mais très pratiques :
min()
Cette fonction renvoie la plus petite valeur entre deux valeurs fournises :
Code : Autre1
2
3
| float a = 0.2, b = 0.5;
float res = min(a, b); |
Ici,
res =
0.2
Notez que cette fonction peut être remplacée par l'instruction suivante (comme en C) :
Code : Autre
Tout comme de nombreuses fonctions,
min() est surchargée, vous pouvez donc lui envoyer des vecteurs, elle vous renverra le plus court.
max()
Exactement l'inverse de
min(),
max() vous renvoie son plus grand paramètre :
Code : Autre1
| int res = max(2, 4); // res = 4 |
Elle est bien évidemment elle aussi surchargée.
clamp()
La fonction
clamp() est un mélange des deux fonctions vues ci-dessus, elle prend trois paramètres :
Code : Autre1
| T clamp(T var, T minimum, T maximum); |
L'emploi de 'T' représente juste un type quelconque.
et renvoie ceci :
Code : Autre1
| min(max(var, minimum), maximum); |
Euh, j'ai rien compris, c'est normal ?
Oui, rassurez-vous
En fait, la fonction
clamp() vous renvoie une valeur qui se situe forcément entre
minimum et
maximum.
clamp() renvoie
var si sa valeur est située entre
minimum et
maximum, sinon elle renvoie la valeur la plus proche de
var (
minimum ou
maximum).
Nous pouvons programmer
clamp() comme ceci :
Code : Autre1
2
3
4
5
6
| if(minimum > var)
return minimum;
else if(up < var)
return maximum;
else
return var; |
Spécifications du GLSL
La version du langage étudié dans ce tutoriel possède
des spécifications que vous trouverez sur le site d'OpenGL. Ceci est la documentation de référence et votre meilleur guide dans l'avenir pour l'apprentissage du GLSL.