# 3D terrain generation: geological slices and noise function

Everyone knows how to use Perlin noise to generate the surface of a 3D world. You may use one or several octaves to generate more detail.

It is also known how to use 3D Perlin noise to generate, to put it simply, a 3D world (including what's below the surface) with "holes" in it.

The advantage of Perlin noise is that you don't need to know the entire world to compute one specific point in the world. Since it's a function (or a sum of them), all you need to know is the input seed and the function, and it gives you the output wherever you want. Each point does not depend on its neighbour.

Now I'm wondering how to generate a world which terrain is a mix of different types of materials. You may call them geological layers, even though there's not necessarily slices.

I'm having a hard time picturing how Perlin noise (or any function suitable for this) would apply to this specific goal.

Generators commonly generate the world first and then add individual items (caves, deposits of precious rocks, etc.), but that's not what I want because it would lose the benefit of the function thing. Applying post-processing to the terrain makes it impossible to compute one specific point or range, with a pseudo-infinite level of detail, like a function does.

what's your take on this? (Stick to the mathematical idea, no need for implementation)

• I wish your opening statement was true, my friend, but it is not. Jul 21, 2018 at 14:59

(1) Using the same perlin seed (map) as used for terrain

You could treat ranges in the perlin result as different materials.

Thus at a certain threshold, you transition from air / vacuum to matter, say rock; then at another, higher threshold, you might transition to iron, then to gold etc.

The problem here is that as the values build up in a region, you would always have gold surrounded by iron surrounded by ordinary rock... unless you did some post-processing to remove the surrounds (flood fill, not too hard) leaving only the core material.

(2) Using one perlin map for terrain, and one for materials

Wherever there is rock from the terrain (primary) map, there is also a possibility of other materials occurring, provided the intensity at this point in the materials (secondary) map is high enough. In this case you could just say, well, wherever there is a patch of high enough intensity, then we randomise material type. This could be done by calculating the centroid of those cells which were considered to be a special material (in a connected clump, which would need to be determined by flood-fill), and hashing that centroid's xyz combined (by bitshifting) to get some pseudorandom number which would be your index into the materials table, selecting the material for the clump.

Otherwise you could use the same trick as in the first approach: get the local maximum and let that decide what the core material is, then expand the core material into the surrounding areas until we reach the threshold where we're back to plain rock again.

(3) Using one map for terrain and one for each material

Given that each Perlin noise map / seed gives a 1D value at each point, this is going to be the simplest way to have many materials - have a map per material, and one for (non)solidity of terrain. Then when you exceed the threshold on the map, you can generate that material there, provided there is also solid rock there on the terrain map.

Although this looks the simplest, it probably also costs the most, as in order to get the world layout, you have to sample perlin function for as many materials as there are, plus the base terrain, for every cell in the local zone. Floodfills will probably end up being a bit cheaper, provided you can limit the expanse of each clump by setting thresholds high. But hey, maybe you hash the chunk coords to select only 3 desired materials for the chunk, then sample only these maps?

(x) Fast interpolation of a coarsely-sampled map

To reduce the cost of a flood fill, this can be used in conjunction with approaches 1 & 2. Instead of walking the original map (2D for demo purposes):

0 123456
1 xx0000
2 xxx00x
3 0xxxxx
4 0x0x00
5 00000x
6 xx0000


You could walk / flood fill a reduced map:

0 246
2 x0x
4 xx0
6 x00


...though this would leave you having to address values in between, to complete the map.

There is, however, one way in which those values could be filled in quite rapidly: GPUs do interpolation extremely well. You could interpolate a 3D texture, for instance, to generate all values in between these coarser 0,2,4,6,8 coords... indeed they could even be 0,16,32,48,64... and the GPU could rapidly interpolate all those 15 missing values between, in each axis. Whether you would be interested in linear interpolation is another question... you may prefer something like bicubic interpolation, which will still be very fast on GPU, but not as fast.

• You understood my question perfectly and that's exactly the kind of hints that I'm looking for. Also you explained very well and I understood the issues you raised. Keep them coming, people ;-) Mar 28, 2018 at 21:27
• I don't really like the idea that the last two approaches rely either on flood fill or "expanding". That's very expensive. There has to be a more mathematical, straightforward manner, in the spirit of calculating very basic thresholds. Mar 28, 2018 at 21:49
• @jeancallisti I've added more information to address your concerns. As clumps can be concave, and their convex bounds may overlap, the only way you can safely classify clumps of a single material is by flood fill. Perlin can't do that for you, nor can any other pointwise sampling function, because the points are logically discrete even if numerically continuous. Otherwise, you'll have to go with option 3 - each map is single dimension representing a single material's occupancy. Mar 29, 2018 at 10:38