Unity ID

A Unity ID allows you to buy and/or subscribe to Unity products and services, shop in the Asset Store, and participate in the Unity community.

Notifications

A guide

Introduction

Perlin noise is an unsung mathematical construct that is vital in many graphical effects in movies and games. This theorem is the brainchild of Ken Perlin as part of a quest to create truer to life CGI for the original Tron movie in 1982. For this mathematical prowess, he received an Oscar for Technical achievement. The genius of Perlin noise is the way it converts random vectors in the nth dimension and converts it to controlled geometric constructs. Prior to Perlin noise random noise was used for many effects. The primary problem with random noise is that it was unrealistic and looked more like static than a realistic graphical effect. Therefore, Perlin noise is most commonly used in rendering natural phenomena such as smoke, water, and tree shaders. More recently, it has gained popularity to render terrain in procedural videogames such as Minecraft.

As aforementioned Perlin noise can be generated in any dimension. When contrasting Perlin noise to random noise one can see the difference in smoothness and continuity. See the Image I generated below for reference. When I generated the noise images I took much care to be accurate. However, in the 3rd dimension this chart may be misleading to the unfamiliar observer. The images pictured are examples of terrain Perlin noise, meaning that they are extruded as 3D meshes along only the y axis with a weight coefficient using the formula for only 2D Perlin noise. True 3D Perlin noise along all axis is beyond the scope of this paper, but for reference it resembles a smoke clouds.

Function 2D 3D terrain

Getting Started with Perlin noise

Code wise a standard 2D Perlin noise method takes in two arguments for an x and y position and returns a Decimal weight value that can be translated into a shade of grey or a height value.

Mathf.PerlinNoise(Xcord, Ycord);

However, by itself, this method only returns a value for only one pixel or mesh vertex. To remedy this the user needs to specify both the size of the image and the resolution of the Perlin noise kernel. A kernel is a matrix that is inscribed on top of the image that contains all the Perlin noise data. A Kernel is comprised of cells that have 4 random vectors each. The quality of the Perlin noise is directly tied the cell count and resolution. Resolution is usually set as an input variable that changes the scale of the image. For simplicity both the kernel and the image are perfect squares.

The Perlin Noise Plane is mathematically infinite therefore when rendering a Kernel, it is best to add offset to the X and Y values to add variance. This is how one would animate the noise to resemble waves for instance. The x offset moves the image left and right and the y offset up and down. These actions would create as scrolling effect as they are incremented.

This is a formula for generating a specific instance of Perlin Noise at a specified kernel and image resolution at a specified offset.

float Xcord = (float)x / gridsize * size + offsetx;

float Ycord = (float)y / gridsize * size + offsety;

In Layman’s terms, this script references both the kernel(size) and the image (gridsize) resolution to find a specific coordinate (offsets) of Perlin Noise. The variables are in floating notation to create high decimal accuracy. This process is repeated for all the pixels in the image to form the Perlin pattern.

The Mathematical Journey of a lone pixel

What is pictured below is one cell in a kernel that has a resolution of 16 pixels. In this explanation, we will find the value of the pixel at (2,1). For this demonstration, first start with 4 random vectors called gradient vectors (colored in yellow). These vectors originate from the 4 corners of the Kernel cell (colored in green). The aim is to find the value of the pixel (colored in blue)

To begin round the gradient vectors to the nearest horizontal or diagonal orientation for best effect.

For example, these vectors are recommended for Perlin noise because of their more realistic outcome. Also, they are less stress for the computer to handle computationally.

Next, calculate the distance vectors to the desired pixel from the 4 points on the kernel. To do this we need to convert the coordinates into a decimal value of 1 therefore (2,1) becomes (.66,.33)

Now calculate the distance vectors (colored in red) to the desired pixel. After the desired pixel has all its distance vectors it is time to take the dot product of both the distance and gradient vector at each point (A,B,C,D)

The Table below is an example of the work that is needed to complete this phase of the pixels journey to becoming part of a Perlin pattern.

The dot products of all the points are useful in the bilinear interpolation. Bilinear interpolation is a linear interpolation along two dimensions. Meaning that fist find the 2 points of interpolation on the x axis (colored in purple). This is done by taking the dot products taken in the previous step. Next repeat the process for the Y interpolation between the purple circles.

One example formula for finding the linear interpolation for the kernels is

See the chat below for the answer to the bilinear interpolation.

Finally, there is a weight that is given as a result, in this case it is returned as a negative fraction. However, since this value is a pixel color or topography height, it needs to be a positive decimal. And after the conversion this process is completed for every pixel in every cell of the Kernel it will look like this.

This image does not resemble Perlin noise because of a quirk of bilinear interpolation called artifacting. In the above image, one can clearly see the edges of each cell of the kernel. This issue could be solved by Cosine interpolation. However, for processing reasons Perlin noise uses a polynomial fade function as seen below.

When .148 is plugged into the fade function the value returned is .2215. This means that if the value of each pixel is put through this function all artifacting will be removed and make an image like this.

One final point of this process that is important to mention is that the above math is just for 1 pixel in 1 kernel cell in 1 kernel. However, for a full image this process had to be replicated thousands of times a second with thousands of pixels and sometimes within multiple simulations noise maps. This may be a limitation for this paper, but it inspires awe at the process of a computer.

Process and personal engagement

As a budding computer scientist, I have had a fascination with the math behind many of mundane the things I encounter in my daily life. With that in mind I made a point of creating most of the images seen in this paper. (figures, 2,3,5,6,7,8,9,10,11,12,14) To generate the noise I used a Unity scene with Scripts written in C#. To generate the Kernel examples, I used Adobe Illustrator. Finally, to generate the fade function I used a custom script written in Python with the aim to find the optimal pixel value. As you can see I have used many tools to express the intricacies of Perlin noise. This project incorporates the practical applications of art and computational rendering to explain an unsung theorem.

Bibliography

Noise, being a pseudorandom artist. (n.d.). Retrieved January 11, 2018, from http://catlikecoding.com/unity/tutorials/noise/

Perlin Noise Explained Tutorial 2. (2017, January 14). Retrieved January 11, 2018, from https://www.youtube.com/watch?v=MJ3bvCkHJtE

Ken’s Blog. (n.d.). Retrieved January 11, 2018, from http://blog.kenperlin.com/

(Mathematician’s blog)

Image credits

M. (2016, March 03). Thermal Expansion for Minecraft 1.9/1.8 (Team CoFH Mods). Retrieved January 11, 2018, from http://minecraftplanet.tumblr.com/post/140364174944/thermal-expansion-for-minecraft-1918-team-cofh

Glossary. (n.d.). Retrieved January 11, 2018, from http://libnoise.sourceforge.net/glossary/

Other Projects