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.
Par contraste, le graphique suivant montre des nombres générés aléatoirement dans le temps.
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 :Temps | Valeur de bruit |
---|---|
0 | 0,469 |
0,01 | 0,478 |
0,02 | 0,485 |
0,03 | 0,490 |
0,04 | 0,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
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é.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.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.