# [Perlin noise: What is it, how to use it, and why it's better than value noise.](https://blog.hirnschall.net/perlin-noise/)

author: [Sebastian Hirnschall](https://blog.hirnschall.net/about/)

meta description: How Perlin noise generates smooth randomness — gradient noise vs value noise, computational cost, and practical use in terrain generation and animation.

meta title: Perlin Noise Explained — How It Works & When to Use

date published: 27.08.2020 (DD.MM.YYYY format)
date last modified: 03.04.2026 (DD.MM.YYYY format)

---

What is Perlin Noise
--------------------

Perlin noise is a type of gradient noise that can be used to generate "smooth" randomness in one or more dimensions. This is why it is often used in the movie and special effects industry for procedural texture generation. It was developed by Ken Perlin in 1983. He was later awarded an Academy Award for Technical Achievement for creating the algorithm.

![Visualization of 1d perlin noise](https://blog.hirnschall.net/perlin-noise/resources/img/perlin-noise-1d.png)


(a) plot of Perlin Noise




![Visualization of 1d random variables](https://blog.hirnschall.net/perlin-noise/resources/img/random-1d.png)


(b) plot of random numbers



Figure 1.1: Comparing Perlin Noise to random numbers (p5js random() and noise())

As you can see in fig 1.1 \(noise(x),x\in\mathbb{R}\) is a continuous function. In other words, Perlin noise can be used to generate a more "controlled" form of randomness.

### How Gradient Noise Works

To generate the random, continuous function \(noise(x):\mathbb{R}^n\to\mathbb{R}^n\)  we start with a set of random vectors (gradients)

$$g\_u\in\mathbb{R}^n,u\in\mathbb{Z}^n.$$

As the name gradient noise implies we now set

$$noise'(u)=g\_u$$
$$noise(u)=0.$$

We can now interpolate to find \(noise(x),\forall x\in\mathbb{R}^n\).

![How 1d gradient noise works](https://blog.hirnschall.net/perlin-noise/resources/img/noise-1d-gradients.png)


Figure 2.1: Resulting interpolant for one-dimensional noise

As you can see in fig. 2.1 the resulting function \(noise(x)\) is zero if \(x=u\). To get a better result we take a linear combination of \(M\) weighted noise functions with different frequencies

$$Noise(x)=\sum\_{i=0}^{M-1}a\_i\cdot noise(f\_i\cdot x)$$

where \(a\_i\) is a weight (amplitude) and \(f\_i\) is a frequency. These terms are called octaves.

[


Animation of linear combinations of perlin noise
](resources/vid/linearcombination/linearcombination.webm)

### Octaves used in this animation:

![perlin noise octave 1](https://blog.hirnschall.net/perlin-noise/resources/img/noise-o1.png)


![perlin noise octave 2](https://blog.hirnschall.net/perlin-noise/resources/img/noise-o2.png)


![perlin noise octave 3](https://blog.hirnschall.net/perlin-noise/resources/img/noise-o3.png)


![perlin noise octave 4](https://blog.hirnschall.net/perlin-noise/resources/img/noise-o4.png)

### Result:

![perlin noise combination of 4 octaves](https://blog.hirnschall.net/perlin-noise/resources/img/noise-total.png)

### How Value Noise Works

The apparently "often confused with" value noise works in a similar way to gradient noise. We start with a grid of random points

$$g\_u\in\mathbb{R}^n,u\in\mathbb{Z}^n.$$

In contrast to gradient noise we demand that

$$noise(u)=g\_u.$$
As with gradient noise, we then use the interpolant to calculate \(noise(x),x\in\mathbb{R}^n\). To get a better result we can use a linear combination of \(M\) different octaves (with different weights, \(a\_i\) and frequencies \(f\_i\)).
$$Noise(x)=\sum\_{i=0}^{M-1}a\_i\cdot noise(f\_i\cdot x)$$

### Gradiant Noise vs Value Noise

In short: As gradient (Perlin) noise emphasizes frequencies around and above the grid spacing it will, in general, lead to a visually more appealing result.

One problem with value noise can be its random nature. The result might look ugly if too many gridpoints have a similar value.

For more information on gradient noise vs value noise take a look at [this answer on StackExchange.](https://math.stackexchange.com/q/184153)

### Computational complexity

As we have seen above, to evaluate \(noise(x),x\in\mathbb{R}^n\) (n-dimensional Perlin noise), we have to interpolate between the \(2^n\) nearest grid points. We will later see that this can be done by calculating the dot-product of the gradient assigned to each of these points and \(x\). Afterward, we interpolate linearly between the results and apply an ease curve.

As all of these operations scale with complexity \(\mathcal{O}(n)\) the algorithm scales with complexity \(\mathcal{O}(2^n)\) for \(n\) dimensions.

When to use Perlin Noise?
-------------------------

Perlin noise is typically used to make things look more realistic or live like. As most things in nature do not change instantaneous, using a normal random number generator is not a good option. As we have seen Perlin noise is a continuous ("smooth") function and therefore the result looks much more natural.

For more flexibility, we may use different dimensions of Perlin noise. You can see some example use cases below:

| Dimension | Visualization | Example usage |
| --- | --- | --- |
| 1 | 1d perlin noise | 1d Perlin noise can be used to make a straight line look hand-drawn or make movement look more realistic (no instant speed changes, no perfectly straight lines, etc.) |
| 2 | 2d perlin noise | 2d perlin noise for terrain generation in minecraft   2d Perlin noise is often used to generate terrain, textures, or flowfields. |
| 3 | 3d perlin noise | 3d perlin noise for cave generation in minecraft   3d Perlin noise can be used to generate caves (like those in Minecraft) or for animating textures etc. that use 2d noise |

How to use Perlin Noise
-----------------------

### Implementation

If the language you are using does not have Perlin noise as a built-in function you can either use [Ken Perlin's reference implementation](https://mrl.nyu.edu/~perlin/noise/) to implement it yourself or check [github.com](https://github.com/search?q=perlin+noise) if someone else already did all the work.

If you are using unity you can use Mathf.PerlinNoise(float x, float y).

### Using Perlin noise (for animations)

In contrast to \(random()\), \(noise(t)\) will return the same value for a given \(t\) no matter how often we call it. To get different results we increment \(t\). We can control the smoothness by how quickly we increment \(t\).

![perlin noise timestep expanation](https://blog.hirnschall.net/perlin-noise/resources/img/timesteps.png)


Figure 3.1: Timesteps [1]

If we need more than one noise value \(x:=noise(t\_1)\) and \(y:=noise(t\_2)\) we can use a large offset between \(t\_1\) and \(t\_2\). You can see how this works in fig. 3.2 below:

![multiple different perlin noise results](https://blog.hirnschall.net/perlin-noise/resources/img/different-results.png)


Figure 3.2: Different values [1]

### Mapping the result

Depending on the implementation the noise function will return a value \(x\) in a given intervall\([a,b],a<b\). This is not what we want for most usecases. If we want a value between \(c\) and \(d\) with \(c<d\), we can map the intervall \([a,b]\) to \([c,d]\) using

$$map(x,a,b,c,d) := \frac{(x-a)(d-c)}{b-a}+c.$$

Some languages have this function already implemented (p5js for example).

### Terrain generation

Let's start with a triangulation of a plane (fig. 3.3 (a)). We can now use 2d Perlin noise to assign a random z value (height) to each vertex (x,y). To control the smoothness we can divide both x and y by some constant s. We will also map the result of noise(x,y), a value between 0 and 1 (in p5js), to a value between minheight and maxheight to control the min and max height of the terrain we generate. You can see the result in fig. 3.3 (b).

![terrain generation without using perlin noise](https://blog.hirnschall.net/perlin-noise/resources/img/terrain-flat.png)


(a) constant height value


![terrain generation using perlin noise](https://blog.hirnschall.net/perlin-noise/resources/img/terrain-perlin.png)


(b) height with Perlin noise



Figure 3.3: Terrain generation using Perlin noise

```
    for(var y =0;y<height/w;++y){
  beginShape(TRIANGLE_STRIP);
  for(var x =0;x<=width/w;++x){
    vertex(x*w,j*w,map(noise(x/s,y/s),0,1,minheight,maxheight));
    vertex(x*10,(y+1)*w,map(noise(x/s,(y+1)/s),0,1,minheight,maxheight));
  }
  endShape();
}
```

Listing 3.1: Example code to generate terrain with Perlin noise

### Animation

Using the example above we'll start with a terrain (or texture) \(T=**(x,y,noise(x,y)):x\in[a,b],y\in[c,d]**\). If you are not familiar with this notation, it means the terrain (or texture) \(T\) is a set of points \((x,y)\) and their corresponding noise value \(noise(x,y)\). If we want this terrain (or texture) to change smoothly we can:

* change the x,y values to scroll the terrain (or texture) in one direction
* use a third dimension as time

Using 3d Perlin noise, we know that \(noise(x,y,t\_1)\) will be close to \(noise(x,y,t\_2)\), if \(t\_1\) is close to \(t\_2\). So, we use 2d nosie to create the terrain/texture and animate it using a third dimension. You can see the result below:

[


Animated terrain using 3d Perlin noise
](resources/vid/animation.webm)


(a) using an extra dimension


[


Animated terrain using 2d Perlin noise
](resources/vid/animation-scrolling.webm)


(b) scrolling



Figure 3.4: Different animation approaches (looped video)

### More examples

For more examples take a look at [these posts](https://blog.hirnschall.net/?q=perlinnoise) on my blog:

* [Coding Challenge #2: Flow-simulation](https://blog.hirnschall.net/flow-simulation-js/)
* [How to make perfectly looping gifs - with perlin noise](https://blog.hirnschall.net/perfect-looping-gif/)