[Tutorial] 3d voxel terrain caves

I saw a lot of people asking how to do procedural caves, so I decided to create a thread about this.

IMPORTANT: THIS IS NOT A PROCEDURAL TERRAIN GENERTAION, JUST HOW TO MAKE A GIGANT CAVE SYSTEM

First, create a cube. Name it what you want, make it a prefab and delete it from the scene. This will be the voxel.

Next create a empty game object. Im going to name it CaveGenerator (Yeah, very original) and add to it a new script Im also going to name it CaveGenerator.

Okay, so first the variables:

public float noiseScale = 0.05f;
[Range 0,1]public float noiseMin = 0.5f;
[Range 0,1]public float noiseMax = 0.65f;
public GameObject cube;
public float size = 30f

So lets see them one by one:
-The noise scale is the size of the caves, the caves will be exactly the same but bigger or smaller.
-The noise min value is the smallest number that can have a voxel, if smaller, it wont appear.
-The noise max value is the same as the noise min value bu setting a max value a voxel can have, if bigger, It wont appear.
-The cube gameobject is the prefab we created. We will place it if the noise values are correct.
-The size is how much big is going to be our cave system. Be careful, big sizes cause unity crashing.

Is a good idea to make the variables pubic so you can edit then in the inspector.

Second, some 3D noise function:

float Perlin3D(int X, int Y, int Z)
{
    float x =(float)X;
    float y =(float)Y;
    float z =(float)Z;

    x *= noiseScale;
    y *= noiseScale;
    z *= noiseScale;

    float xy = Mathf.PerlinNoise(x,y);
    float xz = Mathf.PerlinNoise(x,z);
    float yx = Mathf.PerlinNoise(y,x);
    float yz = Mathf.PerlinNoise(y,z);
    float zx = Mathf.PerlinNoise(z,x);
    float zy = Mathf.PerlinNoise(z,y);

    return (xy+xz+yx+yz+zx+zy) / 6
}

This noise function transforms 2D noise into 3D noise, so we can generate our caves.

Okay, next we are going to genetate the actual caves:
First, in the Start void:

void Start()
{
    GenerateCaves();
}

Now we are going to create the GenerateCaves void:

void GenerateCaves()
{
    for(int x = 0; x < size; x++)
    {
        for(int y = 0; y < size; y++)
        {
            for(int z = 0; z < size; z++)
            {
                if(Perlin3D(x,y,z)<noiseMax)
                {
                    if(Perlin3D(x,y,z)>noiseMin)
                    {
                        //A voxel can be here
                        Instantiate(cube,new Vector3((float)x,(float)y,(float)z), Quaternion.identity);
                    }
                }
            }
        }
    }
}

Now put the Cube prefab into the cube field, change th nlise values as you lika and hit play! After some time the cave will be there! Since the cubes have a collider you can make a character controller and walk trough them!

Some very important things:
If you set the scale to 0, there wont ve any caves.
A very big size causes unity to break.
Is posible to edit the script so you can get interesting caves.

Post your caves here!

I feel like i need to mention this: while this will generate cave-like structures and thus technically does what OP says, you will not be able to use this in your games.

Procedural generation is a pretty advanced topic. It requires some decent to hefty amount of optimizations to run properly in realtime. Usually this refers to topics like multithreading and spatial partitioning, but for starters you would never want to calculate the noise for the same coordinate twice, or instantiate thousands of individual objects.

“Voxel” does not necessarily refer to blocks, but even for Bloxels it is important to keep in mind that the world is not actually made out of blocks! Instead what you do for games like this create the mesh for each chunk to appear as if it was made out of blocks, while actually being one single object. It is then re-constructed upon change. It’s not as simple as taking all of those cubes and combining their mesh either. You dont need the overwhelming majority of these triangles, and thus you usually just manually draw the side of one cube (ie a square) where a voxel touches air.
This plus multithreading the the most basic setup you can expect to run well.
So for anybody looking to actually make a game using procedural generation: approach it properly or dont at all.

I do not wanna be rude, but this example does nothing but visualize basic Perlin noise in the most imperformant way imaginable. Perlin noise inherently has “holes”, but creating caves does not end there. In procedural generation you define the shape of the terrain using coherent noise functions (2D for 2D, 3D for 3D and so on), which you then add or subtract with various scalings to achieve certain effects.
For example, one could take perlin noise and combine it with a falloff texture to create terrain with some clear surface level and basically no holes underground. You would then subtract something like perlin strings to carve caves into the terrain. Or you could add something like Voronoi to achieve some crazy fantasy terrain.
Visualizing the result is then an entirely different topic again, which can be done in various ways.

5 Likes

You are wrong.
Is possible to add this to a terrain generation if it is made in a 3d grid.
Instead of adding a cube, you could set a point that was “ground” to “air”
This is just a VERY simple tutorial about using noise to make 3d caves. The thing is that you can replace the Instantiate with anithung you want.
A lot of people are making minecraft clones and ask about caves so here Im giving and way to do it. Im just using cubes to make it simple, but is possible to use a marching cubes algorithm to make it as you said (One mesh).

It allows chunk generarion, just in the Perlin3D X add the position in x of the chunk generation etc.

How to implement it in a minecraft like world:
Generate the minecraft terrein with no caves.
In the code I made, instead of instantiating a cube, remove the terrain block (If it is)
Voila! Caves in terrain
The next tutorial will be a world with this caves.

I just want to help the people that need caves in their terrain and you are being very agressive :frowning:

If you are saying all that like a challenge,
I ACCEPT One mesh worlds with perlin noise and all that stuff

Says someone registered a mere week ago to someone actively helping in this community for more than 2 years. A very cocky attitude if you ask me.

Yoreki replied very politely. I refused to answer to your first post as it was so “pathetic”. Just search the forum as there are some threads about voxel worlds already. And attempts of “noobs” to create them with Unity cubes are rectified quickly.

That should’ve given you a hint already that it wont work this way. Each cube is a GameObject and having thousands of them does not work as Unity has a “hard cap” of 65k GO’s (AFAIK) but it will “break” much earlier. So you will have to build something smarter for “showing off”. Note that such a complex topic like procedural mesh generation is not something a “noob” should takle anyway. Someone with enough experience to build it does not require a “tutorial” for it. And someone who thinks it is a good idea to use cubes for that is not ready to build it.

It’s good that you try to educate others. But for doing that one should have an advanced understanding of the things talked about. Which you clearly don’t have (yet).

2 Likes

OK this is very funny.
I have started posting here a week ago but programing in unity 3 YEARS AGO. Do you think that if I recently started with unity I will reply questions or make a tutorial?
Now, I know several ways to do this better; marching cubes for example. I only posted that as an example of how you could make a cave system. You are saying that @Yoreki hasnt be agressive, but you have be. A SIMPLE UNDERSTANDIG for the “noobs” that make cubic terrain, for them is this maked, so they understand how they can make caves to theit minecraft like project. I know that I should check what faces are visible, delete the not visible ones, put all together in a single mesh…
But I made this to be begginer friendly.
You and @Yoreki are repling too agresively to a 14 year old teenager.
Im NOT a Unity noob by far. I know how I should made this, I know that the code is “noob like” but is simple code for the “noobs” to understand.:frowning:

If you where the unity “noob” you will understand this tutorial as it is? Yes, is VERY simple (I made it like this cuz it is made for the “noobs”)
Now, I add marching cubes algorithm so instead of a ton of cubes it is a single mesh, threading so it dont lags, and all that stuff, the unity “noobs” will understand? No.

I dont think age matters. Neither do achievements in life or anything else. What matters is what’s being posted and, to some degree, how. I have to judge and comment based on that, as it usually is the only thing i have access to as well.

As far as my reply is concerned, i dont think it can be considered aggressive in the least. I simply mentioned a bunch of quite important or even critical informations relevant to the topic. Informations that were missing from your “tutorial”, but without which one will easily get the wrong idea.
From what you wrote, i realise you simply want to help. But ask yourself, who is being helped by a tutorial that misrepresents a topic? I dont say this to be rude either. I simply believe that, as posted, the tutorial would do more harm than good, which is why i felt the need to correct some of those misunderstandings. And i did so in a pretty factual, neutral and certainly non-aggressive way, i may add.

As it currently stands your tutorial and your comments do:

  • Misrepresent the complexity of an advanced topic
  • Leave out a ton of critical informations, even (or especially) for beginners
  • Skip all kinds of optimizations which, for this topic at least, are a critical part of any implementation
  • Misrepresent their own content / goal. The tutorial is not about creating caves. It is about visualizing standard Perlin3D. Which may still bring a lot of value to beginners… if it wasnt a picture-perfect example of what not to do.
  • You claim you are experienced and only wanted to keep it beginner friendly, but no beginner would understand the code less if you cached the perlin noise calculation in the loop. That’s not even an optimization, but a simple beginner mistake. Your argument simply doesnt float here.
  • May hype up beginners to create a voxel game, who then use your implementation, see it have crippling performance problems, research for why that is… and hit a rock wall of topics they are not ready for, crushing their motivation.

I do feel bad if my reply made you feel bad. I really do. But that does not change the fact that i think your post was missing critical informations anybody interrested in the topic should know about. Nor does it change the fact that i think your tutorial as posted would do more harm than good. Neither can i ignore all those people it may hype into a topic they are not ready for by making it seem all simple, just for them to then get their hopes crushed by reality.

Last but not least, it appears to me that the one posting most aggressively - or rather overly defensively - is you. And i understand why. Certain things still had to be said about this tutorial, and if doing so in a perfectly neutral way is already considered an aggressive reply by you, then i’m afraid i cant help with that.

1 Like

Again, Im going to do one “advanced” one

You just want hide unvisible faces, one mesh chunks, multithreading, chunck generation support (Like in minecraft)… OK, I will do It

1 Like

Those would be the basics of procedural generation you can actually use in games, yeah. However, if your goal is to talk about creating caves -which it is according to the title- you actually do not need to do or talk about any of the above. It’s basically a different topic.
Independant of what your sample rate is, or whether you visualize it as cubes or using something like marching cubes or dual contouring, the actual cave generation is applied to the underlying data, ie it happens in the noise part of things. So if you want to talk about that, you can do so without touching any of the above topics. You may then include a working example with a visualization approach that works well (ie, including the above), which people can download to test your cave generation examples in practice. You could even use the same tool to include images as examples of what you are talking about in the post about caves.

Closing.
No one is being “aggressive”. But they are being direct.

Sharing your learning progress is a great thing, and we have a forum for it. (works in progress or made with unity). This doesn’t really belong in scripting. It’s also a good idea to realize that creating “tutorials” and such is better approached much later in you personal development, if at all. Again, great to share stuff you are doing, but framing it as a tutorial isn’t helpful for folks coming here to learn. This isn’t anything that is game ready/practical, it is an example of visualizing math and can be fun. But for folks looking for help and googling “tutorial, voxel caves terrain, etc” it is none of those things.

Keep learning, and sharing in the appropriate forum, but worry about “creating tutorials” later.

3 Likes