Bruit de Perlin
Le bruit de Perlin est une texture procédurale utilisée comme effet visuel pour augmenter le réalisme apparent dans la synthèse d'image. La fonction a une apparence pseudo-aléatoire, et pourtant tous ses détails visuels sont de taille égale (voir image). Cette propriété permet à cette texture d'être facilement contrôlable. De multiples copies zoomées de bruit de Perlin peuvent être insérées dans des expressions mathématiques pour créer une grande variété de textures procédurales.
Usages
modifierLe bruit de Perlin est une texture procédurale primitive, c'est un bruit de gradient (par opposition aux bruits de valeur) utilisé pour améliorer le réalisme des infographies. La fonction a un aspect pseudo-aléatoire, cependant ses détails sont de la même taille ; cette propriété la rend facilement contrôlable en la combinant à différentes échelles.
Le bruit de Perlin est souvent utilisé dans les images de synthèse pour des éléments tels que le feu, la fumée ou les nuages.
Les démos font couramment usage du bruit de Perlin car il permet de générer des textures en étant très économique en termes d'espace mémoire.
Cette texture procédurale a aussi été utilisée dans des jeux vidéo tel que Minecraft, le jeu appliquait cette texture à la carte, ainsi les endroits plus sombres étaient profonds et les endroits plus clairs étaient hauts par exemple le pic d'une montagne. L'usage de cette texture est ingénieux car il permet la génération d'un monde cohérent dans le jeu .
-
Feu généré à partir de bruit de Perlin.
-
Terrain généré à partir de bruit de Perlin.
Développement
modifierLe bruit de Perlin a été développé par Ken Perlin en 1985. À cette époque, après avoir travaillé sur les effets spéciaux de Tron pour MAGI (en) en 1981, il cherchait à éviter le look « machinique »[1]. Il commença donc par mettre au point une fonction pseudo-aléatoire de bruit qui remplit les trois dimensions de l'espace[2],[3], avant d'inventer l'année suivante le premier langage de shading (en)[4]. Ses travaux sur les textures procédurales ont valu à Ken Perlin l'Academy Award for Technical Achievement (en) en 1997[5].
Algorithme
modifierLe bruit Perlin est le plus couramment utilisé à deux, trois, voire quatre dimensions, il peut être défini pour un nombre quelconque de dimensions. L'algorithme se décompose en trois étapes :
- définition de la grille avec des vecteurs de gradient aléatoires ;
- calcul du produit scalaire entre le vecteur de gradient et le vecteur distance ;
- interpolation entre ces valeurs.
Définition de la grille
modifierDéfinir une grille à n dimensions. À chaque point de la grille (nœud), attribuer un vecteur de gradient aléatoire de longueur unitaire et de dimension n.
Pour une grille à deux dimensions, à chaque nœud sera assigné un vecteur aléatoire du cercle unité, et ainsi de suite pour les dimensions supérieures. Le cas unidimensionnel est une exception : le gradient est un scalaire aléatoire entre -1 et 1.
Le calcul des gradients (pseudo)-aléatoires en une et deux dimensions est trivial en utilisant un générateur de nombres aléatoires. Pour les dimensions supérieures, une approche Monte Carlo peut être utilisée où les coordonnées cartésiennes aléatoires sont choisies dans un cube unité, les points situés en dehors de la sphère unité sont rejetés et les points restants sont normés.
Produit scalaire
modifierSoit un point de l'espace à n-dimensions envoyé à la fonction de bruit, l'étape suivante dans l'algorithme consiste à déterminer dans quelle cellule de grille le point donné tombe. Pour chaque nœud-sommet de cette cellule, calculer le vecteur distance entre le point et le nœud-sommet. Puis calculer le produit scalaire entre le vecteur de gradient au nœud et le vecteur de distance.
Pour un point dans une grille bidimensionnelle, cela nécessitera le calcul de 4 vecteurs de distance et de 4 produits scalaires, tandis que dans les trois dimensions, 8 vecteurs de distance et 8 produits scalaires sont nécessaires. Cela conduit à l'échelle de complexité .
Interpolation
modifierLa dernière étape est l'interpolation entre les produits scalaires calculés aux nœuds de la cellule contenant le point d'argument. Cela a pour conséquence que la fonction de bruit renvoie 0 lorsqu'elle est évaluée sur les nœuds de la grille eux-mêmes.
L'interpolation est effectuée en utilisant une fonction dont la dérivée première (et éventuellement la dérivée seconde) est nulle aux nœuds de la grille . Cela a pour effet que le gradient de la fonction de bruit résultante à chaque nœud de grille coïncide avec le vecteur de gradient aléatoire précalculé. Si , un exemple de fonction qui interpole entre la valeur au nœud de grille 0 et la valeur au nœud de grille 1 est
où la fonction smoothstep (en) a été utilisée.
Les fonctions de bruit utilisées dans l'infographie produisent généralement des valeurs comprises dans la plage [-1.0,1.0]. Afin de produire du bruit Perlin dans cette plage, la valeur interpolée peut avoir besoin d'être mise à l'échelle par un facteur d'échelle.
Pseudo-code
modifierVoici le pseudo-code de l'implémentation du bruit de Perlin dans un espace à deux dimensions.
// Function to transition smoothly from 0.0 to 1.0 in the range [0.0, 1.0] function smoothstep(float w) { if (w <= 0.0) return 0.0; if (w >= 1.0) return 1.0; return w * w * (3.0 - 2.0 * w); } // Function to interpolate smoothly between a0 and a1 // Weight w should be in the range [0.0, 1.0] function interpolate(float a0, float a1, float w) { return a0 + (a1 - a0) * smoothstep(w); } // Computes the dot product of the distance and gradient vectors. function dotGridGradient(int ix, int iy, float x, float y) { // Precomputed (or otherwise) gradient vectors at each grid node extern float Gradient[IYMAX][IXMAX][2]; // Compute the distance vector float dx = x - (float)ix; float dy = y - (float)iy; // Compute the dot-product return (dx*Gradient[iy][ix][0] + dy*Gradient[iy][ix][1]); } // Compute Perlin noise at coordinates x, y function perlin(float x, float y) { // Determine grid cell coordinates int x0 = floor(x); int x1 = x0 + 1; int y0 = floor(y); int y1 = y0 + 1; // Determine interpolation weights // Could also use higher order polynomial/s-curve here float sx = x - (float)x0; float sy = y - (float)y0; // Interpolate between grid point gradients float n0, n1, ix0, ix1, value; n0 = dotGridGradient(x0, y0, x, y); n1 = dotGridGradient(x1, y0, x, y); ix0 = interpolate(n0, n1, sx); n0 = dotGridGradient(x0, y1, x, y); n1 = dotGridGradient(x1, y1, x, y); ix1 = interpolate(n0, n1, sx); value = interpolate(ix0, ix1, sy); return value; }
Annexes
modifierNotes et références
modifier- (en) Ken Perlin, « History », sur www.noisemachine.com (consulté le ).
- (en) Ken Perlin, « Controlled random primitive », sur www.noisemachine.com (consulté le ).
- (en) Ken Perlin, « coherent noise function over 1, 2 or 3 dimensions », sur nyu.edu (consulté le ). Code (en C) de la première version de la fonction, en 1983.
- (en) Ken Perlin, « Rapid adoption », sur www.noisemachine.com (consulté le ).
- (en) Ken Perlin, « Noise and Turbulence », sur nyu.edu (consulté le ).