Procedural Generation

Cellular (Voroni Distance) Noise

Voroni distance noise separates regions of space into 'cells' by taking the distance from some target point, to the closest 'feature point' around it. Outside of a shader, the points may just be a set of data, a list of coordinates in space. Inside of a shader, we can't really use a set of points, so we have to build them. We first set up a lattice that we sample from, much like how coherent noise works, so we can get the same sets of points.

Example Lattice

The purple points are the 'Feature' points, and the blue lines connect them to their lattice points.

Local Feature Neighborhood
t p f1

All of the 'feature' points are looked at, and compared to the target point.

Then, the distance of the closest feature point is used as the value of the noise.

Many variants of this noise instead use the second or third point distances.

Other variants use the difference between the distances of the first and second point.

(NVidia Cg)
//Using orignal hash function defined in part 1...
float hash3(float3 v) { return hash(v.x + v.y * 113.0 + 153 * v.z); }
float voronif1(float3 v) {
    float3 p = floor(v);
    float3 f = frac(v);
	
    float closest = 2.0;
    for (int k = -1; k <= 2; k++) {
        for (int j = -1; j <= 2; j++) {
            for (int i = -1; i <= 2; i++) {
                float3 sampleOffset = float3(k, j, i);
                float3 featureDiff = sampleOffset - f + hash3(p + sampleOffset);
                float dist = length(featureDiff);
                if (dist < closest) { closest = dist; }
            }
        }
    }
    return closest;
}
Adaptation of closest-point voroni distance noise.

Looking at the code for the 3d closest-point voroni distance noise, we can see it samples a 4x4x4 space of points. For the single-closest point, changing this down to only the 2x2x2 neighborhood around the point probably wouldn't cause the output to be any different. However, when moving into the second closest point, it may cause some difference.

(NVidia Cg)
//Using orignal hash function defined in part 1
//and the hash3 function defined above...
float voronif2(float3 v) {
    float3 p = floor(v);
    float3 f = frac(v);
    
    float closest = 2.0;
    float second = 2.0;
    for (int k = -1; k <= 2; k++) {
        for (int j = -1; j <= 2; j++) {
            for (int i = -1; i <= 2; i++) {
                float3 sampleOffset = float3(k, j, i);
                float3 featureDiff = sampleOffset - f + hash3(p + sampleOffset);
                float dist = length(featureDiff);
                if (dist < closest) { second = closest; closest = dist; }
                if (dist < second) { second = dist; }
            }
        }
    }
    return second;
}
Adaptation of second-closest-point voroni distance noise.

There is also a variant that would return second-closest, as well as variants that use the 'manhattan distance' rather than eculidean distance.

Just below is a grid of 8 variants of voroni noise. Each of these variants uses a slight variation of the noise function. The worley noise version uses the difference between the first two distances (second - first).

Manhatten Voroni Distance Noise
Closest-Point Voroni Distance Noise
Second-Closest Voroni Distance Noise
"Worley" Voroni Distance Noise
1 - (Above noise)

We can also make a generalized function that can calculate various kinds of voroni noises.

(NVidia Cg)
//Mode constants
#define NORMAL 0
#define MANHATTAN 1

float voroni(float3 v, float3 shift, float4 comp, int distMode) {
    //Integer and fracional components
    float3 p = floor(v);
    float3 f = frac(v);
    
    //Closest point distances
    float3 closest = float3(2.0, 2.0, 2.0);
    
    //Loop over the (4x4x4) local neighborhood
    for (int k = -1; k <= 2; k++) {
        for (int j = -1; j <= 2; j++) {
            for (int i = -1; i <= 2; i++) {
                //Offset of current sample
                float3 sampleOffset = float3(i,j,k);
                //Difference to current feature point
                float3 featurePoint = sampleOffset - f + (shift * hash3(p + sampleOffset));
                
                float dist = 0.0;
                //Different distance modes
                if (distMode == MANHATTAN) {
                    //Uses the highest cardinal direction distance
                    featurePoint = abs(featurePoint);
                    dist = max(max(featurePoint.x, featurePoint.y), featurePoint.z);
                } else if (distMode == NORMAL) {
                    //Otherwise uses the eculidean length
                    dist = length(featurePoint);
                }
                
                //Properly track the closest 3 point distances
                if (dist < closest.x) { 
                    closest.z = closest.y; 
                    closest.y = closest.x; 
                    closest.x = dist; 
                } else if (dist < closest.y) { 
                    closest.z = closest.y; 
                    closest.y = dist; 
                } else if (dist < closest.z) { closest.z = dist; }
            }
        }
    }
    //Combine the 3 distances based on the 'comp' parameter
    return comp.w * abs(comp.x * closest.x + comp.y * closest.y + comp.z * closest.z);
}
//Some functions that use the above function with different parameters
float manhattan(float3 v) { return voroni(v, float3(1,1,1), vec4(-1,1,.30,1.), MANHATTAN); }
float manhattan3(float3 v) { return voroni(v, float3(1,1,1), vec4(-1,.5,.5,1.7), MANHATTAN); }
float voroni1f(float3 v) { return voroni(v, float3(1,1,1), vec4(1,0,0,.8), NORMAL); }
float voroni2f(float3 v) { return voroni(v, float3(1,1,1), vec4(0,1,0,.8), NORMAL); }
float worley(float3 v) { return voroni(v, float3(1,1,1), vec4(-1,1,0,1.5), NORMAL); }

More modular version of the noise function
Manhatten Distance version
Euclidean Distance version
1-(above)

Using this programmable function, many more noise fields can be used (and, even better, switched between without having to recompile the shader program!). This may become useful to create many effects. Some examples might be The segmenting for stained glass or uneven stone tiles, cellular 'fleshy' textures, and even the patterns of circuit boards can be created using various voroni distance noise fields.