Worley Noise
Worley Noise1 (also known as Voronoi noise or Cellular noise) was introduced by Steven Worley2 in 1996 as a type of procedural noise function.
Its appearance resembles biological cells, which is why the author originally called it “Cellular Texture.”
The algorithm for generating Worley Noise works as follows: the image is divided into a grid of cells, and each cell contains a single feature point. The value of any given pixel is the minimum distance from that pixel to the feature points in the surrounding cells.
Since each cell contains only one feature point, each pixel only needs to check the 9 neighboring cells, making it a comparison of just 9 points in total.
Here are two examples of its use in games3: a cracked desert floor and an exaggerated billowing smoke column.

Shadertoy
For this implementation, I mainly learned from Suboptimal Engineer4 and The Book of Shaders5, while writing the actual code on Shadertoy6.
Additionally, iquilezles7 has a wealth of useful references on graphics programming.
Grid Code
Open Shadertoy and start with the following code:
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
vec3 col = vec3(0.0);
fragColor = vec4(col,1.0);
}
This simply displays a black screen.
Next, transform the coordinates into square grid coordinates, where each cell spans the range $[-0.5, +0.5]$.
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
vec2 uv = fragCoord/iResolution.y;
uv = uv * 4.0;
vec2 gird = floor(uv);
vec2 coord = fract(uv) - 0.5;
vec3 col = vec3(coord, 0);
fragColor = vec4(col,1.0);
}
Now color each pixel based on its distance from the edges of the grid cell.
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
vec2 uv = fragCoord/iResolution.y;
uv = uv * 4.0;
vec2 gird = floor(uv);
vec2 coord = fract(uv) - 0.5;
float distanceGrid = 2.0 * max(abs(coord.x), abs(coord.y));
vec3 col = vec3(distanceGrid);
fragColor = vec4(col,1.0);
}
Finally, only highlight the grid boundaries and tint them red.
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
vec2 uv = fragCoord/iResolution.y;
uv = uv * 4.0;
vec2 gird = floor(uv);
vec2 coord = fract(uv) - 0.5;
float distanceGrid = smoothstep(0.9, 1.0, 2.0 * max(abs(coord.x), abs(coord.y)));
vec3 girdColor = vec3(1.0, 0, 0) * vec3(distanceGrid);
vec3 col = girdColor;
fragColor = vec4(col,1.0);
}
Cell Code
Next, we need to do two things:
- Use a pseudo-random function to determine the position of the feature point in each cell.
- For each pixel, compute the distance to feature points in the 9 neighboring cells and take the minimum.
First, render the feature points, with one point per cell.
vec2 random2( vec2 p )
{
// add 0.5 to avoid vec2(0, 0) return (0, 0)
return fract(sin(vec2(dot(p + 0.5, vec2(213.1,322.2)),dot(p + 0.5, vec2(513.1,312.2))))*51312.1234);
}
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
vec2 uv = fragCoord/iResolution.y;
uv = uv * 4.0;
vec2 gird = floor(uv);
vec2 coord = fract(uv) - 0.5;
// Gird Color
float distanceGrid = smoothstep(0.9, 1.0, 2.0 * max(abs(coord.x), abs(coord.y)));
vec3 girdColor = vec3(1.0, 0, 0) * vec3(distanceGrid);
// Cell Color
float distancePoint = 1.0;
for (int i=-1; i<=1; i++)
{
for (int j=-1; j<=1; j++)
{
vec2 near = vec2(float(i), float(j));
vec2 point = near + 0.5 * sin(iTime + 6.2831 * random2(gird + near));
float currentDistance = length(coord - point);
distancePoint = min(currentDistance, distancePoint);
}
}
vec3 pointColor = vec3(smoothstep(0.90, 1.0, 1.0 - distancePoint));
vec3 col = girdColor + pointColor;
fragColor = vec4(col,1.0);
}
Once we have the distance, we can simply map it to a color.
vec2 random2( vec2 p )
{
// add 0.5 to avoid vec2(0, 0) return (0, 0)
return fract(sin(vec2(dot(p + 0.5, vec2(213.1,322.2)),dot(p + 0.5, vec2(513.1,312.2))))*51312.1234);
}
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
vec2 uv = fragCoord/iResolution.y;
uv = uv * 4.0;
vec2 gird = floor(uv);
vec2 coord = fract(uv) - 0.5;
// Gird Color
float distanceGrid = smoothstep(0.95, 1.0, 2.0 * max(abs(coord.x), abs(coord.y)));
vec3 girdColor = vec3(1.0, 0, 0) * vec3(distanceGrid);
// Cell Color
float distancePoint = 1.0;
for (int i=-1; i<=1; i++)
{
for (int j=-1; j<=1; j++)
{
vec2 near = vec2(float(i), float(j));
vec2 point = near + 0.5 * sin(iTime + 6.2831 * random2(gird + near));
float currentDistance = length(coord - point);
distancePoint = min(currentDistance, distancePoint);
}
}
vec3 pointColor = vec3(smoothstep(0.95, 1.0, 1.0 - distancePoint));
vec3 distanceColor = vec3(smoothstep(0.2, 2.0, 1.7 - distancePoint));
vec3 col = girdColor + pointColor + distanceColor;
fragColor = vec4(col,1.0);
}
Finally, if we remove the helper grid and the feature points, we get the actual Worley Noise image.
Palettes
Lastly, we can add some colors through gradient interpolation8.
vec3 palette( in float t)
{
vec3 a = vec3(0.5, 0.5, 0.5);
vec3 b = vec3(0.5, 0.5, 0.5);
vec3 c = vec3(1.0, 1.0, 1.0);
vec3 d = vec3(0.0, 0.1, 0.2);
return a + b * cos( 6.283185 * ( c * t + d ) );
}
vec2 random2( vec2 p )
{
// add 0.5 to avoid vec2(0, 0) return (0, 0)
return fract(sin(vec2(dot(p + 0.5, vec2(213.1,322.2)),dot(p + 0.5, vec2(513.1,312.2))))*51312.1234);
}
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
vec2 uv = fragCoord/iResolution.y;
uv = uv * 4.0;
vec2 gird = floor(uv);
vec2 coord = fract(uv) - 0.5;
// Gird Color
float distanceGrid = smoothstep(0.95, 1.0, 2.0 * max(abs(coord.x), abs(coord.y)));
vec3 girdColor = vec3(1.0, 0, 0) * vec3(distanceGrid);
// Cell Color
float distancePoint = 1.0;
for (int i=-1; i<=1; i++)
{
for (int j=-1; j<=1; j++)
{
vec2 near = vec2(float(i), float(j));
vec2 point = near + 0.5 * sin(iTime + 6.2831 * random2(gird + near));
float currentDistance = length(coord - point);
distancePoint = min(currentDistance, distancePoint);
}
}
vec3 pointColor = vec3(smoothstep(0.95, 1.0, 1.0 - distancePoint));
vec3 distanceColor = vec3(palette(smoothstep(0.2, 2.0, 1.7 - distancePoint)));
vec3 col = distanceColor;
col += girdColor + pointColor;
fragColor = vec4(col,1.0);
}
wikipedia, Worley noise, https://en.wikipedia.org/wiki/Worley_noise ↩︎
Steven Worley, (1996), A Cellular Texture Basis Function, https://cedric.cnam.fr/~cubaud/PROCEDURAL/worley.pdf ↩︎
Por Ryan Brucks, (2016) , Getting the Most Out of Noise in UE4, https://www.unrealengine.com/es-ES/tech-blog/getting-the-most-out-of-noise-in-ue4 ↩︎
Suboptimal Engineer, (2023), What is Voronoi Noise? , https://www.youtube.com/watch?v=vcfIJ5Uu6Qw&ab_channel=SuboptimalEngineer ↩︎
Patricio Gonzalez Vivo and Jen Lowe, The Book of Shaders, https://thebookofshaders.com/12/ ↩︎
Shadertoy, https://www.shadertoy.com/ ↩︎
iquilezles, float small and random, https://iquilezles.org/articles/sfrand/ ↩︎
iquilezles, palettes - 1999, https://iquilezles.org/articles/palettes/ ↩︎