The Book of Shaders by Patricio Gonzalez Vivo & Jen Lowe

Bahasa Indonesia - Tiếng Việt - 日本語 - 中文版 - 한국어 - Español - Portugues - Français - Italiano - Deutsch - Русский - Polski - English


Design génératif

Il n'est pas surprenant qu'après avoir passé autant de temps à organiser régulièrement les choses, l'auteur soit amené à introduire du chaos.

Aléatoire

Ryoji Ikeda - test pattern (2008)

L'aléatoire est la plus haute expression de l'entropie. Comment pouvons nous créer de l'aléatoire dans un environnement apparemment aussi rigide et prévisible ?

Analysons la fonction suivante :

Nous récupérons la partie fractionnelle (fract()) d'une fonction de sinus sin(). Le sinus oscille entre -1.0 et 1.0 et on récupère les chiffres après la virgule ce qui annule le signe (- ou +) et retourne une valeur absolue. Nous pouvons utiliser ce procédé pour obtenir des valeurs pseudo-aléatoires en cassant cette oscillation en petits morceaux. Comment ? En multipliant le résultat de sin(x) par un grand chiffre. Essayez d'ajouter quelques zéros au multiplicateur de sin(x) dans le code ci-dessus.

En arrivant à 100000.0 (l'équation ressemble à : y = fract(sin(x)*100000.0)), il n'est plus possible de distinguer l'oscillation de la sinusoïde. La granularité de la partie fractionnelle a altéré les valeurs de la sinusoïde au point de la transformer en chaos pseudo-aléatoire.

Contrôler le chaos

Utiliser l'aléatoire peut être difficile ; soit le résultat sera trop chaotique, soit il ne sera pas assez aléatoire. Dans le graphe suivant, nous utilisons une fonction rand(), implémentée exactement comme décrit ci-dessus.

En regardant de plus près, on peut voir les pics que forme la sinusoïde à -1.5707 et 1.5707. Je parie que vous savez pourquoi - c'est là que la sinusoïde atteint ses valeurs minimum et maximum.

En regardant la distribution des valeurs en Y, vous noterez également que les valeurs se concentrent autour de .5 plutôt que vers 0 et 1.

Il y a quelques temps, Pixelero a publié un article sur les distributions aléatoires. J'ai ajouté quelques une des fonctions dont il se sert dans l'exemple ci-dessus pour que vous voyiez comment modifier une distribution. Décommentez les lignes pour voir comment chacune se comporte.

Si vous avez lu l'article de Pixelero, il est important de garder à l'esprit que notre fonction rand() est déterministe, aussi appelée pseudo-aléatoire. Ce qui signifie par exemple que rand(1.) renverra toujours la même valeur alors que Pixelero se sert de la fonction Math.random() qui est non-déterministe et renvoie une valeur différente à chaque appel.

Aléatoire en 2D

Maintenant que nous en savons un peu plus sur l'aléatoire, nous pouvons nous atteler à la deuxième dimension ; un bruit en x et y. Nous aurons besoin pour ça de transformer un vecteur à deux dimensions en un chiffre aléatoire. Il y a plusieurs façons de procéder mais la fonction dot() nous sera particulièrement utile dans ce cas précis. Elle retourne un chiffre compris entre -1.0 et 1.0 en fonction de l'alignement de deux vecteurs normalisés.

Le dot product ou produit scalaire renvoie le cosinus de l'angle formé par deux vecteurs normalisés. Il permet donc de retrouver l'angle formé par les 2 vecteurs et de déterminer si les 2 vecteurs pointent dans la même direction.

Aux lignes 13 à 15, nous utilisons le résultat du dot() de vec2 st et d'un autre vecteur( vec2(12.9898,78.233)).

Utiliser le chaos

L'aléatoire en 2D ressemble à la neige d'un téléviseur, n'est-ce pas ? C'est un métariau brut, difficile à utiliser tel quel pour construire une image, apprenons à mieux en tirer parti.

Notre première étape consistera à appliquer une grille ; en se servant de la méthode floor(), nous allons créer un tableau de cellules. Regardez bien le code suivant, notamment les lignes 22 et 23.

Après avoir multiplié l'échelle par 10 (ligne 21), nous séparons la partie entière de la partie fractionnelle du vecteur de coordonéées (st). C'est une opération dont nous nous sommes servis au dernier chapitre, elle nous permet de subdiviser l'espace et d'obtenir des cellules dont les coordonnées sont normalisées entre 0.0 et 1.0. La partie entière (le vecteur vec2 floor(st)) des coordonnées nous donne une valeur commune à chaque cellule, ce qui nous permet de trouver une valeur aléatoire pour chaque cellule plutôt que pour chaque fragment. Du fait de la nature déterministe de notre fonction rand(), la valeur retournée par la fonction lorsqu'on lui passe plusieurs fois le même vecteur sera la même. Comme tous les fragments d'une cellule passeront le même argument ipos à la fonction rand(), tous les fragments d'une cellule obtiendront la même couleur.

Décommentez la ligne 29 pour voir que nous conservons également la partie fractionnelle des coordonnées. Nous pouvons toujours utiliser ces coordonnées pour dessiner quelque chose dans la cellule.

En combinant les deux valeurs - la partie entière et la partie fractionnelle des coordonnées - permet de créer des variations et de faire des mélanges de nos valeurs aléatoires.

Regardez cette implémentation du célèbre générateur de labyrinthes 10 PRINT CHR$(205.5+RND(1)); : GOTO 10:

Ici, je me sers de la valeur aléatoire d'une cellule pour dessiner une ligne dans une direction ou l'autre en appelant la méthode truchetPattern() du chapitre précédent (lignes 41 à 47).

Vous pouvez obtenir un motif intéressant en décommentant les lignes 50 à 53, ou l'animer en décommentant les lignes 35 et 36.

Maîtriser l'aléatoire

Ryoji Ikeda, un compositeur et artiste japonais maîtrise l'utilisation de l'aléatoire ; difficile de ne pas être touché par son oeuvre. Dans ses oeuvres audio et vidéo, il utilise l'aléatoire de telle façon que ce n'est pas une série ennuyeuse de variations accidentelles mais plutôt un mirroir de la complexité de notre culture technologique.

Reagrdez le travail d'Ikeda et essayez les exercices suivants :

Utiliser l'aléatoire de façon esthétique peut être difficile, en particullier si vous recherchez un rendu naturel. L'aléatoire est beaucoup trop chaotique et dans la vraie vie, très peu de choses paraissent aussi aléatoires. Si vous regardez la pluie ou le cours de la bourse, qui sont tous les deux aléatoires, vous verrez qu'ils n'ont rien en commun avec la méthode que nous avons créé en début de chapitre. Pourquoi ? Les valeurs aléatoires ne sont pas corrélées entre elles, alors que les phénomènes naturels conservent souvent une trace de leur état précédent.

Au prochain chapitre, nous allons étudier le bruit, une manière plus organique de créer du chaos dans un shader.