Overview

Here, I’ll describe 2 approaches for generating looping noise, with examples in GLSL and Processing.

Applying noise to a surface is a way to give objects an organic, unpredictable look.

Noise functions don’t inherently loop. So to make perfect looping gifs, vj clips, repeatable entropy of sorts, you have to make the chaos loop.

I recommend reading The Book Of Shaders’ article on Noise if you haven’t already.

gif

Method 1: Interpolate between 2 noise functions

Although this is more expensive and naive, it’s nice for rapid prototyping, as it’s faster to implement, and you don’t need to modify any noise functions.

The idea is to have two noise functions, A and B, evolving over time and interpolate between the two. The second function, B, evolves such that it starts where function A began at every loop cycle.

Another useful thing is to define a transition start time, which defines the range in which the functions interpolate between each other. In the example below, the 2 second loop starts the transition at 1.5 seconds, therefore it will be a 0.5 second transition.

In GLSL, it looks like:

float loopLength = 2.;
float transitionStart = 1.5;
float time = mod(iGlobalTime, loopLength);

float v1 = noise(uv + time);
float v2 = noise(uv + time - loopLength);

float transitionProgress = (time-transitionStart)/(loopLength-transitionStart);
float progress = clamp(transitionProgress, 0., 1.);

// An improvement could be to use a curve to interpolate between the two
float result = mix(v1, v2, progress);

An example on Shadertoy can be seen below.

Method 2: Cycling the noise edges

To simplify, visualize in a single dimension. 1D Noise can generated by extracting the fractional and floored integer component of an increasing floating point number. The fractional component is used to interpolate between a random value generated by the current integer and the next one.

With this technique, the trick is to repeat the domain of the floored integers, such that it repeats a pattern of n “edges”.

This can be extended to 2D by repeating the domain of the square tile edges. Higher dimensions similarly.

Synchronize the noise evolve speed to scroll one tiles length per loop duration.

This gif was rendered as 30 frames with the duration of 1 second. I used Thomas Hooper’s Shadertoy Frame Exporter to export the frames.

Edge Cycling Example in Processing

processing

!!repo!!

Here’s an example that demonstrates looping noise applied to the radius of several concentric circles. The noise is feeded by the angle in which you are drawing around the circle.

Vector2[] segments = new Vector2[numSegments];

// Calculate the segments before drawing them to avoid calculating each one twice
for (int segment = 0; segment < numSegments; segment++) 
{
    float noiseParam = ((float)segment / numSegments) * noiseCycles;
    float angle = ((float)segment / numSegments) * PI * 2.0;      

    float r = radius + lnoise(noiseParam + circle*.001, noiseCycles) * noiseAmplitude;

    float x = centerX + cos(angle) * r;
    float y = centerY + sin(angle) * r;

    segments[segment] = new Vector2(x, y);
}    

// Draw the circle segments
for (int segment = 0; segment < segments.Count; segment++) 
{
    Vector2 s1 = segments[segment];
    Vector2 s2 = segments[segment+1];

    line(s1.x, s1.y, s2.x, s2.y);
}   

And then the implementation of the noise functions described above:

float seed = random(0, 50000);

float fract (float val) {
    return val - (long)val;
}

float lrandom (float val) {
    return fract(seed + sin(val) * 54275.5453123);
}

// 1D noise adapted from The Book Of Shader's
float lnoise(float x, float edges) {

    // cycle the edges
    x = x % edges;

    float i = floor(x); // floored integer component
    float f = fract(x); // fractional component
    float u = f*f*f*(f*(f*6.-15.)+10.); // use f to generate a curve

    // interpolate from the current edge to the next one wrt cycles
    return lerp(lrandom(i), lrandom((i + 1.0) % edges), u); 
}

I’ve pushed the example project to my Github. so you can check it out yourself. It’s by no means a library, but more of an example to checkout and build your own solutions.

Thanks for reading! If you have any questions, please send me an email.