If you're seeing this message, it means we're having trouble loading external resources on our website.

If you're behind a web filter, please make sure that the domains *.kastatic.org and *.kasandbox.org are unblocked.

Main content

Perlin noise

A good random number generator produces numbers that have no relationship and show no discernible pattern. As we are beginning to see, a little bit of randomness can be a good thing when programming organic, lifelike behaviors. However, randomness as the single guiding principle is not necessarily natural.
There's an algorithm that results in more natural results, and that's known as “Perlin noise". Ken Perlin developed the noise function while working on the original Tron movie in the early 1980s; he used it to create procedural textures for computer-generated effects. In 1997, Perlin won an Academy Award in technical achievement for this work. Perlin noise can be used to generate various effects with natural qualities, such as clouds, landscapes, and patterned textures like marble.
Perlin noise has a more organic appearance because it produces a naturally ordered (“smooth”) sequence of pseudo-random numbers. The graph below shows Perlin noise over time, with the x-axis representing time; note the smoothness of the curve.
Nature of Code Image
Figure I.5: Noise
Contrastingly, the next graph below shows pure random numbers over time.
Nature of Code Image
Figure I.6: Random
ProcessingJS has a built-in implementation of the Perlin noise algorithm: the function noise(). The noise() function takes one, two, or three arguments, as noise is computed in one, two, or three dimensions. Let’s start by looking at one-dimensional noise.

Noise Detail

The noise reference tells us that noise is calculated over several “octaves.” Calling the noiseDetail() function will change both the number of octaves and their importance relative to one another. This in turn changes how the noise function behaves.
Consider drawing a circle in our ProcessingJS window at a random x-location:
var x = random(0, width);
ellipse(x, 180, 16, 16);
Now, instead of a random x-location, we want a Perlin noise x-location that is “smoother.” You might think that all you need to do is replace random() with noise(), i.e.
var x = noise(0, width);
ellipse(x, 180, 16, 16);
While conceptually this is exactly what we want to do—calculate an x-value that ranges between 0 and the width according to Perlin noise—this is not the correct implementation. While the arguments to the random() function specify a range of values between a minimum and a maximum, noise() does not work this way. Instead, noise() expects us to pass in an argument that signifies a "moment in time," and always returns a value between 0 and 1.  We can think of one-dimensional Perlin noise as a linear sequence of values over time. For example, here are example inputs and return values:
TimeNoise Value
00.469
0.010.480
0.020.492
0.030.505
0.040.517
Now, in order to access one of those noise values in ProcessingJS, we have to pass a specific moment in time to the noise() function. For example:
var n = noise(0.03);
According to the above table, noise() will return 0.505 at the time of 0.03. We can write a program that stores a time variable and requests that noise value continuously in draw().
The above code results in the same value printed over and over. This happens because we are asking for the result of the noise() function at the same point in time over and over.
If we increment the time variable t, however, we’ll get a different result.
The rate at which we increment t also affects the smoothness of the noise. If we make large jumps in time, then we are skipping ahead and the values will be more random.
Noise over time
Figure 1.7
Try running the code above several times, incrementing t by 0.01, 0.02, 0.05, 0.1, 0.0001, and you will see different results.

Mapping Noise

Now we’re ready to answer the question of what to do with the noise value. Once we have the value with a range between 0 and 1, it’s up to us to map that range to what we want.
We could just multiply by the max number in the range, but this is also a good opportunity to introduce the ProcessingJS’s map() function, which will help us in more situations later on. The map() function takes five arguments. First up is the value we want to map, in this case n. Then we have to give it the value’s current range (minimum and maximum), followed by our desired range.
Nature of Code Image
Figure I.8
In this case, we know that noise has a range between 0 and 1, but we’d like to draw a rectangle with a width between 0 and the current width.
We can apply the exact same logic to our random walker, and assign both its x- and y-values according to Perlin noise.
Notice how the above example requires an additional pair of variables: tx and ty. This is because we need to keep track of two time variables, one for the x-location of the Walker object and one for the y-location.
But there is something a bit odd about these variables. Why does tx start at 0 and ty at 10,000? While these numbers are arbitrary choices, we have very specifically initialized our two time variables with different values. This is because the noise function is deterministic: it gives you the same result for a specific time t each and every time. If we asked for the noise value at the same time t for both x and y, then x and y would always be equal, meaning that the Walker object would only move along a diagonal. Instead, we simply use two different parts of the noise space, starting at 0 for x and 10,000 for y so that x and y can appear to act independently of each other.
Nature of Code Image
Figure I.9
In truth, there is no actual concept of time at play here. It’s a useful metaphor to help us understand how the noise function works, but really what we have is space, rather than time. The graph above depicts a linear sequence of noise values in a one-dimensional space, and we can ask for a value at a specific x-location whenever we want. In examples, you will often see a variable named xoff to indicate the x-offset along the noise graph, rather than t for time (as noted in the diagram).
In the next challenge, you'll try using noise with the Walker in a slightly different way. Have fun!

This "Natural Simulations" course is a derivative of "The Nature of Code" by Daniel Shiffman, used under a Creative Commons Attribution-NonCommercial 3.0 Unported License.

Want to join the conversation?

  • old spice man blue style avatar for user kevinlyang01
    How does the map function work?
    (60 votes)
    Default Khan Academy avatar avatar for user
    • piceratops ultimate style avatar for user Jasper
      With regards to the actual implementation, map converts between two linear scales given two equivalent points. Here is an example implementation:
      var map = function(x, imin, imax, omin, omax) {
      var irange = imax - imin;
      var scaled = (x - imin) / irange;
      var orange = omax - omin;
      return scaled * orange + omin;
      };

      This function first takes the input value x from the input scale to a (0,1) scale by subtracting imin and dividing by irange. This value is stored in scaled. scaled is then converted to the output scale by multiplying by orange and adding omin.
      (12 votes)
  • duskpin ultimate style avatar for user John Lee
    How do you finish Noisy step walker? I have been keep trying and I can't seem to get it.
    (24 votes)
    Default Khan Academy avatar avatar for user
    • leafers tree style avatar for user Falconer3 ✝
      //this is the solution:
      //i figured it out by looking at other people's suggestions and experimenting with the values.
      //my logic: since we are now dealing with stepsizes instead of the location of the walker on the screen, the 4th and 5th map values obviously need to be smaller. what's more, the 4th one needs to be negative, since we dont want him to go off the screen.
      var Walker = function() {
      this.x = width/2;
      this.y = height/2;
      this.tx = 0;
      this.ty = 1000;
      };

      Walker.prototype.display = function() {
      strokeWeight(1);
      stroke(0, 0, 0);
      point(this.x, this.y);
      };

      Walker.prototype.walk = function() {

      var xStepSize = map(noise(this.tx), 0, 1, -4, 4);
      var yStepSize = map(noise(this.ty), 0, 1, -4, 4);

      this.x += xStepSize;
      this.y += yStepSize;

      this.tx += 0.01;
      this.ty += 0.01;
      };

      var w = new Walker();

      draw = function() {
      w.walk();
      w.display();
      };
      (9 votes)
  • leaf green style avatar for user Jacob Mikkelsen
    Playing around with the walker code on this page, I found that if you change the increment of tx and ty to an integer, the walk doesn't move at all! However, if you set it to be a value with a decimal, restart, and then change it to an integer at run-time it will move as expected (a lot!)

    Is this a bug?
    (12 votes)
    Default Khan Academy avatar avatar for user
    • leaf green style avatar for user Kyle
      No this isn't a bug, it's actually due to how Perlin noise is implemented.

      Without going into too much detail, part of the Perlin noise function (in the one dimensional case) multiplies the decimal-part of the input by a pseudorandom value associated with the integer-part of the input. Since the decimal-part of a whole number is 0, this value becomes 0 which influences the rest of the function such that it will always output 0.

      If you have the motivation/time I'd recommend looking into what the Perlin noise function actually does behind the scenes. The 2D case is probably the easiest to understand in geometric terms and once you get it, you can easily extend it to n dimensions.

      I realize this question is 3 years old and the poster might already know this by now, but wanted to give the correct answer for any other readers.
      (30 votes)
  • hopper cool style avatar for user Daiwei Wang
    I am stuck in the Noisy Step Walker Challenge. Could anyone help me? Here's what I put:

    var Walker = function() {
    this.x = width/2;
    this.y = height/2;
    this.tx = 0;
    this.ty = 10000;
    };

    Walker.prototype.display = function() {
    stroke(0, 0, 0);
    point(this.x, this.y);
    };

    Walker.prototype.walk = function() {

    var this.x = map(noise(this.tx), 0, 1, 0 , width);
    var this.y = map(noise(this.ty), 0, 1, 0, width);

    this.x += 0.01;
    this.y += 0.01;
    };

    var w = new Walker();

    var draw = function() {
    w.walk();
    w.display();
    };

    When I did this there's a orange letter on top of my program that says:
    Synax Error!

    Could you fix my mistakes? Thanks!
    (7 votes)
    Default Khan Academy avatar avatar for user
  • aqualine seed style avatar for user K B
    In the last program, we have code line

    this.x = map(noise(this.tx), 0, 1, 0, width);


    then x can have any value and start at any point. Then why it is always starting at (200, 200)?
    (7 votes)
    Default Khan Academy avatar avatar for user
  • hopper cool style avatar for user Britt
    If you restart the walker program over and over again, it will keep drawing the same pattern. I thought this would give us a different pattern each time?!
    (6 votes)
    Default Khan Academy avatar avatar for user
  • hopper jumping style avatar for user Bushra R. Khan
    why are those specific numbers used for the noise values? EX. .01 = .469
    (7 votes)
    Default Khan Academy avatar avatar for user
  • hopper jumping style avatar for user abhishek994sharma
    this.y = map(noise(this.ty), 0, 1, 0, height);


    in above example <i>this.ty</i> is" 10000" then how could its minimum and maximum value be 0 & 1 respectively ?
    (4 votes)
    Default Khan Academy avatar avatar for user
  • leaf orange style avatar for user apex [still active]
    I still do not understand how map() works. ;-;

    I've read what Bob Lyon said with his answer, but it still doesn't quite make sense. Is there a better explanation that could be put in the most basic term possible?

    I think it's most confusing to us because it's taught in the same lesson as noise, so we confuse the two, even though they are seperate commands with seperate functions.

    Help would be great.

    Have a blessed day everyone!
    (4 votes)
    Default Khan Academy avatar avatar for user
    • leaf red style avatar for user Cavan P
      It essentially takes a value and squeezes it to be within bounds that you set.

      The first argument will be the variable you wish to adjust, say you have variable a assigned to a value of 50.
      The second two arguments are the initial range of this variable. Let's say a is constrained to a range between 0 and 100.
      The final two arguments are the range we want to adjust the value to - say 0 and 1.

      Our function looks like this:
      map(a, 0, 100, 0, 1);
      which produces an output of 0.5 (remember, a was given a value of 50, so this output makes sense).
      (4 votes)
  • area 52 purple style avatar for user Legowar || Thrawn
    Can you input negative values into noise?
    (2 votes)
    Default Khan Academy avatar avatar for user