Create Random 3D Terrain by Using Perline Noise

Hiroaki Kubo
3 min readMay 5, 2024

--

This article shows the mothod to create various mountains by using Perline noise. Other article introduces Perline noise in detail. This article will mainly introduce implementation part.

Algorithm

1. Create random gradient vectors

Each grid point has a gradient vector, which has a random angle.

dirs = [
(math.cos(a * 2.0 * math.pi / 256), math.sin(a * 2.0 * math.pi / 256))
for a in range(256)
]

2. Caculate distance vector

The vector from each grid point to the target point is called a distance vector.

3. Calculate the dot product of the gradient vector and distance vector

A grid point that is close to a certain point has a stronger influence. To do this smoothly, use the following fade function.

fade function
def calculate_weighted_dot_product(gridX, gridY, x, y, period, dirs, perm):
distX, distY = abs(x - gridX), abs(y - gridY)
# The closer the distance between a point and the grid,
# the greater the weight of that grid.
weightX = 1 - 6 * distX**5 + 15 * distX**4 - 10 * distX**3
weightY = 1 - 6 * distY**5 + 15 * distY**4 - 10 * distY**3
hashed = perm[perm[int(gridX) % period] + int(gridY) % period]
dot = (x - gridX) * dirs[hashed][0] + (y - gridY) * dirs[hashed][1]

return weightX * weightY * dot

4. Merge results in multiple octaves

By merging results in octaves with different frequencies and amplitudes, you can get more natural and detailed results.

def calculate_octave_perline_noise(x, y, period, octs, dirs, perm):
noise = 0
# Add noise functions
for octave in range(octs):
amplitude = 0.5**octave
frequency = 2**octave
noise += amplitude * create_noise(
x * frequency, y * frequency, period * frequency, dirs, perm
)

return noise

Implementation

The code is here. You can get a 2D random image by running following command.

python3 create_perline_noise.py --size 128 --octs 5 --set_seed

You can get a 3D random mountain by running following command.

python create_3d_terrain.py --size 128 --octs 5 --set_seed

If you want a rough mountain, you should change the number of octs from 5 to 1.

If you want to output a different mountain each time it is executed, do not specify the set_seed argument.

python create_3d_terrain.py --size 128 --octs 5

--

--

Hiroaki Kubo

Computer vision engineer. 3D computer vision/ Machine learning / Optimization / Graphics, https://www.linkedin.com/in/hiroaki-kubo-2819951ba/