Can someone explain noise() aka perlinNoise() function?

Hi!
How do I use noise()? I tried a few times but still nothing. I know you can enter a 1D, 2D or 3D input. but this happen


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

void draw() {
  for(int i = 0; i < width; i++) {
    for(int j = 0; j < height; j++) {
      stroke(noise(i,j)*255);
      point(i,j);
    }
  }
  noLoop();
}

the examples on reference page aren’t helping.

1 Like

I found the function noiseDetail() but I still don’t understand

Please see Understanding 2D Perlin noise

This will point you to understanding how the values are derived by the function initially and how to make use of it. Also coding train has some good introductions to perlin.

Also you might want to check javidx9 ’ channel who makes his own perlin noise in c++. Language is different but algorithm is sound.

You can imagine an endless (random) terrain which has hills and valleys. You will walk on the terrain forward and backward by supplying an input value ie. noise(x). What you get returned is the height on the terrain at that point between 0 and 1. You can use that value to set the color, set the position, etc. For instance, for color, multiply by 255 ie.noise(x) * 255.

You’re using the function correctly but at the “wrong scale”.

Scale down the noise inputs (so that the noise difference between successive pixels is lesser; i.e. the frequency is reduced) and you’ll get a more expected result:

final float scale = 0.01;

void draw() {
  for(int i = 0; i < width; i++) {
    for(int j = 0; j < height; j++) {
      stroke(noise(i*scale,j*scale)*255);
      point(i,j);
    }
  }
  noLoop();
}

Note that noiseDetail() doesn’t affect the “zoom” or the pattern at a coarse level, but affects the finer detail of the noise pattern – higher values for noiseDetail are more important the more “zoomed in” the noise is.

scaled inputs, with noiseDetail = 4 (default):

scaled inputs, with noiseDetail = 8:

However, back to your original image, the zoomed out view shows us that Processing’s noise function is terrible at large scales – we can clearly see it’s not randomly noisy (in the manner we would like) at all! (Why is perlin noise looping?)

As I describe in the topic Paul linked to, the 2D noise function gives you only a 16x16 grid of unique numbers, everything beyond that is a repetition of these numbers. Zooming in doesn’t really help, because you just get cosine interpolation between the unique values.

The best solution to get a reasonably random 2D pattern: either you use the 1D noise and run it over your whole area. This way you can work with at least 4096 unique values but you might not get good transitions between rows of values, because the noise values are not close to each other.
Or you use noise(i/1.5,j/1.5). This way you stretch out the pattern repetition, because you don’t end up at the same value in each 16x16 grid.

Changing the noiseDetail doesn’t really change the fundamental issue, because you use the same random numbers. The large range issues stay the same, because that is dominated by the first octave.
The short range might get more detailed but when you zoom into that, you will end up getting the same problems as in the large scale, because it is the same number.

Add:
However, in his presentation about his noise, Ken Perlin never used the noise directly. He actually plugged the results of his noise functions in other functions to get different effects for different surfaces. So that might be worth trying:
https://web.archive.org/web/20071011035810/http://noisemachine.com/talk1/

Looking at Processing’s noise implementation then…

…do the static noise values PERLIN_YWRAP and PERLIN_ZWRAP determine the period of the noise? Therefore setting these values to the width and height of the sketch would make noise repeat every width and height units?

How does PERLIN_SIZE = 4095 relate to this? I thought it could be saying we have a maximum of 4096 unique noise values between each pair of integers (therefore evaluating noise using values of 1/8192 and 2/8192 would give the same result) but this doesn’t quite match to up to my observations.

My first perlin noise program!

float m = 0.01,step = 10, r=5;
void setup() {
  size(600,600);
}
void draw() {
  background(0);
  stroke(0);
  for(int i = 0; i < width; i+=step) for(int j = 0; j < height; j+=step) {
    float dr = (noise(i*m,j*m)*TWO_PI);
    fill(noise(i*m,j*m)*255);
    circle(i,j,r*2);
    line(i+cos(dr)*r,j+sin(dr)*r,i,j);
  }
  noLoop();
}

1 Like

PERLIN_SIZE is 4095 but in getPerlin +1 is added. getPerlin creates your random number array. These are just normal random numbers but not gradients as in true perlin noise.

The critical line is of = x + 16 * y + 256 * z. PERLIN_YWRAPB and PERLIN_ZWRAPB are just the multipliers expressed with bit operators. x,y,z are the input parameters you entered in your noise function.

The variable of is used to pick the random number out of the array of 4096.
The equation makes sense, because for the 3D case you get 16x16x16 original values. However, that also means that for 2D, that of is the same for the pairs x=17, y=2 (of=49) and x=33 and y=1 (of=49).
For 2D you could use a multiplier of 64 (by changing PERLIN_YWRAPB). This would allow a 64x64 grid in the 4096 array.

You can easily check that by using noise(16 * i,j), which gives you diagonal lines.
noise(i,256 * j) and noise(16 * 256 * i,j) give you vertical or horizontal lines because you go beyond the 4096 threshold (see my code below).

Values between the integers are interpolated with cosine. So 1/8192 = 0.0001 would be interpolated between 0 and 1.

int gridsize=64;
float elevation;
float[][] mark = new float[gridsize][gridsize];

void setup(){
 size(700,700);
 background(125);
 dots();
}

void draw(){ 
  for (int i=0; i < gridsize;i++){
   for (int j=0; j < gridsize; j++){
     stroke(255, mark[i][j], mark[i][j]);
     strokeWeight(10);
     point(i*10+10,j*10+10);
     }
   }
 }

void dots(){
 for (int i=0; i < gridsize;i++){
   for (int j=0; j < gridsize; j++){
     noiseSeed(10);
     elevation = map(noise(i,256*j,0),0,1,0,255);
     mark[i][j] = elevation;
   }
 }
}