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 par la communauté des développeurs graphiques.
Pour ce faire, nous pouvons utiliser une boucle `for` pour itérer sur un tableau de points et conserver la distance minimum en nous servant de la fonction [```min()```](../glossary/?search=min).
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.
![](cell-01.png)
Une façon d'aborder le problème est de diviser l'espace en *tuiles* (**tiles**) ou *cellules*.
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.
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
for (int y= -1; y <= 1; y++) {
for (int x= -1; x <= 1; x++) {
// cellules voisines
vec2 neighbor = vec2(float(x),float(y));
...
}
}
```
![](cell-02.png)
Nous pouvons prévoir la position des points des cellules adjacentes en ajoutant les deltas `x` et `y` de la boucle `for` aux indices de la cellule courante.
On peut s'en servir pour calculer la position du point de la cellule en cours de traitement dans la boucle grâce à la méthode `random2()` décrite plus haut.
```glsl
...
// Random position from current + neighbor place in the grid
Pour le reste, il suffit de calculer la distance entre ce point et le fragment et de conserver le minimum dans une variable ```m_dist``` (*minimal distance*).
*"... it might be worth noting that there's a nice trick in this code above. Most implementations out there suffer from precision issues, because they generate their random points in "domain" space (like "world" or "object" space), which can be arbitrarily far from the origin. One can solve the issue moving all the code to higher precision data types, or by being a bit clever. My implementation does not generate the points in "domain" space, but in "cell" space: once the integer and fractional parts of the shading point are extracted and therefore the cell in which we are working identified, all we care about is what happens around this cell, meaning we can drop all the integer part of our coordinates away all together, saving many precision bits. In fact, in a regular voronoi implementation the integer parts of the point coordinates simply cancel out when the random per cell feature points are subtracted from the shading point. In the implementation above, we don't even let that cancelation happen, cause we are moving all the computations to "cell" space. This trick also allows one to handle the case where you want to voronoi-shade a whole planet - one could simply replace the input to be double precision, perform the floor() and fract() computations, and go floating point with the rest of the computations without paying the cost of changing the whole implementation to double precision. Of course, same trick applies to Perlin Noise patterns (but i've never seen it implemented nor documented anywhere)."*
En résumé : on subdivise l'espace en cellules, chaque fragment va calculer sa distance au point dans sa cellule ainsi qu'aux 8 cellules adjacentes et conserver la plus courte.
Le champ de distance final est visible dans l'exemple suivant :
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'algorithme canonique de ce genre de formes a été trouvé par [Georgy Voronoi](https://en.wikipedia.org/wiki/Georgy_Voronoy) et porte maintenant son nom.
Construire un diagramme de Voronoi à partir d'un bruit cellulaire est plus simple qu'il n'y paraît.
Il nous faut simplement conserver certaines informations en plus ; nous allons conerver le point le plus proche dans un ```vec2``` appelé ```m_point```.
```glsl
...
if( dist <m_dist){
m_dist = dist;
m_point = point;
}
...
```
Notez que nous n'utilisons plus la fonction ```min``` pour conserver la distance au point le plus proche mais que nous nous servons d'une condition ```if```.
Pourquoi ? Parce que nous avons besoin de modifier la référence au point le plus proche (```m_point```) à chaque fois qu'un point est plus proche que le précédent (lignes 32 à 37).
![Accretion Disc Series - Clint Fulkerson](accretion.jpg)
![Vonoroi Puzzle - Reza Ali (2015)](reza.png)
### Améliorer Voronoi
En 2011, [Stefan Gustavson a optimisé l'algorithme de Steven Worley sur le GPU](http://webstaff.itn.liu.se/~stegu/GLSL-cellular/GLSL-cellular-notes.pdf) en n'utilisant que des kernels de 2x2 au lieu de 3x3.
Cela amoindrit la charge de manière significative mais peut créer des artefacts et des discontinuités. Visibles dans l'exemple suivant:
Plus tard, en 2012 [Inigo Quilez a écrit un article expliquant comment trouver des frontières précises](http://www.iquilezles.org/www/articles/voronoilines/voronoilines.htm).
Inigio ne s'est pas arrété là et en 2014, il a écrit un article sur ce qu'il a appelé le [voro-noise](http://www.iquilezles.org/www/articles/voronoise/voronoise.htm) ; une exploration combinant bruit et cellules de Voronoi.
*"Despite this similarity, the fact is that the way the grid is used in both patterns is different. Noise interpolates/averages random values (as in value noise) or gradients (as in gradient noise), while Voronoi computes the distance to the closest feature point. Now, smooth-bilinear interpolation and minimum evaluation are two very different operations, or... are they? Can they perhaps be combined in a more general metric? If that was so, then both Noise and Voronoi patterns could be seen as particular cases of a more general grid-based pattern generator?"*