Week 8: Perlin Noise – an uncanny algorithm

Perlin Noise, an algorithm invented by movie special effects researcher Kevin Perlin, has an unparalelled capacity to create forms that are intrinsically organic. In this Workshop we explore its possibilities.

bec53823f8a325dedc6cf52ffd5e0aba

This below work, by early computer artist Manfred Mohr, was not generated using Perlin noise. Can you see how it was made?

stocking
“Zerreissprobe”, black nylon stocking on cardboard, 1960, 35cm x 50cm, Private Collection, Germany © 1960 by Manfred Mohr

Understand Perlin Noise

Perlin Noise is a fractal order. That is to say, it is an order in which self-similarity is exhibited at different scales. However, instead of the self-similarity being a line or a shape, it is in the amount of randomness.

So if you have the same amount of randomness at different scales like this:

 float x = random(1) + random(10) + random(100) + random(1000);

Here you have the basis for Perlin Noise. Another key characteristic of Perlin Noise is that neighbouring values have a relation to each other. This is a bit like a wave motion, where a wave is made up of values that have a relation to the neighbouring value.

In the image below, notice how each wave is randomised at different scales? Perlin Noise simply involves summing up each of these waves to achieve the wave shown at the bottom.

In the image below, a 3D wave is randomised. The image on the left shows a randomisation at only 1 scale. In the middle image, its randomness is applied at two different scales. In the third image, three different scales. Notice how the third image starts to exhibit characteristics that appear very similar to real-world landscapes?

Perlin Noise

Exercise

Find an example of Perlin Noise and see if you can understand exactly what might be being randomised at different scales.

You might try searching in:

  • graphic design
  • art
  • film special effects
  • computer game design

Can you find a use of Perlin Noise that doesn’t involve a visual element?

Processing Code Samples

In the below code a grid of random circles are drawn in a grid. Execute the code on your own computer and make sure that you understand everything by commenting each of the lines.

What do you notice about the randomness of the circles? They have no relation to each other!

void setup(){
 background(255); size(800,600); 
 strokeWeight(0.4); noFill(); 
 noLoop(); 
}

void draw() {
 
 float radius = 0;
 
 for (int i = 0 ; i < 800 ; i = i + 20){
  for (int j = 0 ; j < 600 ; j = j + 20){
   radius = random(20);
   ellipse(i,j, radius, radius);
  }
 } 
}

Processing has already ‘abstracted’ Perlin Noise for us. That is to say, Processing makes it very easy for us to use Perlin Noise simply by calling a function:

noise(float x, float y);

x and y can be simply as the coordinates of a map.

Be careful! … the above function will always return a value between 0 and 1. In other words, it is very likely that you will need to multiply the results of the noise function by some other value to bring it into a usable range.

Now, copy and paste the below code into your computer and see how the random circles have taken on a very different character. Now, the randomness of each circle is tied to the value of the circles next to it.

void setup(){
 size(800,600);
 background(255);
 noFill(); strokeWeight (0.4);
 noLoop(); 
}

float radius, resolution = 180;

void draw() {
 background(255);
 for (int i = 0 ; i < 800 ; i = i + 20){
  for (int j = 0 ; j < 600 ; j = j + 20){
   radius = noise(i / resolution, j / resolution) * 30;
   ellipse(i,j, radius, radius);
  }
 }
 
}

Comment the above lines of code until you understand what each line does.

What else might you drive using Perlin Noise? You could try:

  • line thickness
  • colour variations
  • opacity
  • different shapes sizes
  • circle location instead of circle size
  • etc.

What would happen if we were to try to draw polylines, where each point was varied using Perlin Noise? Try the below code:

void setup() {
 size(800, 600); background(255);
 noFill(); strokeWeight (0.1);
 noLoop();
}

float perlinResolution = 400;

void draw() {

for (int lineCount = 0; lineCount < 600; lineCount = lineCount + 4) {
  beginShape();
  for (int i = 0; i < 800; i = i + 4) { 
   vertex( i, noise( i / perlinResolution, lineCount / perlinResolution) * 600 );
  }
  endShape();
 }
}

Other resources to understand Perlin Noise

Noise, flows and generative art

Continue Iterating on your project

Remember that successful creative practice is driven by a pattern of iterative development. In other words, the best way to create engaging visual designs is to continually explore, changing small aspects of your design, always observing the produced result independently from your intentions!

 

One thought on “Week 8: Perlin Noise – an uncanny algorithm

  1. void setup() {
    size(800, 600); background(255);
    noFill(); strokeWeight (0.1);
    // noLoop();
    // frameRate(10); //slow down code refresh rate
    }
    float movement = 0;
    float perlinResolution = 400;
    float radius, resolution = 180;
    float t= 0;

    void draw() {
    //Try un-commenting the functions one at a time below to observe the code
    DrawPerlinLines();
    //PerlinNoise();
    //DrawPerlinRect();
    //DrawPerlinEllipse();
    //PerlinNoiseEllipse();
    //PerlinNoiseRect();
    //MovingEllipse();
    //PerlinEllipse();
    // clouds();

    // PerlinNoise();
    }

    void DrawPerlinLines() {

    for (int lineCount = 0; lineCount < 600; lineCount = lineCount + 20) {
    for (int i = 0; i < 800; i = i + 20) {
    radius = noise(i / resolution, lineCount / resolution) * 30;
    line(i,lineCount, radius, radius+30);
    }
    }
    }

    void DrawPerlinRect() {
    for (int lineCount = 0; lineCount < 600; lineCount = lineCount + 20) {
    for (int i = 0; i < 800; i = i + 20) {
    radius = noise(i / resolution, lineCount / resolution) * 30;
    rect(i,lineCount, radius, radius);
    }
    }
    }

    void DrawPerlinEllipse() {
    for (int lineCount = 0; lineCount < 600; lineCount = lineCount + 20) {
    for (int i = 0; i < 800; i = i + 20) {
    radius = noise(i / resolution, lineCount / resolution) * 30;
    ellipse(i,lineCount, radius, radius);
    }
    }
    }

    void PerlinNoiseEllipse() {
    for (int lineCount = 0; lineCount < 600; lineCount = lineCount + 4) {
    beginShape();
    for (int i = 0; i < 800; i = i + 4) {
    vertex( i, noise( i / perlinResolution, lineCount / perlinResolution) * 600 );
    radius = noise(i / resolution, lineCount / resolution) * 30;
    ellipse(i,lineCount, radius, radius);
    }
    endShape();
    }
    }

    void PerlinNoiseRect(){
    for (int lineCount = 0; lineCount < 600; lineCount = lineCount + 4) {
    beginShape();
    for (int i = 0; i < 800; i = i + 4) {
    vertex( i, noise( i / perlinResolution, lineCount / perlinResolution) * 600 );
    radius = noise(i / resolution, lineCount / resolution) * 30;
    rect(i,lineCount, radius, radius);
    }
    endShape();
    }
    }

    void MovingEllipse(){
    background(0);
    fill(255);
    float x = random(width);
    ellipse(x, height/2, 40, 40);
    }

    void PerlinEllipse(){
    background(0);
    fill(255);
    // t=t+1;
    //t=t+0.5;
    t=t+0.01;
    float x = noise(t);
    x = map(x,0,1,0,width);
    ellipse(x, height/2, 40, 40);
    }

    void clouds() {
    movement = movement + 0.01;
    background(255);
    for (int i = 0 ; i < 800 ; i = i + 5) {
    for (int j = 0 ; j < 600 ; j = j + 5) {
    // randomise colour using Perlin noise
    fill(noise(i / resolution, j / resolution) * 255,
    noise(i / resolution / 8, j / resolution / 8) * 255,
    noise(i / resolution / 64, j / resolution / 64) * 255);

    radius = noise(i / resolution + movement, j / resolution) * 12;

    ellipse(i, j, radius, radius);
    }
    }
    }

    void PerlinNoise() {
    for (int lineCount = 0; lineCount < 600; lineCount = lineCount + 4) {
    beginShape();
    for (int i = 0; i < 800; i = i + 4) {
    vertex( i, noise( i / perlinResolution, lineCount / perlinResolution) * 600 );
    }
    endShape();
    }
    }

Leave a Reply

Your email address will not be published. Required fields are marked *