Perlin's Noise Algorithm
05 March 2023<br>Perlin's Noise Algorithm
What is Noise?
Well if you have tried to learn about anything in procedural generation one thing you must have come across is noise ! Now, what exactly is it?
Well, noise is nothing but a collection of random values.
To be honest, that is all there to noise at the core, but as you can guess it’s not that simple.
To be a bit more technical, noise is a function. A function that takes N parameters and gives us a value following some rules(rules depend on the algorithm we are talking about).
Now depending on the number of parameters we can classify noise into 1-Dimensional, 2-Dimensional, 3-Dimensional, etc. And the range of value it gives us also depends on the algorithm we are talking about.
Now there are several uses for each type of noise but according to me it’s easiest to work with 2D noise while implementing the algorithms in the first place as it’s really easy to visualize.
How?
Through textures (images)!
Once we have an algorithm setup for 2D we can generalize it to 1D, 3D, etc. (at least most of the time)
Ok, so how do we generate a texture using our noise function?
Here is some pseudocode:
for(int i = 0 ; i image.height ; i++)<br>for(int j = 0 ; j image.width ; j++)<br>float n = noise( (float)j / image.width , (float)i / image.height );<br>n = n / NOISE_MAX; // calculate noise in range [0, 1]<br>image.SetPixel(j, i, n, n, n); // set (R, G, B) values at pixel (j, i)<br>Now now, let us see what’s going on.
We loop throughout pixels and set them to the value generated by our noise function taking the x and y coordinates as input.
Now you may think why am I dividing the x and y coordinates by the width and height?
Well, it is to normalize them and map them to the [0, 1) range (open at one as i, j starts from 0 and goes only till width - 1, height - 1).
Why do we do it?
I can’t answer it just yet, so let’s just follow it blindly for now. In the future when we will be talking about applying transformations on these noise functions we will see how we can transform these parameters to transform the noise into something we want. But that’s something for the future.
Alright now, what about the noise function?
Let’s just try and use our rand() function from the previous article and see how it looks.
float noise(float x, float y)<br>return rand(x + y);<br>NOTE: We are using the x and y coordinates as the seed here.
The output:
Cool right?
Nope?
Well, you can say it’s not very interesting in itself, right?
What do I mean?
Well, everything is very random and we can’t distinguish any particular pattern or any feature.
So, what do I mean by interesting?
Let’s see,
So, it seems a bit more interesting, right?
As you can now distinguish some features or patterns yet the thing is quite random in itself right?
It’s termed Coherent Noise.
It is a smooth version of our previous noise functions using rand() (a pseudo-random noise function)
There are some basic properties of a coherent noise function:
Passing in the same input value will always return the same output value (same for almost all noise algorithms)
A small change in the input value will produce a small change in the output value
A large change in the input value will produce a random change in the output value
Perlin’s Noise Algorithm
Well, there are several algorithms to generate coherent noise and we will be covering them one by one.
But undoubtedly the most famous of all noise algorithms is Perlin Noise .
To quote some history about this from Wikipedia,
Ken Perlin developed Perlin noise in 1983 as a result of his frustration with the “machine-like” look of computer-generated imagery (CGI) at the time. He formally described his findings in a SIGGRAPH paper in 1985 called An Image Synthesizer. He developed it after working on Disney’s computer animated sci-fi motion picture Tron (1982) for the animation company Mathematical Applications Group (MAGI). In 1997, Perlin was awarded an Academy Award for Technical Achievement for creating the algorithm.
NOTE: The implementation of the Perlin Noise algorithm in this article is from here
Alright, getting into the algorithm.
So, we know that the input to our noise function will be 2 numbers on the 2D plane.
So, as you can see from the above graph, every point in the 2D plane is inside a square whose corners coordinates are the nearest integers to the coordinates of the point.
We can easily get the coordinates of the four corners of the square using:
We have our point as
P=(x,y)P = (x, y)P=(x,y)
Now our corner coordinates of the square are:
P0=(floor(x),floor(y))P_0 = (floor(x), floor(y))P0=(floor(x),floor(y))
P1=(floor(x),floor(y)+1)P_1 = (floor(x), floor(y) + 1)P1=(floor(x),floor(y)+1)
P2=(floor(x)+1,floor(y))P_2 = (floor(x) + 1, floor(y))P2=(floor(x)+1,floor(y))
P3=(floor(x)+1,floor(y)+1)P_3 = (floor(x)+1, floor(y)+1)P3=(floor(x)+1,floor(y)+1)
Now Perlin’s algorithm states that for each of these four points, we have...