[Python] Diamond–Square algorithm in Python produces uniform noise instead of fractal terrain

Discussão em 'Python' iniciado por Stack, Maio 12, 2025.

  1. Stack

    Stack Membro Participativo

    [​IMG]## Problem

    I’m trying to implement the diamond–square algorithm in Python with NumPy and Matplotlib to generate a fractal terrain heightmap. Instead of seeing hills and valleys, my output is just uniform “speckled” noise.

    What I’ve tried

    • I initialize the four corners of an N×N grid with random values.
    • I alternate the square step and diamond step, halving the scale of the random offset each iteration.
    • I ensure half_step = step // 2 and return the terrain at the end.
    • I call plt.imshow(terrain, cmap="terrain") to visualize.

    Despite this, the result looks like purely random noise (see screenshot below) rather than a smooth fractal.

    Code


    import matplotlib.pyplot as plt
    import numpy as np
    import random


    def diamond_square(size, scale):
    terrain = np.zeros((size, size))
    #valori aleatorii pentru cele patru colturi
    terrain[0, 0] = random.uniform(-scale, scale)
    terrain[0, size -1] = random.uniform(-scale, scale)
    terrain[size -1, 0] = random.uniform(-scale, scale)
    terrain[size -1, size -1] = random.uniform(-scale, scale)

    step = size-1

    while step > 1:
    half_step = step//2

    #parcurg gridul
    #merg din element in element
    for x in range(0, size-1, step):
    for y in range(0, size -1, step):
    square(terrain, half_step, x,y, scale)

    for x in range(0, size-1, step):
    for y in range(0, size -1, step):
    diamond(x,y, size, scale, terrain, half_step)

    step = half_step
    #injumatatesc si intervalul de valori random
    scale = scale/2

    return terrain




    def diamond(x,y, size, scale, terrain, half_step):
    if x ==0:
    # media vecinilor est, nord, sud
    avg = (
    terrain[x + half_step, y] +
    terrain[x, y - half_step] +
    terrain[x, y + half_step]
    ) / 3.0
    terrain[x, y] = avg + random.uniform(-scale, scale)
    elif y == 0:
    avg = (
    terrain[x - half_step, y] +
    terrain[x + half_step, y] +
    terrain[x, y + half_step]
    ) / 3.0
    terrain[x, y] = avg + random.uniform(-scale, scale)
    elif x == size -1:
    #elif daca x este dimensiunea toata minus 1
    avg = (
    terrain[x - half_step, y] +
    terrain[x, y - half_step] +
    terrain[x, y + half_step]
    ) / 3.0
    terrain[x, y] = avg + random.uniform(-scale, scale)
    elif y == size -1:
    # elif y daca este dimensiunea maxima a gridului
    avg = (
    terrain[x - half_step, y] +
    terrain[x + half_step, y] +
    terrain[x, y - half_step]
    ) / 3.0
    terrain[x, y] = avg + random.uniform(-scale, scale)

    else:
    #daca nu ma aflu in niciunu din cele fac media aritmetica plus adun valoare random
    avg = (
    terrain[x - half_step, y] +
    terrain[x + half_step, y] +
    terrain[x, y - half_step] +
    terrain[x, y + half_step]
    ) / 4.0

    # atribuim noua valoare cu perturbare aleatoare
    terrain[x, y] = avg + random.uniform(-scale, scale)

    #x si y = coltul initial
    def square(terrain, half_step,x,y, scale):

    terrain[x + half_step//2, y + half_step//2 ] =(
    terrain[x,y] + terrain[x + half_step, y ]
    +terrain[x + half_step, y + half_step]
    +terrain[x + half_step, y])/4.0 + random.uniform(-scale, scale)



    def main():
    size = 129 #dimensiunea gridului
    scale = 100 #valori aleatori
    terrain = diamond_square(size,scale)

    plt.figure(figsize=(6, 6))
    plt.imshow(terrain, cmap="terrain")
    plt.colorbar(label="Height")
    plt.title("Diamond–Square Terrain")
    plt.tight_layout()
    plt.show()


    if __name__ == "__main__":
    main()

    Expected behavior


    A classic fractal terrain: large hills and valleys on the coarse scale, with progressively finer wrinkled detail at each subdivision. In other words, you should see smooth blobs at first and then smaller bumps filling them in, not a texture that looks like pure random noise.

    Continue reading...

Compartilhe esta Página