Search code examples
pythonprocedural-generationperlin-noisenoise-generator

Procedurally generating areas with distinctly higher elevations with Perlin Noise


I am trying to learn about Perlin Noise and procedural generation. I am reading through an online tutorial about generating landscapes with noise, but I don't understand part of the author's explanation about making areas with higher elevation.

On this webpage under the "islands" section there is the text

Design a shape that matches what you want from islands. Use the lower shape to push the map up and the upper shape to push the map down. These shapes are functions from distance d to elevation 0-1. Set e = lower(d) + e * (upper(d) - lower(d)).

I want to do this, but I'm not sure what the author means when they're talking about upper and lower shapes.

What could the author mean by "Use the lower shape to push the map up and the upper shape to push the map down"?

Code Example:

from __future__ import division
import numpy as np
import math
import noise


def __noise(noise_x, noise_y, octaves=1, persistence=0.5, lacunarity=2):
    """
    Generates and returns a noise value.

    :param noise_x: The noise value of x
    :param noise_y: The noise value of y
    :return: numpy.float32
    """

    value = noise.pnoise2(noise_x, noise_y,
                          octaves, persistence, lacunarity)

    return np.float32(value)


def __elevation_map():
    elevation_map = np.zeros([900, 1600], np.float32)

    for y in range(900):

        for x in range(1600):

            noise_x = x / 1600 - 0.5
            noise_y = y / 900 - 0.5

            # find distance from center of map
            distance = math.sqrt((x - 800)**2 + (y - 450)**2)
            distance = distance / 450

            value = __noise(noise_x, noise_y,  8, 0.9, 2)
            value = (1 + value - distance) / 2

            elevation_map[y][x] = value

    return elevation_map

Solution

  • The author means that you should describe the final elevation, fe, of a point in terms of its distance from the centre, d, as well as the initial elevation, e, which was presumably generated by noise.

    So, for example, if you wanted your map to look something like a bowl, but maintaining the noisy characteristic of your originally generated terrain, you could use the following functions:

    def lower(d):
        # the lower elevation is 0 no matter how near you are to the centre
        return 0
    
    def upper(d):
        # the upper elevation varies quadratically with distance from the centre
        return d ** 2
    
    def modify(d, initial_e):
        return lower(d) + initial_e * (upper(d) - lower(d))
    

    Note in particular the paragraph starting with "How does this work?", which I found quite illuminating.