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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.