Perlin Noise

So a while back, like last trimester (3-4 months). I followed a tutorial to create a procedural map generator, but I want to take a deeper look into how it works and what it's doing. Since Perlin Noise consists of the image below, it's akin to the static you got on your old television that couldn't get a signal from the antenna back when we didn't all have digital tuners.

There's some serious maths behind the whole process with plenty of calculations to even make those confident at maths probably take a second to understand what the hell is being done.

It all starts with a noise map. Unity has a built in PerlinNoise method which effectively Generates a 2D Perlin Noise. The code below loops through each number of the height and width supplied, loops through the number of octaves specified to get a value between a range. This method of generation allows for negative noise so, like the Earth, results in uneven terrain rather than a flat plane with some hills.

//Loop through the noiseMap
for(int y = 0; y < mapHeight; y++) {  
    for(int x = 0; x < mapWidth; x++) {
        //Frequency and amplitude
        float amplitude = 1;
        float frequency = 1;
        float noiseHeight = 0;

        for(int ind = 0; ind < numOctaves; ind++) {
            //Divide by a scale to get non-integer values
            float sampleX = x / scale * frequency + octaveOffsets[ind].x;
            float sampleY = y / scale * frequency + octaveOffsets[ind].y;

            //Allow for negative noise so we multiply by 2 and subtract 1
            float perlinVal = Mathf.PerlinNoise(sampleX, sampleY) * 2 - 1;
            noiseHeight += perlinVal * amplitude;

            //Amplitude decreases while the frequency increases
            amplitude *= persistance;
            frequency *= lacunarity;

        //Normalize the noiseMap so the values are back within 0 to 1
        if(noiseHeight > maxNoiseHeight) maxNoiseHeight = noiseHeight;
        else if(noiseHeight < minNoiseHeight) minNoiseHeight = noiseHeight;

        noiseMap[x, y] = noiseHeight;

From here, the second option is to colour the noise map in. Making use of an array of regions (see below), you can quite easily create a nice looking terrain and adjust it for whatever climate/terrain type you want.

Which results in the following...

So what's next? Because that's not a useable map. The next step is to take that colour map and create a mesh from it, then with that flat mesh, multiply each coordinate by a height multiplier to get a 3D version of it.

You could take this a step further and use Unity's water physics to place water on the blue parts of the map. But the map just needs a MeshCollider and it's perfectly usable to place objects on. The scale is something to consider with any objects placed on it since the map will probably be something like 5 times larger in it's scale proportionality.

But that's a map generated from a perlin noise map which just looks like a bunch of black and white ink was thrown randomly on a canvas. Although in this specific case, it's a lot more spread out and has more of a gradient.

Link to the repo here if you want to try out the end result.

Tom Lynn

Read more posts by this author.