6
\$\begingroup\$

I searched around the web but I found nothing that could help me, so I'm asking here.

I'm trying to procedurally generate terrain using the marching cubes algorithm, and I can generate a mesh. The problem is that the mesh that may be anything!

https://www.dropbox.com/s/w99lvynrfra2a5v/question.JPG

As you can see in that screenshot, everything is messed up.

Is this a problem with the noise function? I'm using a simple Perlin noise function. How can I achive a result like this:

http://www.youtube.com/watch?v=-hJkrr5Slv8

If the problem is with the noise, what do I need to change to achieve this? I want to create natural terrain with hills, mountains, plains etc.

(I'm using Unity3D, but I don't think this makes any difference.)

\$\endgroup\$
0

2 Answers 2

2
\$\begingroup\$

I suggest scaling down the vertical component of the sample point before sampling the noise function.

The starting point of the voxel terrain in the video looks like a heightmap, so they may have multiplied the component by 0.

Also, you have to add the vertical component to the field function.

so your field function should look something like this:

const float noise_vertical_scale = 0.2;
const float field_vertical_scale = 0.01;
const float iso_surface = 0.5;

/*
 * returns field at point (pos):
 *     negative = inside
 *     0 = surface
 *     positive = outside
 */
float sampleField(vector3 pos)
{
    vector3 sample_pos = pos;
    sample_pos.y *= scale;
    return noise3D(sample_pos) + pos.y * field_height_scale - iso_surface;
}

Hope that helps.

\$\endgroup\$
10
  • \$\begingroup\$ It may help me if you could explain me some points x) See, the noise that I'm using is a library that I downloaded from asset store and I don't actually know what "noise_vertical_scale" may be in that library... and what do you mean with "field_vertical_scale" ? If you want here's a link for a forum where you can get the library: [Unity Community Forum CoherentNoise Lib][1] [1]: forum.unity3d.com/threads/… Could you help me out? xD Still I'll try to figure out what your code means x) Sorry for my ignorance.... \$\endgroup\$
    – Sammael
    May 3, 2013 at 1:08
  • \$\begingroup\$ Ok it's already generating better mesh, with the code that you gave me. Only thing I had to do was change this last line "noise3D(sample_pos) + pos.y * field_height_scale - iso_surface;" in my code to fit what you told me and is already much better. Thank you very much, I think I already understand what you said x) \$\endgroup\$
    – Sammael
    May 3, 2013 at 1:18
  • \$\begingroup\$ still if could try to explain me what exactly are those two variable you would be great: noise_vertical_scale field_vertical_scale xD \$\endgroup\$
    – Sammael
    May 3, 2013 at 1:22
  • \$\begingroup\$ Yeah, sorry, I didn't explain very well. when taking the sample at a point in space, if you scale the sample point down, it is the same as scaling the noise up. For example, halving the height of the sample point will stretch the resulting noise shape by 2 in the vertical direction. \$\endgroup\$
    – DaleyPaley
    May 3, 2013 at 4:01
  • \$\begingroup\$ field_vertical_scale controls the influence the height has on the field function, so a large value will create a very flat terrain. \$\endgroup\$
    – DaleyPaley
    May 3, 2013 at 4:02
3
\$\begingroup\$

The good news: your Marching Cubes algorithm looks just fine to me! That 3d surface reconstruction looks gorgeous. If you're committed to a voxel-based approach with isosurface visualization, you're off to a fine start.

The problem is that 3d noise in this form really isn't suitable for use with a Marching Cubes-type algorithm for terrain. If you want to be able to do the sort of terrain modification that the demo you point to does, what I would suggest is to build the heightmap first and then build your volumetric data based on the heightmap.

Building the heightmap in the first place is relatively straightforward; I'd just use one of the classic fractal methods. You can use an approach like square-diamond midpoint displacement (probably the most common), but I would encourage a Fourier-based approach instead because it should allow you a lot more control over how 'rolling' your terrain is (and you can always 'postfilter' by applying a gamma-type effect, e.g. setting h(x,y) -> c*h(x,y)^3 or h(x,y) -> c*sqrt(h(x,y)), to make the terrain more or less jagged - if you look at the early articles on fractal terrain you'll see a lot of this).

Once you've got your heightmap data, there are a bunch of different procedures for converting that information into volume data. For simplicity's sake I'll assume that your heightmap data has been stored at higher resolution than your voxel data has; this makes a lot of sense, since a 3d array with the same XY resolution would (obviously) have to be a lot larger than the 2d heightmap. The easiest way to do it is as simple as

for (0 < vx < VOXEL_X_RES) {
  for (0 < vy < VOXEL_Y_RES) {
    pick the closest point (x,y) on the heightmap corresponding to (vx,vy) 
    (e.g. x = HEIGHTMAP_X_RES*vx/VOXEL_X_RES, etc)
    find the z value of the heightmap at (x,y) (and convert it to a voxel-space value vz)
    fill every value below (vx, vy, vz) with 1 to indicate it's in the terrain
    fill every value above (vx, vy, vz) with 0
  }
}

Because this fills the voxel array with only 0s and 1s, it can mean that the marching cubes interpolation along edges looks a little too 'regular' and results in surfaces with too many identical slopes on them. Instead, you may want to 'subsample' the heightmap to build your voxel array, using something like:

for (0 < vx < VOXEL_X_RES) {
  for (0 < vy < VOXEL_Y_RES) {
    find all 'pixels' on the heightmap corresponding to (vx,vy)
    for ( 0 < vz < VOXEL_Z_RES) {
      compute how many of the pixels in the set above have z > vz
      set the value of the voxel array at (vx, vy, vz) to the proportion of pixels with z > vz
    }
  }
}

The set of pixels on the heightmap for this second version can be anything from a straight subsampled grid (i.e., find hxmin = HEIGHTMAP_X_RES*vx/VOXEL_X_RES and hxmax = HEIGHTMAP_X_RES*(vx+1)/VOXEL_X_RES, similarly for hymin and hymax, and consider all pixels (hx, hy) with (hxmin <= hx < hxmax) and (hymin <= hy < hymax) ) to an 'overlapping samples' approach where you look at every heightmap-pixel within a circle centered around wherever (vx, vy) maps to on the heightmap; you could even subsample your heightmap and interpolate between heightmap pixels for finer detail.

One major caveat with this whole approach is that fractal terrain isn't really very 'terrain-aware' - it knows height, but it doesn't know anything about features : it doesn't really know what a river is or the effect it has on the surrounding geography; it can't distinguish easily between 'old' and 'new' geography; etc. If you want truly realistic terrain then you should consider some of the more simulationist approaches - but these tend to directly conflict with the kind of terrain modifications that the linked video shows, so if realism is your goal then it may be worth rethinking the voxel approach entirely.

\$\endgroup\$
10
  • \$\begingroup\$ nop, realism isn't the goal, I actully don't care if the terrain is realistic, I only want the effects, mounstains and plains and so on x) I already tried the heightmap approach with cubes, like minecraft, and it generated good terrain. So I already thought about using the method that you told me, the problem is, the marching cubes algorithms is using float values, 'cause if you use bool values for voxels it becomes more cubic, so to me the problem about using the heightmaps is actually that, wich value will I insert in the array index 'cause it can't be only 1 or 0... Still I'll try it. thnks \$\endgroup\$
    – Sammael
    May 3, 2013 at 1:48
  • \$\begingroup\$ about the marching cubes algorithm. Credits aren't mine, I made some changes and some optimizations, but it was given to me by a guy that is actually helping me who I found in unity community called scrawk, he's being great, so the credit is all to him. But I agree with you, the surface is pretty cool x) I understand how the algorithm works but in the begining I was getting doubts how to implement it, so scrawk gave me the algorithm so I could understand how does it works, and finally I understood and was able to do it my own way, but most of the things came from his algorithm x) \$\endgroup\$
    – Sammael
    May 3, 2013 at 1:57
  • \$\begingroup\$ As I knew giving boolean values (1 or 0) to the voxels results in "cubic" terrain kind of minecraft terrain, a bit better, but, still "cubic", thank you for your explanation but it doesn't fit my problem, still thank you very much ;) \$\endgroup\$
    – Sammael
    May 3, 2013 at 14:27
  • \$\begingroup\$ @Sammael That's true - all of your break points along edges will be at midpoints between cubes, and that can lead to some distinctive visual artifacting with long stretches of identical slopes. I'll add some notes to this answer in a bit to explain in more detail how to get non-binary values when you sample your terrain. \$\endgroup\$ May 3, 2013 at 15:35
  • \$\begingroup\$ now, that is a great thing x) If you could that would help me too :) Guys, you're being just great x) \$\endgroup\$
    – Sammael
    May 3, 2013 at 16:16

You must log in to answer this question.

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