This repogitory creates various mountains by using perline noise. Check out this article to understand perline noise in detail.
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)
]
The vector from each grid point to the target point is called a 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.
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
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
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