If you're seeing this message, it means we're having trouble loading external resources on our website.

Si vous avez un filtre web, veuillez vous assurer que les domaines *. kastatic.org et *. kasandbox.org sont autorisés.

Contenu principal

Le bruit de Perlin

Un bon générateur de nombres aléatoires produit des nombres n'ayant pas de liens les uns avec les autres et ne laisse pas entrevoir de schéma répétitif. Comme nous avons commencé à nous en apercevoir, le hasard peut s'avérer utile pour simuler des comportements organiques, vivants. Cependant, le hasard seul n'est pas nécessairement représentatif de ce qu'est la nature. Un algorithme, connu sous le nom de “bruit de Perlin”, du nom de son inventeur Ken Perlin, tient compte de cette réalité. Perlin a développé la fonction de bruit alors qu'il travaillait sur le film Tron, durant les années 1980. Il devait créer des textures procédurales pour des effets générés par ordinateurs. Perlin a gagné le Prix académique de la réalisation technique 1997 pour ce travail. Le Bruit de Perlin peut être utilisé pour générer des effets variés, possédant des qualités naturelles, comme les nuages, des paysages ou des textures à motifs comme le marbre.
Le Bruit de Perlin a une apparence organique car il produit une séquence plus naturelle ("fluide") de nombres pseudo-aléatoires. Le graphique ci-dessous montre le bruit de Perlin en fonction du temps. Remarquez la douceur de la courbe.
Image de Nature of Code
Figure I.5 : Bruit
Par contraste, le graphique suivant montre des nombres générés aléatoirement dans le temps.
Image de Nature of Code
Figure I.6 : Aléatoire
ProcessingJS contient une implémentation intégrée de l'algorithme de bruit de Perlin : la fonction noise(). La fonction noise() prend un, deux ou trois arguments, car le bruit est calculé en une, deux ou trois dimensions. Commençons par regarder à quoi ressemble un bruit unidimensionnel.

Qu'est-ce que le bruit ?

La documentation sur la fonction noise nous explique que le bruit est calculé sur plusieurs "octaves". Appeler la fonction noiseDetail() permet de modifier le nombre d'octaves et l'importance que celles-ci ont, les unes par rapport aux autres, ce qui modifie le comportement de la fonction noise.
Une lecture en ligne (en anglais) vous en apprendra plus sur le fonctionnement du bruit, par Perlin lui-même.
Considérons que nous dessinions un cercle dans notre fenêtre ProcessingJS à une coordonnée x aléatoire.
var x = random(0, width);
ellipse(x, 180, 16, 16);
Maintenant, plutôt qu'une coordonnée x aléatoire, nous souhaitons une coordonnée x avec bruit de Perlin, plus "fluide". On pourrait penser qu'il suffit juste de remplacer random() par noise() :
var x = noise(0, width);
ellipse(x, 180, 16, 16);
Même si conceptuellement, c'est exactement ce que nous voulons faire (calculer une valeur x qui varie entre 0 et la largeur de l'écran, selon le bruit de Perlin), ce n'est pas la façon correcte de procéder. Alors que les paramètres de la fonction random() spécifient une plage de valeurs comprises entre un minimum et un maximum, noise() ne fonctionne pas de cette façon. À la place, noise() s'attend à ce que nous lui passions un argument représentant un "moment dans le temps", et retourne toujours une valeur comprise entre 0 et 1. Nous pouvons représenter un bruit de Perlin unidimensionnel comme une séquence linéaire de valeurs dans le temps. Par exemple, voici des entrées passées en argument, avec leurs valeurs de retour :
TempsValeur de bruit
00,469
0,010,478
0,020,485
0,030,490
0,040,420
Pour accéder à ces valeurs de bruit en ProcessingJS, nous devons donc passer un moment spécifique dans le temps à la fonction noise(). Par exemple :
var n = noise(0{,}03);
D'après le tableau ci-dessus, noise(0{,}03) retourne 0,490, pour un temps égal à 0,03. On peut améliorer ceci en utilisant une variable de temps, et en demandant continuellement une valeur de bruit dans draw().
Le code ci-dessus affiche sans arrêt la même valeur. C'est que nous demandons, en permanence, le résultat de la fonction noise(), au même point dans le temps. Si on incrémente la variable t du temps, cependant, on obtiendra des résultats différents.
La vitesse à laquelle on incrémente t, affecte également le lissage du bruit. Si nous faisons de grands sauts dans le temps, nous glisserons et nous obtiendrons des valeurs plus aléatoires
Bruit au fil du temps
Figure 1,7
Essayez d'exécuter le code ci-dessus plusieurs fois, en incrémentant t de 0,01, 0,02, 0,05, 0,1 et 0,0001. Vous observerez des résultats différents.

Mapper le bruit

Nous sommes maintenant prêt à répondre à la question : que faire avec les valeurs du bruit ? Une fois que nous obtenons une valeur entre 0 et 1, il nous reste à faire une correspondance proportionnelle avec un intervalle. Nous pourrions simplement multiplier par le nombre maximum de l'intervalle désiré, mais voici une bonne opportunité d'introduire la fonction map() de ProcessingJS, qui nous aidera dans plusieurs situations plus tard. La fonction map() prend cinq arguments. Le premier est la valeur que nous voulons mapper, ici n. Puis, nous devons donner les valeurs de notre intervalle actuel (minimum et maximum), suivi de l'intervalle désiré.
Image de Nature of Code
Figure I.8
Dans notre cas, nous savons que le bruit est compris entre 0 et 1, et nous voulons dessiner un rectangle dont la largeur est comprise entre 0 et la largeur de la zone de dessin.
Nous pouvons appliquer exactement la même logique avec notre marcheur aléatoire et lui affecter des coordonnées x et y qui suivraient le bruit de Perlin.
Remarquez que l'exemple ci-dessus nécessite deux variables supplémentaires : tx et ty. C'est parce qu'il nous faut enregistrer deux variables de temps, une pour la coordonnée x de l'objet Walker et l'autre pour sa coordonnée y. Mais il y a quelque chose d'étrange à propos de ces variables. Pourquoi tx commence à 0 et ty à 10 000 ? Bien que ces deux nombres sont des choix arbitraires, nous avons volontairement initialisé nos deux variables avec des valeurs différentes. C'est parce que la fonction de bruit est déterministe : elle vous donnera toujours le même résultat pour un temps donné t. Si nous avions demandé une valeur de bruit, pour le même temps t, pour x et pour y, alors x et y auraient été identiques, ce qui veut dire que l'objet Walker ne se serait déplacé qu'en diagonale. À la place, nous utilisons deux sections différentes de l'espace temporels, en commençant à 0 pour x, et 10 000 pour y, afin que x et y semblent agir indépendamment l'une de l'autre.
Image de Nature of Code
Figure I.9
En vrai, aucun concept réel de temps ne joue ici. C'est une utile métaphore pour nous aider à comprendre comment la fonction de bruit fonctionne, mais nous avons en fait à faire à de l'espace, plutôt qu'à du temps. Le graphique, ci-dessus, dépeint une séquence linéaire de valeurs de bruit dans un espace unidimensionnel, et nous pouvons demander une valeur, pour une coordonnée spécifique x, à n'importe quel moment. Dans nos exemples, vous verrez souvent une variable nommée xoff pour indiquer le décalage (offset en anglais) horizontal le long du graphique (sur l'axe des x) de la fonction bruit, plutôt que t pour le temps.
Dans le prochain défi, vous allez essayer d'utiliser le bruit sur le Walker, d'une façon légèrement différente. Amusez-vous !

Ce cours sur les "simulations de phénomènes naturels" est dérivé de l'ouvrage "The Nature of Code" de Daniel Shiffman, utilisé sous licence Creative Commons Attribution-NonCommercial 3.0 Unported License.

Vous souhaitez rejoindre la discussion ?

Pas encore de posts.
Vous comprenez l'anglais ? Cliquez ici pour participer à d'autres discussions sur Khan Academy en anglais.