Files
english/.opencode/skills/shader/references/glsl-cellular-voronoi-worley-noise-patterns.md
2026-04-12 01:06:31 +07:00

3.3 KiB

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:

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

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)

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

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

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

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

// 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));
}