2
\$\begingroup\$

Following this lesson for implementing mid-point displacement algorithm for terrain generation. I aim at generating a wavefront(obj) file of the terrain

I have an array of dimension (2^n + 1) x (2^n + 1). The corners of the 2d array is initialized with random numbers.

n = plug_in_n 
arr = Array.new(2**n + 1) { Array.new(2**n +1) { 0 } }
n_augmented = 2**n 

arr[0][0] = rand(10 + 1)
arr[0][n_augmented] = rand(10 + 1)
arr[n_augmented][0] = rand(10 + 1)
arr[n_augmented][n_augmented] = rand(10 + 1)

This is the script I have written for generating a terrain.

a = arr
n_augmented_copy = n_augmented
while n_augmented > 1

puts "n_augmented = " + n_augmented.to_s
i = 0
while(i < n_augmented_copy)
    j = 0
    while(j < n_augmented_copy)
        a[i][j+(n_augmented)/2] = (a[i][j] + a[i][j+n_augmented]) / 2.0  + (rand 0.0..1.0)
        a[i + (n_augmented) / 2][j + n_augmented] = (a[i][j + n_augmented] + a[i + n_augmented][j + n_augmented]) / 2.0 + (rand 0.0..1.0)
        a[i + n_augmented][j +( n_augmented) / 2] = (a[i + n_augmented][j] + a[i + n_augmented][j + n_augmented] )/ 2.0 + (rand 0.0..1.0)
        a[i + (n_augmented) / 2][j]  = (a[i + n_augmented][j] + a[i][j] )/ 2.0 + (rand 0.0..1.0)
        a[i + (n_augmented) / 2][j +( n_augmented) / 2] = ((a[i][j+(n_augmented)/2] + a[i + (n_augmented) / 2][j + n_augmented] + a[i + n_augmented][j +( n_augmented) / 2]  + a[i + (n_augmented) / 2][j]))/ 4.0  + (rand 0.0..1.0)
        j = j + n_augmented    
    end
    i = i + n_augmented
end
# binding.pry
# p_arr(a)
n_augmented = n_augmented / 2

end

Demonstrating a case for n = 2: I have omitted the random-displacement rand 0.0..1.0to check if the heightmap chucks are getting calculated fine.

Here is how the iterations look like

n_augmented = 4
    9     0   5.5     0     2 
    0     0     0     0     0 
  6.5     0   5.5     0   4.5 
    0     0     0     0     0 
    4     0   5.5     0     7 
n_augmented = 2
    9  7.25   5.5  3.75     2 
 7.75 6.625   5.5 4.375  3.25 
  6.5   6.0   5.5   5.0   4.5 
 5.25 5.375   5.5 5.625  5.75 
    4  4.75   5.5  6.25     7 

If I form a mesh using this alone, it results in a plane like: enter image description here

Considering the random displacement for this case, it results in : enter image description here

For n = 5, It looks like : enter image description here

This is not desirable since I cannot see any peaks and slopes.

Here is the ruby script : CODE

\$\endgroup\$

2 Answers 2

3
\$\begingroup\$

The magnitude of your random displacement is not changing appropriately. For your initial points, you're using a random value between 0 and 10. But for the subdivisions you're only using a random value between 0 and 1.

What you probably want to do is to start with a random value between 0 and 10, and then cut the range in half on each iteration. So on the 2nd iteration, the range of random values would only be between 0 and 5. On the 3rd iteration it would be between 0 and 2.5, etc. That should get you something with peaks and valleys.

Once you have that, you can increase the Y scale to make the peaks taller or valleys deeper, or decrease it to reduce the range.

\$\endgroup\$
2
  • \$\begingroup\$ Thanks. Got it working and also posted the updated code in my answer. Y- scale in your answer referring to the initial upper range of the random value? \$\endgroup\$ Apr 7, 2019 at 4:46
  • 1
    \$\begingroup\$ Yes, you can either increase the first random values, or scale all values afterwards. \$\endgroup\$ Apr 7, 2019 at 5:17
1
\$\begingroup\$

What you probably want to do is to start with a random value between 0 and 10, and then cut the range in half on each iteration. So on the 2nd iteration, the range of random values would only be between 0 and 5. On the 3rd iteration it would be between 0 and 2.5, etc. That should get you something with peaks and valleys.

Thanks for this step. Here is my updated source if it helps anyone and here is the result: Result

def p_arr(arr)
    width = arr.flatten.max.to_s.size+2
    for i in (0..arr.length - 1)
        for j in (0..arr.length - 1)
            print arr[i][j].to_s.rjust(width + 2) + " "
        end
        puts ""
    end
end
def getrnd(range)
    rand -range.to_f..range.to_f
end

n = 8
arr = Array.new(2**n + 1) { Array.new(2**n +1) { 0 } }
n_augmented = 2**n 
arr[0][0] = rand(10 + 1)
arr[0][n_augmented] = rand(10 + 1)
arr[n_augmented][0] = rand(10 + 1)
arr[n_augmented][n_augmented] = rand(10 + 1)


a = arr
n_augmented_copy = n_augmented
range = 50.0
while n_augmented > 1
    i = 0
    while(i < n_augmented_copy)
        j = 0
        while(j < n_augmented_copy)
            a[i][j+(n_augmented)/2] = (a[i][j] + a[i][j+n_augmented]) / 2.0  + getrnd(range)
            a[i + (n_augmented) / 2][j + n_augmented] = (a[i][j + n_augmented] + a[i + n_augmented][j + n_augmented]) / 2.0 + getrnd(range)
            a[i + n_augmented][j +( n_augmented) / 2] = (a[i + n_augmented][j] + a[i + n_augmented][j + n_augmented] )/ 2.0 + getrnd(range)
            a[i + (n_augmented) / 2][j]  = (a[i + n_augmented][j] + a[i][j] )/ 2.0 + getrnd(range)
            a[i + (n_augmented) / 2][j +( n_augmented) / 2] = ((a[i][j+(n_augmented)/2] + a[i + (n_augmented) / 2][j + n_augmented] + a[i + n_augmented][j +( n_augmented) / 2]  + a[i + (n_augmented) / 2][j]))/ 4.0  + getrnd(range)
            j = j + n_augmented    
        end
        i = i + n_augmented
    end
    range = range / 2
    n_augmented = n_augmented / 2
end

board = n_augmented_copy + 1
c = 0 
k = board + 1
#Print vertices 
File.open("mountain.obj", 'w') { |file| 
    for i in 0..a.length - 1
        for j in 0..a.length - 1
            file.write("v " + j.to_f.to_s + " " + a[i][j].to_f.to_s + " " + i.to_f.to_s+ "\n")
        end
    end

    for i in 0..a.length - 2
        for i in 0..a.length - 2
            file.write("f " + (c + i + 1).to_s  + " " + k.to_s + " " + (c + i + 2).to_s + "\n")
            file.write("f " + (c + i + 2).to_s + " "  + (k).to_s + " " + (k+1).to_s  + "\n")
            k=k+1
        end
        k = k +1
        c += board 
    end
}
\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .