Making things look natural
Noise is a pseudo-random function for generating values. Many phenomenon in the real world are noisy, meaning that there is some kind of random variation, such as static on a phone call. Clever people realized this and started using computational noise functions to add realism to computer graphics and other simulations of reality. One very simple approach, Perlin Noise (named after Ken Perlin), proved extremely effective and showed that simple noise can be very powerful.
Noise is ubiquitous in generating natural-looking materials such as clouds, wood and stone. It also is used for natural-looking distributions, such as where branches and leaves grow on a plant or the shape of lakes.
Recent games such as Mojang's Minecraft have brought procedural generation of maps into popular use. The image on the right is from a research game that several students have been working on with me, where we use noise functions to determine tile placement (including water) and plant distribution.
In this lab, you'll be playing with some noise functions, to get more experience with functions and image manipulation.
Some additional reading, if you're interested. You can Google much more.
Shae McCombs on Procedural Texture Generation
Notch, very briefly, on the original Minecraft terrain generation
First, you need to install the noise
module, which has convenient functions for noise generation. Generating noise isn't hard, you just combine random numbers together in different ways. At a system command prompt like cmd
in Windows (not the Python top level!), install the noise
module.
py -3 -m pip install noise
To test it, try import noise
at the Python top level.
Download the latest glib.py and save it in the directory you're going to be working in. Using the new functions available (and the examples from class), write a Python program with a main
function that:
To generate a noise value from the noise
module, you do this:
from noise import pnoise2 value = pnoise2(0.5, 0.5, 1)
This is 2-dimensional Perlin Noise, where the first two arguments are real numbers reflecting the x and y coordinates of the noise. The noise returns a random number between -1.0 and 1.0 that smoothly changes with x and y. True random numbers would have no correlation to the numbers next to them. The third argument is the number of octaves, which alters the appearance of the noise.
The scale of x and y impacts how the noise comes out as well. If they range from 1-10, it will look very different than 1-100. To simplify this, we use the concept of frequency to scale x and y. That is, we'll pick a certain frequency and divide both x and y by that number. As we change frequency, we can see the noise change. Thus, the noise call will look like:
value = pnoise2(x/freq, y/freq, octaves)
We could have separate xfreq
and yfreq
variables for even more control, but won't do that here.
Not done yet! If we want to use those Perlin Noise values for RGB colors, then we need them to range from 0 to 255, not from -1.0 to 1.0. That's a straightforward scaling problem. (Hint: add and multiply).
Your job:
x
, y
, freq
and octaves
and returns a Perlin Noise value.bottom
and top
and a value between -1.0 and 1.0, and returns that value scaled to be between bottom
and top
. Remember, it's easier to test functions outside a big program.width
, height
, freq
and octaves
and creates a list-of-lists where the number of lists is height
and each list has width
Perlin Noise values scaled to be between 0 and 255. (Hint: use the first two functions to do this).(v,v,v)
where v
is the value in the list-of-lists at the same coordinates. Note that the RGB values need to be ints, so you'll have to convert from floats in the list-of-lists.Keep working in the same file.
Okay, so noise looks kind of cool, but not like anything natural. Turns out that by combining noise functions we can get very natural effects.
Your job in this part is to write a function that takes two lists-of-lists generated by your third function and adds them together, producing a third list-of-lists. Since you want the resulting values to also range from 0 to 255, you'll need to divide each value by 2 as you add them.
Once you have that function, use it to add four different noises together, with frequencies 16.0, 32.0, 64.0 and 128.0. You will notice your program start to slow down as you generate more noises. If you want to be clever, you can do this in a loop. Now play around with frequncies and octaves and try to get something that starts to resemble an overhead view of clouds. Feel free to play with color as well by not just setting it to grayscale.