Generating Volumetric Terrain

Started by
18 comments, last by 3Ddreamer 10 years, 8 months ago

JTippets, thanks for that answer. It goes a bit beyond what I'm trying to make sense of right now, however I appreciate the details.

I do not have a well rounded mathematical education. This I cannot change. I have to work with what I have, in order to achieve my goal, there's simply no other way. I cannot go back to university in order to do what I"m trying to do... I have to learn on my own with what i"ve got.


I've only got about a year and a half of college education myself, so it's not really a matter of formal education. You're on the right track by asking questions.

Having said that, I understand generally what you are saying, and it's making sense to me in a general sense. Once I get past the current problem I am having, I believe that playing with these functions in some type of pre-made terrain generator, may assist me in figuring out what types of noise functions can produce various end results.


Yes, seeing it in action would certainly help.

The part where you talk about the Sky/Ground and how we are talking simply about values of density between -1 and 1 then in terms of starting with a normal 2D heighmap makes sense to me.

Although even that, is tripping me up right now. I know that the volume data is a Matrix of values [x,y,z] The marching cubes algorithm takes this data, and then uses it to generate the mesh.

If the volume data was all 1's or all -1's should this produce a CUBE then for that region of "space"? and a volume data matrix of all values of zero, would be blank space?


Well, it depends actually. If you just consider the values filling the volume data chunk in isolation then, yes, filling with a single value might produce a cube. Or it might produce nothing at all. It all depends on what you assume cells outside the volume to be. If you assume them to be 1, and you fill the chunk with 1, then no mesh will be produced. If you assume them to be 1 and fill the volume with 0, then you will generate a cube.

When dealing with voxel values in isolation like this, you have to pay particular attention to those out-of-bounds cells. Either you need to somehow track the cells that lie in neighboring regions, or you need to generate your voxel values deterministically using a function (such as Perlin noise) so that you can determine the value of an out-of-bounds neighbor cell by evaluating the function. This is the key if you want chunks to seamlessly connect with their neighbors; if all chunks are generated from the same continuous function then they should seamlessly connect. Otherwise you have to do a lot of weird stuff to wire them all up and get them to fit.

If you remove the noise entirely, shouldn't you be able to lets say fill the matrix with half 1's and half 0's and get Half a cube?


Yes. In fact, this is exactly what the linear gradient + select function will do if you orient the gradient along the line segment (0,-1,0)->(0,1,0) and use a threshold of 0, then map a volume of the function from (-1,-1,-1) to (1,1,1) into your voxel buffer. The 0 threshold will split the (-1,1) Y domain in half, placing the ground threshold in the center of the voxel chunk.

I want to make sure I understand the volume data and what it's meant to represent, just to make sure I didn't have a faulty premise on what the volume data is suppose to represent.


The volume data represents density. A value of 0 means 0 density (ie, nothing) while a value of 1 means full density (ie, solid). In this application we use either-or; instead of having a range of densities, we have either solid or open. This is why the select function is necessary. It converts the linear gradient (which has gradually increasing densities as Y increases) to a solid/open function defined at a threshold.

To map the data, you simply iterate across your voxel chunk and for each voxel you calculate the coordinates to feed to your generator function, evaluate the function at that point and assign the return value to the voxel.

Applications that make use of different terrain types (such as mentioned in the follow up to my initial article) will veer away from the simple solid/open abstraction and assign different values of the density function that evaluate to greater than 0 to different types of terrain. In this case, it's a matter of evaluating the gradient function (without the select function), then comparing the output value by hand to certain arbitrarily chosen thresholds to determine open, sand, dirt, stone, iron, etc... Of course, this aspect of it can get relatively complex since for things such as iron veins you typically have to introduce "branches" to your generation function. It can get kind of complex.
Advertisement

There's a really nice c++ Perlin noise generation library you can use called libnoise (http://libnoise.sourceforge.net/index.html).

And if you're after some specific help for setting it up with a voxel engine, this is an excellent tutorial https://sites.google.com/site/letsmakeavoxelengine/home/landcape-creation.

I've just finished building my landscape generation bits and pieces, and after messing around with libnoise I'm quite happy with the results :

3BOOeYy.png

Hi dude,

I'm going to skip the actual intellectual mumbo jumbo about how to get things done and put some ideas you might work on based on your question on the first post.

How to use noise to generate landscape: remember that noise returns a value between -1 and +1, for whatever position you are trying to get. So, you can use this to you advantage in different ways, for example, you can convert the values to a scale from 0 to 100 and use it as a height map... how do you do that.. simple, first convert it to a scale from 0 to 1... using something like 0.5 + 0.5 * perlin_result, then you can multiply that by whatever you need... 100, 1000, 100000, etc. You can now use that value as a elevation map and just fill cubes from 0 up to the point that perlin results. so if you do 0 to 100, and you get a 53, you will fill 53 cubes with solid, and the remaining up to 100 with non solid or air.

Now how do I put ground on top and something like rock below, well, you can grab something simple like 10% of the value you got, so lets say 5.3, round that either up or down, and put that as dirt, then grab the remaining and put rock, and you can so these kind of calculation to different effects.

How do you make the terrain in chunks, make the world know about other chunks, make smooth transitions and such. Define your view distance, say, 512*512 cubes, assuming the center is at around position 256. then slip that into a size that the program can render fast, say 16*16 or 32*32 or 64*64, it will depend on your optimizations. then make an array of chunks, so if you have 512 and chunks of 64, that will be 512/64 = array of 8 by 8. Each chunk will have an ID, which could be for simplification purposes the position where its first cube starts. so first section ID is {x=0, z=0} next section is {x=64,z=0} and so on... so if you want to know about chunks of another section just check for the cube position, get the section where that cube is at, extract is value, done.

Making smooth transitions between chunks, well, I would recommend that when getting the perlin value from your noise function, you don't do {x=5,y=0,z=7}, you do something like {x=5/2048, y=0, z=5/2048}. this will allow you go get a lot of numbers in a very smooth transition (you also need to tweak you noise frequency and other values)

Why do I use y=0 all the time, well, if you get the x and z value you will always get a height map. if you go up in y imagine a whole different height map, but very similar to the one you had below. That is the 3D perlin.

I don't want to use 2D perlin for noise height maps I want to use 3D, well first off computing a perlin value is not really expensive, computing a billion of perlin values is. But that will be really up to you.

I tried to make 3D noise but it look like a cut in an Ant farm, wtf do I do with it? Well if you use 3D noise as it is, you will end up with flying formation of all kinds. One way to bring all those formation down to earth and still keep some of the variations is to use a vertical gradient. ... Now you are thinking.. Say what!!, yes a gradient, you know... full wait down, full black on top, and lots of grays in the middle.

Using a gradient you will tell your program, for example, if you get a position at Y=0, that's full white in the gradient then it has a 100% change of using whatever value the perlin got. if you get a value in y=50, then you can have 50% chance of using that value, and so on, this will end up looking a bit better but it will not solve your problem entirely, different other approaches give different results so you have to try them out.

Try using curves, instead of a linear one... the linear one is when you have y=x (type y=x in google), an exponential curve is when you have y=x^2, or y=x^3 and so on (type y=x^2 in google to get the idea), you can also use y = sqrt(x), for an inverted curve. The properties of both exponential and roots is that if you have a value from 0 to 1 they will always give you at the end points 0 and 1, its the numbers in between that change their factor. So get the pelin value perlin={x=5/2048, y=0, z=5/2048}, apply and exponential or root formula, perlin = perlin^3, then check to see the value is withing your threshold.

Also in order to make a voxel engine you need to optimize a LOT, so don't draw the cube faces that are occluded by other cubes, for example, if you have 2 cubes, one on top of the other, the upper face of the lower cube, and the lower face of the upper cube are hidden so, why would you make triangles there... this seems like a small optimization but multiply that by 1billion cubes most of the all next to each other, and that will save you a lot of performance.

Use frustum culling with you chunks, this will save lots of rendering time by not sending entire chunks out off view to the GPU.

Another trick you can do, is some sort of data compression, for example if you have a cube tower, from you value 0 to 255 as max height, you will start to notice that you will probably end up with, 20 cubes of solid rock, then 5 of air (cave), then other 40 cubes of solid rock, 5 cubes of dirt and 185 cubes of air, having an array to hold 255 values for just 5 transitions seems dumb. so you could make an array with a structure that will tell you the cube type and how much of them are on top of each other. This will not remove the computational burden of calculating lots of cubes, but it will reduce the amount of information you work with, but this is a rather advanced topic that must be worked on after you have a system in place as it will break a lot of stuff in the process.

Another trick you can do, is have a geometry shader do the cubes for you, based on you positions array, but that a story for another day.

An advice I will give you is that even when the fractal functions produce a really nice looking result if combined right, you should not leave 100% of the generation to combining fractals, try for example using a fractal function to figure out the placing of rocks...small round pre-calculated figures of 3x3 or so, that will first fit on the current chunk, and second will show up if perlin value has an exact value of some constant you have.

Final advice, experiment a lot.

I'm going to leave it there so you can chew on all that, and lots of tests.

[sharedmedia=core:attachments:9449]

Your world is looking great winsrp! Excellent advice too.

that's and old prototype I'm no longer working on. Here is a wider look at it.

[sharedmedia=core:attachments:9460]

Looks damn cool! How on earth do you generate 55 million voxels in -4 seconds :)

well its almost 5 seconds actually... tongue.png

The display area contains much less than 55M (around 2M+ displayed), the 55M are just the ones marked as solid.. (including the ones underground, that are not rendered, since they are not needed) there are other 225M that are marked as air (lots of air here).

This is just a height map (which combines 2 or 3 fractal functions) with "patches" of 3D artifacts here and there, where the patches go, is also defined by 2D fractals. The trick is reading the 2D fractal as a possibility gradient map, instead of a height map, the view would be the same as a height map, the difference is how you interpret the values returned, in my case is value >0.5 check for 3D formations, <= 0.5 no 3D formations. Then I use the actual value 0.73, convert it from value range {0.5,1} to value range {0,1}^3 using fx=((value -0.5) * 2)^3 for example, and use the resulting value as a gradient for that 3D so that it kind of sticks to the ground.

I also used multi-threading to make the 8500+ sections of 32*32*32. This map does not uses the minecraft kind of generation where you can go from 0 to 128, and that's it, In here you could go as high or low as you wanted.


3Ddreamer, telling me to go back to school isn't very helpful... I'd say that's not what most Indie developers do to learn something new.

Actually what I recommended is that you get a book dedicated to noise algorithms and theory specializing in terrain generation. happy.png

Clinton

Personal life and your private thoughts always effect your career. Research is the intellectual backbone of game development and the first order. Version Control is crucial for full management of applications and software. The better the workflow pipeline, then the greater the potential output for a quality game. Completing projects is the last but finest order.

by Clinton, 3Ddreamer


3Ddreamer, telling me to go back to school isn't very helpful... I'd say that's not what most Indie developers do to learn something new.

Actually what I recommended is that you get a book dedicated to noise algorithms and theory specializing in terrain generation. happy.png

Clinton

Do you know of any books about those topics? The only one I've found so far is Texturing and Modeling: A Procedural Approach . Is that a good book on this sort of thing?

Want to get to know my work and I better? See my website: Au 79 Games

I wrote General Tips on the Process of Solo Game Development

This will definitely give you something good to chew, even with print resources, too:

http://vterrain.org/Elevation/Artificial/

Right here at gamedev is very useful information:

http://www.gamedev.net/blog/715/entry-1902202-procedural-terrain-algorithm-visualization/

(If you read it closely, then you will discover a procedural strategy which might save you many hours or research on your own and with trial and error.)

More tons of information:

http://pcg.wikidot.com/category-pcg-algorithms

This book (the updated third edition) has some very good procedural theory for terrain in a couple sections of the publication: (YES! ... to answer your question.)

http://www.amazon.com/Texturing-Modeling-Third-Edition-Procedural/dp/1558608486

(Notice the publications under the subtitle: "Customers Who Bought This Item Also Bought" ...)

Remember that procedural generation (typically) does not include collision which is a big challenge to model with this type of terrain.

Mr. Search will help you take it from here. wink.png

Clinton

Personal life and your private thoughts always effect your career. Research is the intellectual backbone of game development and the first order. Version Control is crucial for full management of applications and software. The better the workflow pipeline, then the greater the potential output for a quality game. Completing projects is the last but finest order.

by Clinton, 3Ddreamer

This topic is closed to new replies.

Advertisement