Perlin Noise: The random numbers that shaped the landscape of the film industry
Background
I was recently inspired by a wonderful video by Primer, that simulates Natural Selection. Finding something very entertaining about the concept of playing god AND making fun graphs, I wanted to venture down the path of replicating this myself. Initially, scoping out the options, I went down the path of doing this in Unity, thinking this would be the most visually satisfying approach to accomplishing this goal. I’ve been teaching myself Javascript, but the thought of doing this with CSS grids just didn’t quite appeal to me for some reason.
So — approaching the project in Unity, I thought to myself: to begin I’ll need an environment for my creatures to live. Taking my first step into the rabbit hole, there were a few routes I could go down, but primarily either — a flat, grey, 2D plane, housing some grey blobby boys that run around, or, alternatively, one with mountains and oceans and beaches, housing plants and actual creatures. Having a general preference for Hawaii over the Blackwall Tunnel, my research into Perlin Noise began.
Perlin Noise
So the preface here is that Perlin Noise is excellent for procedurally generating terrain. The term “noise” even has a lot of different definitions. It can mean unwanted changes / obscurifications in audio or video, or even language itself (give semantic noise a Google, and then bare it in mind the next time you’re listening to a Conservative Party politician.) Or, simply, it could be Liam Gallagher.
Perlin Noise was created as a part of the original TRON film by a man named Ken Perlin. The invention of Perlin Noise revolutionised computer graphics almost entirely, giving the lead to photo-realistic landscapes in later years. This — and I think is extremely cool — inspired a certain man by the name of John Lasseter, the head of Pixar and Disney, who later described that the TRON film helped him “see the potential of computer-generated imagery in the production of animated films”. He literally said “without Tron, there would be no Toy Story.”
Think about the amount of films that wouldn’t have happened without Toy Story — or the lives that Toy Story changed. Perlin Noise had a genuine and palpable cultural impact.
To explain what exactly noise is, in the context of an intended message, be it audio, video, photo etc., my layman’s definition of it is that if our data is comprised of a nice [1, 2, 3, 4, 5], and noise occurs, our data might have some variation at the end, and result in [1, 2, 3.4, 3.9, 5]. This variation, is in essence, what noise is. If you have a particularly noisy photograph, it can add visible blemishes to the image.
Uniform noise is a form of continuous / rectangular distribution and a bunch of other stuff I didn’t really understand. In terms of something that everyone CAN understand, it’s essentially variation that is evenly spread out. Perlin Noise isn’t just the big daddy of noise — it’s the cool uncle too. Instead of random variations being added uniformly, Perlin Noise is gentle. It does pseudo-random numbers gently, with no big leaps in noise anywhere in particular. Let’s look at some exciting graphs:
This first one is just 100 pseudo-random numbers generated by Python:
This second one here, is one-dimensional Perlin Noise.
See? Exciting. Obviously, there’s a big difference: the Perlin Noise is significantly smoother. The difference between the numbers it generates is smaller than random. Say we had a grid of 10x10 grid of random numbers, the difference between each one is, well, pretty random. With Perlin Noise, the change between the numbers is gradual — gradient noise.
Ok — so the first graph looks like my heart rate when I look at a dog, and the second, well… a mountain range?
Using this Python code I found here, we can generate an array of 1024x1024 numbers that maps some Perlin Noise. Using the concepts in this delightful article, I instantly to saw how the wonderful thing that is Perlin Noise would help me generate a terrain. Taking a look at the numbers this array generated, below is the first 5x5 section that was generated.
As you can see, the change between each number on both axes is minimal, but large if we look at the number in the location [0,0] as opposed to [4,4], there is a clear difference; one that was gradually attained.
Now, we can begin to imagine how this might map to a terrain. If we imagine this 2D array of values shows us Y values, we can visualise how we can transition from this bunch of numbers to a three dimensional terrain. If we take each element in this 2D array as a pixel on a square, we can use the values to map to a corresponding colour.
If a number is below 0.3 we can show a dark blue for a deep ocean. If it’s between 0.3 and 0.4, we can show a light blue. 0.4 to 0.45 can be a yellow for sand, and 0.45 to 0.65 can be a green colour. 0.65 to 0.8 can be a light brown, 0.8 to 0.9 can be a dark brown and 0.9 to 0.1 can be white, for snow. Setting this up in Unity with C# was not too challenging, essentially already having the code to do so.
Drawing out the texture and applying it to a plane, we’ve already procedurally generated a lovely looking map.
OK, so now one last issue presents itself. How do we make this three dimensional? Well, in theory, there’s quite a simple answer to that question as described above. Being that the values of the map are just between 0–1, the 3D y-value can just be the numbers stored in the map array. We can just feed in a multiplier value to amplify the peaks and troughs and naturally, the white areas will be at the top, the dark blue oceans at the bottom, and everything in between will fit in to place.
After struggling for about 2 days with Unity and meshes, I eventually got something working. Using this tutorial to help understand how to set up the vertices and triangles of the mesh correctly (and following finding this tutorial, I ended up changing most of my code to be much more succinct), I was able to give my procedurally generated map, life.
My next step with this project is to establish some boundaries to this area, create a food chain including some randomly generated food sources. If anyone wants to do something similar, Sebastian Lague’s tutorials are something that I wish I found earlier in my journey.