143 lines
3.3 KiB
Markdown
143 lines
3.3 KiB
Markdown
# Cellular and Voronoi Noise
|
|
|
|
Distance-based noise for organic cell patterns. See `glsl-noise-random-perlin-simplex-cellular-voronoi.md` for random functions.
|
|
|
|
## Basic Cellular Noise
|
|
|
|
Distance to nearest feature point:
|
|
|
|
```glsl
|
|
float cellularNoise(vec2 st) {
|
|
vec2 i = floor(st);
|
|
vec2 f = fract(st);
|
|
|
|
float minDist = 1.0;
|
|
|
|
// Check 3x3 neighborhood
|
|
for (int y = -1; y <= 1; y++) {
|
|
for (int x = -1; x <= 1; x++) {
|
|
vec2 neighbor = vec2(float(x), float(y));
|
|
vec2 point = random2(i + neighbor);
|
|
vec2 diff = neighbor + point - f;
|
|
float dist = length(diff);
|
|
minDist = min(minDist, dist);
|
|
}
|
|
}
|
|
|
|
return minDist;
|
|
}
|
|
```
|
|
|
|
## Voronoi with Cell ID
|
|
|
|
```glsl
|
|
vec3 voronoi(vec2 st) {
|
|
vec2 i = floor(st);
|
|
vec2 f = fract(st);
|
|
|
|
float minDist = 1.0;
|
|
vec2 minPoint;
|
|
|
|
for (int y = -1; y <= 1; y++) {
|
|
for (int x = -1; x <= 1; x++) {
|
|
vec2 neighbor = vec2(float(x), float(y));
|
|
vec2 point = random2(i + neighbor);
|
|
vec2 diff = neighbor + point - f;
|
|
float dist = length(diff);
|
|
if (dist < minDist) {
|
|
minDist = dist;
|
|
minPoint = i + neighbor + point;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Returns: distance, cell id x, cell id y
|
|
return vec3(minDist, minPoint);
|
|
}
|
|
|
|
// Color cells by ID
|
|
vec3 voronoiColor(vec2 st, float scale) {
|
|
vec3 v = voronoi(st * scale);
|
|
return vec3(random(v.yz), random(v.yz + 1.0), random(v.yz + 2.0));
|
|
}
|
|
```
|
|
|
|
## Worley Noise (F1, F2)
|
|
|
|
```glsl
|
|
vec2 worleyNoise(vec2 st) {
|
|
vec2 i = floor(st);
|
|
vec2 f = fract(st);
|
|
|
|
float f1 = 1.0; // Nearest
|
|
float f2 = 1.0; // Second nearest
|
|
|
|
for (int y = -1; y <= 1; y++) {
|
|
for (int x = -1; x <= 1; x++) {
|
|
vec2 neighbor = vec2(float(x), float(y));
|
|
vec2 point = random2(i + neighbor);
|
|
float dist = length(neighbor + point - f);
|
|
|
|
if (dist < f1) {
|
|
f2 = f1;
|
|
f1 = dist;
|
|
} else if (dist < f2) {
|
|
f2 = dist;
|
|
}
|
|
}
|
|
}
|
|
|
|
return vec2(f1, f2);
|
|
}
|
|
```
|
|
|
|
## Worley Variations
|
|
|
|
```glsl
|
|
float worleyF1(vec2 st) { return worleyNoise(st).x; }
|
|
float worleyEdges(vec2 st) { vec2 w = worleyNoise(st); return w.y - w.x; }
|
|
float worleyBlobs(vec2 st) { vec2 w = worleyNoise(st); return w.x * w.y; }
|
|
```
|
|
|
|
## Animated Voronoi
|
|
|
|
```glsl
|
|
float animatedVoronoi(vec2 st, float time) {
|
|
vec2 i = floor(st);
|
|
vec2 f = fract(st);
|
|
|
|
float minDist = 1.0;
|
|
|
|
for (int y = -1; y <= 1; y++) {
|
|
for (int x = -1; x <= 1; x++) {
|
|
vec2 neighbor = vec2(float(x), float(y));
|
|
vec2 point = random2(i + neighbor);
|
|
// Animate point position
|
|
point = 0.5 + 0.5 * sin(time + 6.2831 * point);
|
|
float dist = length(neighbor + point - f);
|
|
minDist = min(minDist, dist);
|
|
}
|
|
}
|
|
|
|
return minDist;
|
|
}
|
|
```
|
|
|
|
## Distance Metrics
|
|
|
|
```glsl
|
|
float euclidean(vec2 v) { return length(v); }
|
|
float manhattan(vec2 v) { return abs(v.x) + abs(v.y); }
|
|
float chebyshev(vec2 v) { return max(abs(v.x), abs(v.y)); }
|
|
```
|
|
|
|
## Practical Applications
|
|
|
|
```glsl
|
|
// Cracked ground
|
|
vec3 crackedGround(vec2 st) {
|
|
float edges = worleyEdges(st * 5.0);
|
|
return mix(vec3(0.1), vec3(0.5, 0.4, 0.3), smoothstep(0.0, 0.05, edges));
|
|
}
|
|
```
|