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\$
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\$
  • \$\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\$ – Argha Chakraborty Apr 7 at 4:46
  • 1
    \$\begingroup\$ Yes, you can either increase the first random values, or scale all values afterwards. \$\endgroup\$ – user1118321 Apr 7 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\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.