commit
a6b8f469a9
|
|
@ -1,7 +1,7 @@
|
|||

|
||||
|
||||
## Bruit Cellulaire
|
||||
En 1996, seize ans après Le *Bruit de Perlin* et cinq ans avant le *Bruit Simplexe*, [Steven Worley a publié un papier: “Une function pour les textures cellulaires”](http://www.rhythmiccanvas.com/research/papers/worley.pdf).
|
||||
En 1996, seize ans après Le *Bruit de Perlin* et cinq ans avant le *Bruit Simplex*, [Steven Worley a publié un papier: “Une function pour les textures cellulaires”](http://www.rhythmiccanvas.com/research/papers/worley.pdf).
|
||||
Il y décrit une technique de texture procédurale amplement utilisée de nos jours pas la communauté des développeurs graphiques.
|
||||
|
||||
Pour comprendre le principe qui sous-tend l'algorithme, nous devons réfléchir en termes d'itérations.
|
||||
|
|
@ -9,8 +9,8 @@ Pour comprendre le principe qui sous-tend l'algorithme, nous devons réfléchir
|
|||
### Un champ de distances pour quelques points
|
||||
|
||||
Imaginons que nous voulions faire un champ de distance à quatre points.
|
||||
De quoi aurions besoin? pour faire court, **pour chaque pixel, trouver la distance au point le plus proche**.
|
||||
Ce qui signifie qu'il va nous falloir itérer sur tous les points et conserver la daistance au point le plus proche.
|
||||
De quoi aurions nous besoin? pour faire court, **pour chaque pixel, trouver la distance au point le plus proche**.
|
||||
Ce qui signifie qu'il va nous falloir itérer sur tous les points et conserver la distance au point le plus proche.
|
||||
|
||||

|
||||
|
||||
|
|
@ -36,7 +36,7 @@ Jouez avec pour vous donner une meilleure idée de comment ça marche puis essay
|
|||
|
||||
### Pavage et itérations
|
||||
|
||||
vous avez sans doute remarqué que les boucles `for` et les *tableaux* ne sont pas bien amicaux en GLSL.
|
||||
vous avez sans doute remarqué que les boucles `for` et l'utilisation de *tableaux* n'est pas recommandée en GLSL.
|
||||
Les boucles n'accpetent pas d'arguments dynamiques, itérer sur un grand nombre d'entrées ralentit considérablement l'exécution du shader, nous devons donc changer de stratégie.
|
||||
|
||||

|
||||
|
|
@ -45,14 +45,13 @@ Une façon d'aborder le problème est de diviser l'espace en *tuiles* (**tiles**
|
|||
Au fond, tous les pixels n'ont pas besoin de tester l'ensemble des points n'est ce pas?
|
||||
Ils ont simplement besoin de vérifier les points qui sont proches d'eux.
|
||||
C'est l'idée principale [de la publication de Steven Worley](http://www.rhythmiccanvas.com/research/papers/worley.pdf).
|
||||
Nous avons déjà subdivisé l'espace en cellules au chapitres des,
|
||||
We already subdivide the space into cells in the chapters about: [motifs](../09/?lan=fr), de [l'aléatoire](../10/?lan=fr) et du [bruit](../11/?lan=fr).
|
||||
Nous avons déjà subdivisé l'espace en cellules au chapitres des [motifs](../09/?lan=fr), de [l'aléatoire](../10/?lan=fr) et du [bruit](../11/?lan=fr).
|
||||
Vous devriez être un peu plus familier avec cette technique.
|
||||
|
||||
```glsl
|
||||
// échelle (nombre de cellules)
|
||||
st *= 3.;
|
||||
|
||||
|
||||
// variables utilisées pour paver le plan
|
||||
vec2 i_st = floor(st);
|
||||
vec2 f_st = fract(st);
|
||||
|
|
@ -66,7 +65,7 @@ Donc chaque cellule contiendra un point à une position aléatoire dans la cellu
|
|||
vec2 point = random2(i_st);
|
||||
```
|
||||
|
||||
A l'intérieur de chaque cellule, tous les fragments (à l'aide de la partie factorielle de ```f_st```, `fract( st )` ) vont mesurer la distance à ce point.
|
||||
A l'intérieur de chaque cellule, tous les fragments (à l'aide de la partie fractionelle de ```f_st```, `fract( st )` ) vont mesurer la distance à ce point.
|
||||
|
||||
```glsl
|
||||
vec2 diff = point - f_st;
|
||||
|
|
@ -75,12 +74,12 @@ A l'intérieur de chaque cellule, tous les fragments (à l'aide de la partie fac
|
|||
|
||||
Ca ressemblera à:
|
||||
|
||||
<a href="../edit.php#12/cellnoise-01.frag"><img src="cellnoise.png" width="520px" height="200px"></img></a>
|
||||
<a href="../edit.php#12/cellnoise-01.frag"><img src="cellnoise.png" width="520px" height="200px"></img></a>
|
||||
|
||||
Nous devons également calculer la distance aux points des cellules adjacentes ;
|
||||
en effet, il se pourrait que le point le plus proche du fragment en cours d'évaluation se trouves dans une cellule voisine.
|
||||
Pour cela, nous allons itérer sur les cellules voisines, pas toutes les cellules, juste les cellules adjacentes.
|
||||
Soit de ```-1``` (gauche) à ```1``` (droite) cellule en ```x``` et de ```-1``` (bas) à ```1``` (haut) en ```y```.
|
||||
Soit de ```-1``` (gauche) à ```1``` (droite) cellules en ```x``` et de ```-1``` (bas) à ```1``` (haut) en ```y```.
|
||||
Ce qu'on appelle un *kernel de 3x3*, sur lequel on peut itérer grâce à deux boucles `for` imbriquées telle que celle-ci.
|
||||
|
||||
```glsl
|
||||
|
|
@ -110,7 +109,7 @@ Pour le reste, il suffit de calculer la distance entre ce point et le fragment e
|
|||
```glsl
|
||||
...
|
||||
vec2 diff = neighbor + point - f_st;
|
||||
|
||||
|
||||
// Distance au point
|
||||
float dist = length(diff);
|
||||
|
||||
|
|
@ -139,7 +138,7 @@ Explorez en essayant les choses suivantes:
|
|||
Cet algorithme peut également être interprété du point de vue des points au lieu des pixels.
|
||||
Dans ce cas, on peut le décrire comme: chaque point grossit jusqu'à ce qu'il recouvre le rayon d'un autre point.
|
||||
Ce qui reflète certaines règles de croissance de la nature, les formes de vie sont formées par la tension entre une force intérieure d'expansion et des forces contraires venues de l'extérieur.
|
||||
L'algorithm canonique de ce genre de formes a été trouvé par [Georgy Voronoi](https://en.wikipedia.org/wiki/Georgy_Voronoy), et porte maintenant son nom.
|
||||
L'algorithm canonique de ce genre de formes a été trouvé par [Georgy Voronoi](https://en.wikipedia.org/wiki/Georgy_Voronoy) et porte maintenant son nom.
|
||||
|
||||

|
||||
|
||||
|
|
@ -162,7 +161,7 @@ Pourquoi? Parce que nous avons besoin de modifier la référence au point le plu
|
|||
|
||||
<div class="codeAndCanvas" data="vorono-00.frag"></div>
|
||||
|
||||
Notes également que la couleur de la cellule (branchée sur la position de la souris) change en fonction de sa position.
|
||||
Notez également que la couleur de la cellule (branchée sur la position de la souris) change en fonction de sa position.
|
||||
C'est parce que la couleur est déterminée par la valeur (la position) du point le plus proche.
|
||||
|
||||
Pour aller plus loin, nous pouvons à présent ré-utiliser l'algorithme de [Steven Worley](http://www.rhythmiccanvas.com/research/papers/worley.pdf).
|
||||
|
|
|
|||
|
|
@ -0,0 +1,154 @@
|
|||

|
||||
|
||||
## Fractional Brownian Motion
|
||||
|
||||
Le bruit peut avoir plusieurs significations selon les personnes. Les musiciens le trouveront dérangeant, les communicants le considèrent comme une interférence et les astrophysiciens comme un rayonnement cosmique.
|
||||
|
||||
Toutes ces qualifications, nous ramènent à l'ancrage *physique* du bruit dans notre environnement. Commençons toutefois par quelque chose de plus simple et de plus fondamental ; les ondes et leurs propriétés.
|
||||
Une onde peut être considérée comme la variation d'une propriété dans le temps ; le son est une variation de la pression de l'air au fil du temps, une onde électro-magnétique est la fluctuation dans le temps d'un champs électrique et magnétique etc.
|
||||
Les deux caractéristiques importantes d'une onde sont sa *fréquence* et son *amplitude*.
|
||||
|
||||
L'équation d'une onde à une dimension peut s'écrire comme suit:
|
||||
|
||||
<div class="simpleFunction" data="
|
||||
float amplitude = 1.;
|
||||
float frequency = 1.;
|
||||
y = amplitude * sin(x * frequency);
|
||||
"></div>
|
||||
|
||||
* Essayez de changer les valeurs de fréquence et d'amplitude pour comprendre leurs effets.
|
||||
* À l'aide des fonctions de formes, faites varier l'amplitude au fil du temps.
|
||||
* Faites de même avec la fréquence.
|
||||
|
||||
Félicitations! en suivant les deux dernières instructions, vous avez réussi à "moduler" l'onde et à créer une modulation de fréquence (FM) et d'amplitude (AM), et oui, exactement comme des ondes radio!
|
||||
|
||||
Une seconde propriété intéressante des ondes est leur capacité à s'additionner, ce qu'on appelle la superposition.
|
||||
Commentez/décommentez et jouez avec les les lignes suivantes en vous intéressant à la forme que prend l'onde lorsqu'on la combine à d'autres.
|
||||
|
||||
<div class="simpleFunction" data="
|
||||
float amplitude = 1.;
|
||||
float frequency = 1.;
|
||||
y = sin(x * frequency);
|
||||
float t = 0.01*(-u_time*130.0);
|
||||
y += sin(x*frequency*2.1 + t)*4.5;
|
||||
y += sin(x*frequency*1.72 + t*1.121)*4.0;
|
||||
y += sin(x*frequency*2.221 + t*0.437)*5.0;
|
||||
y += sin(x*frequency*3.1122+ t*4.269)*2.5;
|
||||
y *= amplitude*0.06;
|
||||
"></div>
|
||||
|
||||
* Changez les valeurs de fréquence et d'amplitude des ondes additionnelles.
|
||||
* Pouvez vous créer deux ondes qui s'annulent? à quoi ressemblera l'onde finale?
|
||||
* Est-il possible d'additionner des ondes de manière à ce qu'elles s'amplifient l'une l'autre?
|
||||
|
||||
En musique, chaque note est associée à une fréquence particulière. Les fréquences correspondent aux _notes_ de musique et doubler ou diviser par deux une fréquence permet de changer d'_octave_.
|
||||
|
||||
Utilisons à présent un bruit de Perlin au lieu d'une sinusoïde!
|
||||
Un bruit de Perlin de base ressemble globalement à une sinusoïde.
|
||||
Son amplitude et sa fréquence varient un peu mais l'amplitude reste globalement la même tandis que la fréquence
|
||||
reste cantonnée dans une zone restreinte autour de la fréquence centrale.
|
||||
Cependant, ce n'est pas une sinusoïde régulière et il est plus simple d'atteindre un résultat pseudo-aléatoire
|
||||
en ajoutatnt plusieurs versions du bruit à différentes échelles (amplitudes).
|
||||
Il est possible d'obtenir le même résultat avec des sinusoïdes mais il est nécessaire de combiner un nombre d'ondes important pour masquer leur nature périodique.
|
||||
|
||||
En ajoutant différentes itérations du **bruit** (différents *octaves*),
|
||||
dont on augmente la fréquence (la *lacunarité*) et dont on réduit l'amplitude (le *gain*), on obtient une granularité
|
||||
qui nous permet de préserver les détails fins d'un bruit.
|
||||
|
||||
Cette technique s'appelle "Fractional Brownian Motion" (*FBM*) ou simplement *bruit fractal*
|
||||
Voici un exemple d'implémentation:
|
||||
|
||||
<div class="simpleFunction" data="// Properties
|
||||
const int octaves = 1;
|
||||
float lacunarity = 2.0;
|
||||
float gain = 0.5;
|
||||
//
|
||||
// Initial values
|
||||
float amplitude = 0.5;
|
||||
float frequency = 1.;
|
||||
//
|
||||
// Loop of octaves
|
||||
for (int i = 0; i < octaves; i++) {
|
||||
	y += amplitude * noise(frequency*x);
|
||||
	frequency *= lacunarity;
|
||||
	amplitude *= gain;
|
||||
}"></div>
|
||||
|
||||
* Changez progressivement le nombre d'octaves de 1 à 10 et regardez ce qui se produit.
|
||||
* Au delà de 4 octaves, changez la valeur de lacunarité.
|
||||
* toujours au delà de 4 octaves, changez le gain et observez le résultat.
|
||||
|
||||
Notez comment, à chaque nouvel octave, la courbe semble gagner en détail.
|
||||
Notez également lors de l'ajout d'octaves que lorsqu'on zoome sur la courbe, les plus petits éléments ressemblent à l'ensemble et inversement ; c'est ce qu'on appelle l'*auto-similarité*:
|
||||
C'est une propriété importante des fractales et nous la simulons dans notre boucle.
|
||||
Nous ne créons pas une fractale à proprement parler puisque nous arrêtons l'ajout de bruit après quelques itérations mais d'un point de vue théorique,
|
||||
si nous pouvions laisser la boucle tourner indéfiniment et ajouter une somme infinies de bruits, nous obtiendrions une courbe fractale.
|
||||
|
||||
Dans un shader, la finesse du détail est limitée par la résolution écran ; si le résultat devient plus petit qu'un pixel, il n'ya pas vraiment de raison (ni de moyen) de le représenter à l'écran.
|
||||
Nous avons donc pas besoin de boucles infinies pour obtenir une apparence fractale, il faut parfois un grand nombre d'itérations mais jamais une inifinité.
|
||||
|
||||
le code suivant est un exemple d'implémentation de **FBM** en 2 dimensions:
|
||||
|
||||
<div class='codeAndCanvas' data='2d-fbm.frag'></div>
|
||||
|
||||
* Réduisez le nombre d'octaves en changeant la ligne 37
|
||||
* Changez la lacunarité du FBM à la ligne 47
|
||||
* Changez le gain ligne 48
|
||||
|
||||
Cette technique est communément utilisée pour créer des terrains procéduraux.
|
||||
l'*auto-similarité* du FBM se prête bien au rendu de montagnes ; le processus d'érosion qui donne leur forme aux montagnes
|
||||
produit le même genre de motifs auto-similaires à grande échelle.
|
||||
|
||||
Si le sujet vous intéresse, nous vous invitons à lire [cet article d'Inigo Quiles sur les techniques de bruit avancées](http://www.iquilezles.org/www/articles/morenoise/morenoise.htm).
|
||||
|
||||

|
||||
|
||||
Le principe du **FBM** peut être amendé pour obtenir différents effets comme par exemple cette **turbulence**.
|
||||
On part de la structure de notre FBM mais au lieu d'accumuler la valeur signée(+/-) du bruit, on accumule sa valeur absolue(+) ce qui crée des *vallées* et des *collines*.
|
||||
|
||||
```glsl
|
||||
for (int i = 0; i < OCTAVES; i++) {
|
||||
value += amplitude * abs(snoise(st));
|
||||
st *= 2.;
|
||||
amplitude *= .5;
|
||||
}
|
||||
```
|
||||
|
||||
<a href="../edit.php#13/turbulence.frag"><img src="turbulence-long.png" width="520px" height="200px"></img></a>
|
||||
|
||||
Une seconde variante dite *ridge noise* (bruit de *crête* ou d'*arête*) consiste à inverser les vallées:
|
||||
|
||||
```glsl
|
||||
n = abs(n); // create creases
|
||||
n = offset - n; // invert so creases are at top
|
||||
n = n * n; // sharpen creases
|
||||
```
|
||||
|
||||
<a href="../edit.php#13/ridge.frag"><img src="ridge-long.png" width="520px" height="200px"></img></a>
|
||||
|
||||
Une autre variante consiste à multiplier les valeurs de bruit au lieu de les additionner.
|
||||
Il est intéressant de modifier l'échelle d'une itération de bruit en fonction du bruit de l'itération precédente.
|
||||
En faisant ce genre de chose, nous nous éloignons du monde des fractales et entrons dans le monde méconnu des *multifractales*.
|
||||
Les *multifractales* ne sont pas aussi clairement définies mathématiquement que les fractales ce qui ne nous empêche pas de nous en servir dans les shaders.
|
||||
Les simulations *multifractales* sont d'ailleurs très répandues dans les logiciels de génération de terrain.
|
||||
Vous trouverez plus d'informations sur ce sujet au chapitre 16 de "Texturing and Modeling: a Procedural Approach" (3ème édition), de Kenton Musgrave.
|
||||
Malheureusement le livre n'est plus édité depuis quelques années déjà mais vous le trouverez en bibliothèque ou d'occasion.
|
||||
Il est possible d'acheter un PDF de la première édition en ligne mais ça ne vaut pas le coup ; elle date de 1994 et ne contient aucune information sur la génération de terrain.
|
||||
|
||||
### Domain Warping
|
||||
|
||||
[Inigo Quiles a également écrit cet article fascinant](http://www.iquilezles.org/www/articles/warp/warp.htm) sur le fait de "plier" ou "recouvrir" (*wrap*) l'espace d'un FBM à l'aide d'un FBM.
|
||||
ce serait le *rêve dans le rêve* d'Inception.
|
||||
|
||||

|
||||
|
||||
Le code suivant est une variation moins spectaculaire de cette technique, on utilise le *wrapping* (pliage, recouvrement, emballage) pour créer une sorte de nuage.
|
||||
Notez la part que joue l'*auto-similarité* dans le résultat final.
|
||||
|
||||
<div class='codeAndCanvas' data='clouds.frag'></div>
|
||||
|
||||
Le fait de *wrapper* (plier, recouvrir, emballer) ainsi les coordonnées de textures peut être extrêmement utile, relativement amusant et terriblement dur à maîtriser.
|
||||
C'est un outil puissant qui demande beaucoup de pratique pour être correctement utilisé.
|
||||
["Flow noise", un célèbre article de Ken Perlin et Fabrice Neyret](http://evasion.imag.fr/Publications/2001/PN01/) explique comment utiliser les dérivées (ou dégradés) du bruit pour atteindre ce résultat.
|
||||
Les implémentations récentes du bruit de Perlin se servent à la fois de la fonction et de sa dérivée.
|
||||
Si la *vraie* dérivée n'est pas disponible, on peut toujours se rabattre sur les différences finies pour l'approcher bien que ce soit moins précis et demande plus de travail.
|
||||
|
|
@ -445,4 +445,4 @@ The textures coordinates follow this rule which might be counter-intuitive at fi
|
|||
Of course we could have gone deeper into the various concepts but as mentioned earlier, this is meant to give a BIG HUG to the newcomers.
|
||||
It's a quite a lot to ingest but with patience and practice, this will become more and more natural.
|
||||
|
||||
I hope you found some of this useful, now [what about starting your journey through the book?]("https://www.thebookofshaders.com/")
|
||||
I hope you found some of this useful, now what about starting your journey through the book?
|
||||
|
|
|
|||
Loading…
Reference in New Issue