Generating 3-D Ridged Multifractual Noise

Hi, I am working on a game, and it uses procedural terrain generation. In my game, I would like to know how to generate 3-D terrain with lots of overhangs and caves. I have scoured google with different searches, but I still don’t understand it! I am going to use the seeded random number generator in java.util.random to generate numbers. Could someone tell me how to do this in Java 6?



Thanks,

dangerdoc

If you are confused on how to produce random noise, and are not familiar with basic functions like Perlin’s Improved Noise, Voronoi noise, etc. Then you have alot of work to do before you can be producing caves and overhangs. Caves and overhangs are a much more advanced topic.



Check this thread out,

http://hub.jmonkeyengine.org/groups/user-code-projects/forum/topic/java-noise-jnoise/



Be wary, the Simplex noise is apparently copywritten. I would recommend looking at it from an educational standpoint, but dont use it in development.



Google the names of the different types of noise that are in that thread and learn about them. I dont know if the code is still available on there, let me know if it isnt. If it is, there is a class which will generate terrain based upon the values of the noise function. That will be a good place for you to learn about topics like vertex buffers. Of course, you are going to have to become very intimate with the terrain. You will probably need to write you own terrain implementation in order to support caves and overhangs.



Here is another thread you might find interesting:

http://hub.jmonkeyengine.org/groups/user-code-projects/forum/topic/procedural-infinite-3d-cave-generation/



Now, if you are about to get involved in terrain, I recommend reading the development blog for the game Infinity: Quest for Earth

http://www.infinity-universe.com/Infinity/index.php?option=com_content&task=blogcategory&id=0&Itemid=47



There are all kinds of topics in there which you can learn from. However, one of interest might be this one:

http://www.infinity-universe.com/Infinity/index.php?option=com_content&task=view&id=81&Itemid=47



In the article he talks about how he performs the horizontal displacements to produce cliffs. This doesnt even produce caves and I cant think off the top of my head right now how you would do that, it will be very complex. Of course, I recommend reading the first material before jumping into the development blog.



Good Luck!



Eggsworth

Sorry, but I do not understand most of the source… I am still quite a noob at this stuff. I am kind of familiar with 2-D heightmaps, using the diamond-algorithm, but I am lost at the variables and different passes for 3-D. I have read through a tutorial about 3-D generation, but it doesn’t show source, and I am lost. Is there a tutorial themed on building a java 3-D terrain generator form scratch? I am not too familiar with 3-D terrain generation, but I see the advantages over heightmaps.



Thanks for helping a noob,

dangerdoc



Also, I forgot to mention that I am aiming for infinite terrain

Google will be your best bet for finding any info for 3d generated terrain. The links eggsworth posted are excellent resources and you really should read through them. You will not find free code you can just plug in and have it done for you.

You will also have to be extremely familiar with heightmaps to extrapolate it, and the noise algorithms, to 3d.

And you might want to scope back your expectations with “infinite terrain”. Start first with 3d noise; and yes, it will take lots of reading. Then move onto “infinite” terrain.

I changed my search keywords, and I found this C++ Library (luckily, I have some C++ experience), which I will try to convert to Java. Now that I saw a library, I believe that it generates the values when you call it with the coordinates? I’ll post the Java source that I acquire on the forum when I get it done. Thanks for your help, I think that I finally understand the concept which I believe to be something like this:



[java]

int[][][] world = new int[256][256][256];

RidgedMFNoise noise = new RidgedMFNoise(frequency, octaves, seed, quality, lacunarity);

for (int x = 0; x<=256; x++){

for (int y = 0; y<=256;y++){

for (int z = 0; z<=256; z++){

world[x][y][z] = noise.getValue(x, y, z);

}

}

}

[/java]



I did not show the function for noise, but is this a correct concept for I/O with the function?



Thanks,

dangerdoc

I found a java 3-D version of Libnoise already converted, called “Libnoise For Java”. Hopefully that will help more newcomers like me. Also, about infinite generation, do you just keep pulling data from the noise function based on huge coordinate numbers?



Thank you all!

dangerdoc

Yep, as you move out in the world, you use those coordinates to generate the noise. TerrainFractalGridTest is an example of this.

1 Like

For infinite detail generation, you need to implement terrain algorithms such as geomipmapping(preferred), geoclipmapping, ROAM, or others. For infinite distance of generation with a constant detail level, you can implement that pretty easily I would imagine. Problem is though that these noise functions have problems after certain distances. Try finding articles about “infinite perlin noise” for more reading on the topic.

1 Like

I have been going over the internet trying to find my solution. I was doing a search on google, and I noticed that I had clicked on all the links. I also commonly run into familiar pages. I just don’t even understand the concept. Could someone please tell me about a tutorial, I just don’t understand the concept of 3-d. I understand the concept of 2-d, using the diamond-square algorithm.



thanks,

dangerdoc

You finished the internet?! How does it end?



http://http.developer.nvidia.com/GPUGems3/gpugems3_ch01.html Another link worth a read (it will take more than a quick glance to understand it, you have to implement the stuff to learn it)

1 Like
@Sploreg said:
You finished the internet?! How does it end?

Theres a restaurant, its very exclusive ;)
3 Likes

Perhaps I was not giving enough information. I am looking for an explanation of how the code for the generation would work. I understand the generation of heightmaps, but I just don’t know how to generate 3-D terrain. I tried looking at libnoiseforjava, and it had references to un-included code (it was not on the site). I just need to understand the process for deciding whether or not a block is solid. (Does it make a difference if I am generating a world of blocks like mythruna?)



Thanks for putting up with me

dangerdoc

@Sploreg said:
You finished the internet?! How does it end?


The end boss is hard.

There are probably many different articles on how Minecraft generates its terrain… basically I guess it’s a few 3D noise functions that plug x,yz,z into some function and then check that result against some threshold for “solid” or “not solid”.



In Mythruna, I wanted more control over things so I do multiple passes. In the first, I use a layering of three formulas (two are different fractals) to produce a height map. Then I carve caves and gorges out of that with a separate algorithm. I can randomly place caves and gorges or I can specify specific caves systems if I want… or even the seeds of specific cave/gorge systems and let the algorithm finish laying them out. The final cut-away is always randomized a bit. But that’s pretty complicated.



You can get pretty interesting terrain following Minecraft’s methods of 3D perlin noise and some thresholds.

For a truly thorough treatment of related subjects, this is the book I’ve referenced for nearly twenty years or so:

http://www.amazon.com/Texturing-Modeling-Third-Procedural-Approach/dp/1558608486/ref=sr_1_1?s=books&ie=UTF8&qid=1327717544&sr=1-1

1 Like

To sort of sum up what we are saying: you have to do a lot of research. Fully 3D generated worlds are not that common, and finding example code for them is rare. You are lucky that there have been a few posts, with code, on the jme forums (we have linked to these already). As for a full-on tutorial, or a step-by-step, on how to make 3D worlds, those don’t exist for a simple reason: everyone has different requirements so there is not one all-encompassing guide. You have to pick techniques will work for your goals. Be prepared for this learning process to take a lot of time, a lot of reading, and a lot of prototypes.

If you are going to generate terrain from the ground up, you are going to need to learn about IndexBuffers, NormalBuffer, and VertexBuffer of a mesh. Using these, you can tell the terrain the points where the vertcies are located (vertex buffer) which you can apply the noise offset, you can use the index buffer to tell the engine how to connect the verticies into triangles, and you can use the normalbuffer to tell the engine how light will reflect off the surface. Trying making a quad using custom code, thats a good place to start.



https://wiki.jmonkeyengine.org/legacy/doku.php/jme3:advanced:custom_meshes?s[]=index&s[]=buffer

While your advice is still 100% accurate, the fact that the poster purports to be making a block world does make mesh generation slightly more straight forward.

@pspeed said:
While your advice is still 100% accurate, the fact that the poster purports to be making a block world does make mesh generation slightly more straight forward.


That has aroused my interest because I'm doing this as well. I would like to share my code so that you could post possible improvements if you encounter any. Althoug the CollisionShape calculation needs far longer this method could need improvement^^

[java] //top, left, bottom, right, front, back
private static final int[][] vertices = new int[][] {
{ 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1 },
{ 0, 0, 0, 1, 0, 0, 1, -1, 0, 0, -1, 0 },
{ 0, -1, 0, 1, -1, 0, 1, -1, 1, 0, -1, 1 },
{ 0, 0, 1, 1, 0, 1, 1, -1, 1, 0, -1, 1 },
{ 1, 0, 0, 1, 0, 1, 1, -1, 1, 1, -1, 0 },
{ 0, 0, 0, 0, 0, 1, 0, -1, 1, 0, -1, 0 } };
private static final int[][] indexing = {
{ 2, 1, 0, 3, 2, 0 },
{ 4, 5, 6, 4, 6, 7 },
{ 8, 9, 10, 8, 10, 11 },
{ 14, 13, 12, 15, 14, 12 },
{ 16, 17, 18, 16, 18, 19 },
{ 22, 21, 20, 23, 22, 20 }
};

private static final int[] normals = new int[]
{ 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0,
0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1,
0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0,
0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1,
1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0,
-1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0,
};

public static Mesh createFrom(ChunkBlockArray cba) {

int[][][] boxes = cba.getArray();
int size = cba.getSize(); //Number of non air blocks

FloatBuffer fb = BufferUtils.createFloatBuffer(72 * size);
FloatBuffer normalBuffer = BufferUtils.createFloatBuffer(72 * size);
FloatBuffer colors = BufferUtils.createFloatBuffer(96 * size);
IntBuffer indexes = BufferUtils.createIntBuffer(36 * size);

int currIndex = 0;

for(int x = 0; x < boxes.length; x++) {
for(int y = 0; y < boxes[0].length; y++) {
for(int z = 0; z < boxes[0][0].length; z++) {
if(boxes[x][y][z] != 0) { //Not air?

//Create all 24 Vertices
for(int i = 0; i < vertices.length; i++) {
for(int j = 0; j < vertices[0].length; j += 3) {
fb.put(x + vertices[j]);
fb.put(y + vertices[j + 1]);
fb.put(z + vertices[j + 2]);
}
}

//Create the indexing
for(int i = 0; i < 6; i++) {
for(int j = 0; j < 6; j++) {
indexes.put(currIndex + indexing[j]);
}
}

currIndex += 24;
float col = 1f; //Take this from block's information
for(int i = 0; i < 24; i++) {
colors.put(col);
colors.put(col);
//rnd.nextFloat()
colors.put(col / 5);
colors.put(1);
}
for(int i = 0; i < normals.length; i++) {
normalBuffer.put(normals);
}
}
}
}
}

Mesh m = new Mesh();

m.setBuffer(Type.Position, 3, fb);
m.setBuffer(Type.Normal, 3, normalBuffer);
m.setBuffer(Type.Color, 4, colors);
m.setBuffer(Type.Index, 1, indexes);
m.updateBound();

return m;
}[/java]

At first glance, it looks like you are creating faces even when they are never shown (ie: between two solid blocks). That’s a pretty big performance loss since somewhere around half the faces (at least) are hidden in this way.



A relatively straight-forward approach would be to iterate over all of the empty blocks and then the immediate neighbors. Only output faces in the direction of solid neighbors.



Also, collisions on a block world are much less expensive to just do right on the original array data structure. The JME generated collision data will be pretty expensive (creation time and size-wise) in comparison.