Lesson Six: Perlin Noise

If people do not believe that mathematics is simple, it is only because they do not realize how complicated life is.

John von Neumann


Not sure if I agree with this quote but well…

via GIPHY

Did you every start to feel the sweat beading on your forehead the moment your teacher called you up to the board to write out the solution to the latest algebra assignment? — YES

Does the mere mention of the word “calculus” cause a trembling sensation in your extremities? — YES

Modulus

modulo operator written as %

Modulus keeps a value with a certain range. The modulo operator calculates the remainder when one number is divided by another. It can be used when you need to cycle a counter variable back to zero. It is useful when counting through the elements of an array one at a time, returning to zero when getting to the length of an array.

20 / 6 = 3 remainder 2
or 6*3+2=20

20 modulo 6 equals 2
or 20 % 6 = 2

17 / 4 = 4 remainder 117 % 4 = 1
3 / 5 = 0 remainder 33 % 5 = 3
10/3.75=2 remainder 2.510% 3.75 = 2.5
100/50= remainder100% 40 =
9.25/0.5= remainder9.25 % 0.5 =

if A = B % C then A can never be larger than C. The remainder can never be greater than or equal to the divisor.

x = x + 1; 
if (x >= limit {
   x = 0;
}

or using modulo

x = (x + 1) % limit;

Random numbers

The random numbers you get with random() are not truly random but pseudo-random. It is a mathematical function which simulates randomness.

Perlin noise

A little mit of lifelike quality randomness but not too much randomness.

// syntax
noise(x)
noise(x, y)
noise(x, y, z)

I looked up a few of the references related to noise on the Processing website.

noiseDetail()

Adjusts the character and level of detail produced by the Perlin noise function. Similar to harmonics in physics, noise is computed over several octaves. Lower octaves contribute more to the output signal and as such define the overall intensity of the noise, whereas higher octaves create finer-grained details in the noise sequence. https://processing.org/reference/noiseDetail_.html
float noiseVal;
float noiseScale=0.02;

void draw() {
  for (int y = 0; y < height; y++) {
    for (int x = 0; x < width/2; x++) {
      noiseDetail(3,0.5);
      noiseVal = noise((mouseX+x) * noiseScale, (mouseY+y) * noiseScale);
      stroke(noiseVal*255);
      point(x,y);
      noiseDetail(8,0.65);
      noiseVal = noise((mouseX + x + width/2) * noiseScale, 
                       (mouseY + y) * noiseScale);
      stroke(noiseVal * 255);
      point(x + width/2, y);
    }
  }
}
// syntax 

noiseDetail(lod)
// 	int: number of octaves to be used by the noise

noiseDetail(lod, falloff)
// 	float: falloff factor for each octave

noiseWave()

NoiseWave from the reference. Not sure if I can implement it somewhere at some time but it’s good to have it all in one place https://processing.org/examples/noisewave.html

float yoff = 0.0;        // 2nd dimension of perlin noise

void setup() {
  size(640, 360);
}

void draw() {
  background(51);

  fill(255);
  // We are going to draw a polygon out of the wave points
  beginShape(); 
  
  float xoff = 0;       // Option #1: 2D Noise
  // float xoff = yoff; // Option #2: 1D Noise
  
  // Iterate over horizontal pixels
  for (float x = 0; x <= width; x += 10) {
    // Calculate a y value according to noise, map to 
    float y = map(noise(xoff, yoff), 0, 1, 200,300); // Option #1: 2D Noise
    // float y = map(noise(xoff), 0, 1, 200,300);    // Option #2: 1D Noise
    
    // Set the vertex
    vertex(x, y); 
    // Increment x dimension for noise
    xoff += 0.05;
  }
  // increment y dimension for noise
  yoff += 0.01;
  vertex(width, height);
  vertex(0, height);
  endShape(CLOSE);
}

noiseSeed()

Sets the seed value for noise(). By default, noise() produces different results each time the program is run. Set the seed parameter to a constant to return the same pseudo-random numbers each time the software is run. https://processing.org/reference/noiseSeed_.html

float xoff = 0.0;

void setup() {
  noiseSeed(0);
  stroke(0, 10);
}

void draw() {
  xoff = xoff + .01;
  float n = noise(xoff) * width;
  line(n, 0, n, height);
}
// syntax 

noiseSeed(seed)

Back to the book…

Prints the same value over and over because result is asked at the same time.

float t = 0.0; 
void draw() {
float noiseValue = noise(t); 
println(noiseValue);
}

Increment time value t. The speed of increment determines the smoothness of the noise.

float t = 0.0; 
void draw() {
  float noiseValue = noise(t); 
  println(noiseValue);
  t += 0.01;
}
// Example 13-4: Perlin noise

float time = 0.0;
float increment = 0.01;

void setup() {
  size(500, 500);
}

void draw() {
  background(0);

  // Get a noise value at "time" and scale it according to the window's width.
  float n = noise(time) * width;

  // With each cycle, increment the " time "
  time += increment;

  // Draw the ellipse with size determined by Perlin noise
  fill(255);
  ellipse(width/2, height/2, n, n);
}

Exercise 13-3: Complete the following code that uses Perlin noise to set the location of a circle. Run the code. Does the circle appear to be moving “naturally”?

I first played around with my idea of the answer but eventually had to look it up on the learningprocessing.com website. When I see the code I kinda get what is happening but it was a bit hard for me to complete. But well, I’m tired…

// Noise "time" variables 
float xtime = 0.0; 
float ytime = 100.0; 

float increment = 0.01; 

void setup() {
  size(500, 500);
}

void draw() {
background(0); 
float x = noise(xtime) * width; 
float y = noise(ytime) * height; 
xtime += increment; 
ytime += increment;  

// Draw the ellipse with the location determined by Perlin noise 
fill(255); 
ellipse(x,y,32,32);
}

Inspiration

Also I found this on giphy and kinda love it. Wondering if I can recreate it. Technically, it shouldn’t be too complicated but I had other plans for my experiments 😀

via GIPHY


Recap

I finished the chapter about Perlin noise and looked up some extra references. I definitely need to look up some videos on his YouTube channel to expand my knowledge and general understanding of the topic. I hope it gets more clear when working on the script and my own experiments. It’s not like I’m super confused and I also can’t really pin point specific questions so I’m just trying to understand it by experimenting with the exercises from the script and whatever else I can find.