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
Le 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
Le 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
Le 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
DĂ©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
Soit 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
La 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
Voici 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
Notes et références
- (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 ).