Procedurally Generated Caves - What First and How

I want to make a mountain made of destructible enviroment blocks, and then randomly generate caves and cave system connectors inside said mountain through perlin noise or a similar method.

I’m torn between 3D and 2D ant farm view, but whichever would be simpler is preferential. I’m sure there are many similarities in either case.

**So, what do I need, and where do I start? **

I’ve searched the forums as well as google but haven’t found anything equivalent that’s free.

Much obliged for any help.

You can start with dungeon architect plugin (its not free). It is great plugin it will show you limits of proceduraly generated content. However author of it has no experience in level creation, he is great programmr, but kind of drifts into programming challenges instead of making that plugin more useful. In short plugin has many cases where it misplaces decoration, and its quite hard to avoid it with its current design.

But because when you buy it, you get full source, and its extendable in blueprints, you could modify it to your needs.

Back to your problem: you need C++ lots of it. Also very thick skull you are going into kicking contest with a horse (which is unreal). Your stuff requires some serious coding work, basically world creation engine from minecraft, then some serious optimization to not bombard unreal (rendering engine) with millions of cubes. Then stitching it all with unreal. I would say not for beginner.

search here for “minecraft” there were several projects that tried to do this, and disappeared after a while.

also another topic is “dynamically created mesh” this can be done in blueprints only, but because of scale (milions of meshes) you need C++ and algorithm that groups them into bigger meshes.

There was an LD for worked here a while back who did a ‘free friday’ project making a cave generating system using the modular rock meshes from fortnite. It did indeed use c++ for the seeding system, but mostly just to generate a 3d grid of cells that were either on or off (I believe he used a simulation similar to cellular automata but cant recall for sure). Then in blueprint it read back the cells and based on a few rules, placed the modular fortnite rock/terrain meshes to make a seamless cave.

It might simplify things a bit to use more modular rocks rather than procedurally generating the entire mesh. Ie essentially make a building set of floors, walls, ceilings but much more organic.

Hmm, not very comforting news I guess. Though I suppose if those who failed documented their failures well enough there’s always the posibillity of building my success on top of their pile. :stuck_out_tongue:

Yet, is there something a bit easier that would introduce me to some of the mechanics I would be using in such a project as this perhaps?

I’ll be looking up those topics in the meanwhile, but I don’t think I can buy anything though. Cheers.

PS. What’s an LD? Lead Director?

Check how other people do it to understand the process in general:

http://www.roguebasin.com/index.php?title=Cellular_Automata_Method_for_Generating_Random_Cave-Like_Levels

I would go with Cellular Automata approach as there are plenty of articles on how to do erosion and other natural processes on grid structures - if you want your caves formation to look natural. Even without “simulation” approach tweaking rules is rather easy. Start with 2D first, it’s easy to switch to 3D after that.

LD = level designer.

And the task I mentioned was certainly doable all in blueprints, it would have just been a bit slower. The LD in question was by no means a full time programmer, but he found it easier to implement certain small functions in c++. But you could certainly start with blueprints. You shouldn’t really be intimidated by that, it is just something you will probably have to discover for yourself at some point. Some functions while easy to write in BP look messy with wires going all over, whereas the same thing in code can be relatively elegant.

I would think that looking at a “randomized dungeon” tutorial or one like it would help tremendously. There is really no difference between dungeon hallways and caves, caves are just a bit more organic and will likely have more wasted space, but you will still essentially be hooking up rooms and hallways with pre-made socket locations etc.

https://forums.unrealengine.com/showthread.php?50543-Randomized-Dungeon-System

Isn’t that in C#? And I don’t really understand the cell formula, how would I go about something like that in blueprints? I’m not sure if that method is what I need either, since I want to avoid random artifacts left by the automation process, I just want empty rooms with a mostly flat floor really. Would more itterations solve that?

I found this; A new, community-hosted Unreal Engine Wiki - Announcements - Epic Developer Community Forums And used his code to make a simple random map.
Another problem is when I select it, it selects the whole thing, but I need to be able to click individual tiles. I don’t know if this is just in the editor and it can be fixed in game mode or not.

Also, when it comes to generating a number of random rooms within the confines of my predefined map using blueprints, how would I go about doing that?
I tried downloading that project in your link but it always says the traffic is too great for the dropbox account. :frowning:

Blueprints can certainly do cellular 3d simulation, but it will get a little bit slow once you go up in size. Ie 32x32x32 volume is probably going to be slow since that is 32,768 cells.

To make it work you simply need to set up some ‘hash’ macros that convert 3d to 1d indices and vice versa. Then you can deal with linear arrays, or do things like access neighbors in any direction. You could write it as either a linear walk along cells XYZ or as 3 nested loops each of the length of their dimension. Probably doesn’t matter which method. I will dig up some examples that I have later. Feel free to ping me if I forget :slight_smile:

Then once you have this array set up, you can iterate over it and evolve it. again, depending on number of iterations it might get slow. For reference I previously did 2d terrain erosion simulation in BP and it got really slow after a 256x256, which is twice the points as 32x32x32.

I should mention that my experience regarding programming is fairly limited, I barely know what a macro is, and it might not even mean the same thing within this jargon.

Also, ping.

I would really like some examples. I’ve looked at the turnbased strategy example project provided in the learn section, but there’s just so much of it, I don’t know where to start. And just which pieces I need.

Here I come to confuse the day!

So… I can’t give you screenshots… I haven’t done it yet, though I started to play around with procedural meshes in blueprints, so it at least is not totally impossible…

Caveat: It would be more straightforward to do this in C++. That said, it’s not -impossible-, though it might be impractical; it just probably won’t be without its problems (especially since the feature is “beta”)…

Overview

I’m going to describe a method for making a 2D procedural mesh, then describe a method of, using noise, cutting away sections to provide a cavern like system. This will be simple, and by no means a complete project. Would be interesting if it does actually work though…

Part 1: Make a square.
Part 2: Lay out a collection of squares in a 2 dimensional grid (a chunk) to produce one big square.
Part 3: Use a look-up table to determine where a square should be placed in the aforementioned grid to create a differentiation between land and sky.
Part 4: Set a selection of tiles in the land portion to be “sky”, thus creating caverns.

1.) Let’s Make A Square

I do this in an actor blueprint called “ProcSquare”. I replace the default scene component with a ProceduralMesh component, and leave the name as “ProceduralMesh”

So our first goal should be to make one square. For ease, I’d work in 1m sizes (100 U) – this will be easily visible.

Let’s define some variables:

Create a vector variable called “Origin”, compile, and set it to 0, 0, 0. (You can change this later to define the initial point elsewhere if you so wish)
Create a vector variable called “Dimensions”, compile, and set to 100, 0, 100 (1m to the left, and 1m to the up directions)
Add a Material variable, and set it to some material.

Create a function called “CreateSquare” and give it two vector inputs – “SquareOrigin” and “SquareDimensions”. Give it two integer inputs as well – “xOffset” and “zOffset” (these will be used later to create the chunk).

In your construction script, wire the ConstructionScript exec output to “CreateSquare” exec input. Feed “Origin” and “Dimensions” into “CreateSquare”. Leave “xOffset” and “zOffset” at “0”.

Open the “CreateSquare” function.

You’re going to need to create 4 local variables, coinciding to the four vertices of the square. I name them “v0” for the 0,0 Cartesian point, “v1” for the 1,0 point, “v2” for the 1,1 point, and “v3” for the 1,0 point.

On the input, split the “SquareOrigin” and “SquareDimensions” structs so you can see the individual XYZ points.

Add a Set node for each of the 4 local variables, and split their input structs. Here’s the “math” as it were:

v0 x = “SquareOrigin:x * xOffset”, v0 z = “SquareOrigin:z * zOffset”
v1 x = “SquareOrigin:x * xOffset”, v1 z = "SquareOrigin:z * zOffset + “SquareDimensions:z”
v2 x = “SquareOrigin:x * xOffset + SquareDimensions:x”, v2 z = “SquareOrigin:z * zOffset + SquareDimensions:z”
v3 x = “SquareOrigin:x * xOffset”, v3 z = “SquareOrigin:z * zOffset + SquareDimensions:z”

You’ll need to wire from the function input exec through each of the Set nodes.

Add a “MakeArray(Vector)” node with 4 inputs. v0 => [0], v1 => [1], v2 => [2], and v3 => [3]. Add a comment marking this as your “Vertices Array”

From the v3 exec pin, pull into a “Clear Mesh Section” node. The target will be your procedural mesh component. Leave “Section Index” at 0.

From the “Clear Mesh Section” node, pull a “Calculate Tangents for Mesh” node. The “vertices” input pin should be fed the output pin from your Vertices Array. From the Triangles pin, pull out a “Make Array(int)” node, and give it five pins with the following values (in order): 0,1,2,0,2,3 (Add a comment that this is your Triangles Array). Pull out from the UVs pin and add a “MakeArray(Vector2d)” node with 4 pins. I take the “SquareDimensions:x / 100.0” and “SquareDimensions:z / 100.0” as my U and V maxes respectively. So my “MakeArray(Vector2d)” has the following values:

[0] = <0.0, 0.0>
[1] = <0.0, “SquareDimensions:z / 100.0”>
[2] = <“SquareDimensions:x / 100.0”, “SquareDimensions:z / 100.0”>
[3] = <“SquareDimensions:x / 100.0”, 0.0>

Add a comment that that MakeArray is your UVs Array.

From “Calculate Tangents for Mesh”'s exec pin, pull off for a “Create Mesh Section” node. Target is your procedural mesh component. Section index is 0. Vertices can be fed from your Vertices Array. Triangles can be fed off your Triangles Array. Normals will come from the Normals pin of the “Calculate Tangents for Mesh” node. UV0 can be fed your UVs array. You do not need to hook up the Vertex Colors pin. Tangents can be fed off the tangents pin from “Calculate Tangents for Mesh” node.

From the “Create Mesh Section” node’s exec pin, drag off to add a “Set Material” node. The target is the procedural mesh component. Material is your material variable. Wire the exec pin out to the return node.

Drop your blueprint in your scene and you have a square. Not super useful, but there you go.

2.) Let’s Make A (Bigger) Square

Sooooo, first off, we’re not really making one bigger square. We’re creating a 2 dimensional array of smaller squares.

Rather than hand hold you through this one, I’m going to give you more of an overview. Mostly because this is a point I haven’t done, but this would be my approach.

Create two variables:

An integer called “ChunkWidth”
An integer called “ChunkHeight”

Compile and set both to 100.

These are going to be the dimensions of your chunk, or a collection of individual squares.

Now in your construction script, before you call “CreateSquare”, you’re going to add two loops “For 0 to ChunkHeight-1” and “For 0 to ChunkWidth-1”, with the latter nested inside the former. The indices are going to be your offset (which you’ll have to multiply times the SquareDimensions:x or z to get the appropriate offset). So these will be fed into the “CreateSquare” function.

3.) Earth and Sky

You can approach this part relatively simply, because it’s not going to be that different either way… Before calling “CreateSquare” add a branch. Your boolean expression should evaluate if the index of “For 0 to ChunkHeight-1” is less than some value, create a square. Otherwise, continue. So you can check it against a value of 50, for instance. Easy peasy.

4.) Caverns!

Just for ease, we’ll do this with non-uniform noise.

After the last branch statement, add another branch. Your comparison this time will be of a random float between 0 and 1, against a threshold value (.65 for instance). So add a “float <= float” comparison, and off the first float choose “Get random float in range from stream” Min is “0.0”, Max is “1.0”. Pull off stream and select “Make Random Stream”. Now you can play with seed values.

Ideally, you’d want a uniform noise distribution, like Perlin or Simplex noise would offer. There’s no out of the box way to do this that I know of in blueprints, but this can be done in blueprints as well, though it’s not exactly clean. Straight PRN is going to give you missing squares in weird spots, and some holes could be bigger than others, though it won’t be organic.

Anyhow, hope that gives you a bit of a foot in the right direction.

2 Likes