Terrain Deformers

manu3d

Active Member
Contributor
Architecture
Hi everybody,

I just wanted to share something that occurred to me a few days ago. Basically I took a few ingredients:
  1. the way tectonic forces deform the crust, i.e. uplifting, tilting or corrugating large pieces of land
  2. backward sampling done in fluid simulations
  3. overhangs
Now, I don't know what current terrain generators do but by the look of it they sample more or less complicated noise functions that define the properties of every block being loaded.

What occurred to me is that there could be a whole new layer of noise defining WHERE the noise function is sampled.

Simple (silly) example. Let's say we get one of the current terrain generator and and we associate a simple black and white 2D checkered pattern with it, repeating over the whole landscape. The meaning of black is: sample where you normally would. The meaning of white is: sample the function 100 blocks up from where you normally would. Result: same landscape as before with (silly looking) massive shifts downward where the white is - the sampling function finds air where there use to be a landscape.

Now, let's make everything realistically complex. First, rather than thinking about a 2D checkered pattern, let's think about a proper 3D noise resulting in 3 numbers per sample. Let's interpret these three numbers as a 3D vector pointing to where the next sample should be taken. This alone will stretch and compress and uplift and tilt sections of the landscape. Except that we do not stop there. The next sample is taken from another 3D noise function resulting in another vector shifting the sampling of the underlying terrain. And then let's do it one more time, effectively adding three vectors derived by three different noise functions. Only then, in the point indicated by the sum of the three vectors, we sample the original terrain.

So, effectively, that point in the original terrain is translated to the location of the sample taken in the first 3D noise function. Crucially, nearby portions of the original terrain will be displaced in a similar but not identical fashion as the noise varies spatially. With appropriate deforming functions there can be smooth deformations i.e. roundish uplifts, but also discontinuities, i.e. a tectonic fault carving a small canyon as it snakes through the landscape.

In this context overhangs are generated when a part of the landscape is uplifted and then the top-most layers get shifted horizontally. In this context if the whole landscape did that it might be very funny looking. It will be important then to use "masking" noise that ramps up a terrain deformer in certain areas but leave other areas untouched.

As you can imagine the theory can be sufficiently clear but making it work is the real challenge. I just hope to provide some food for thoughts.
 

Cervator

Org Co-Founder & Project Lead
Contributor
Design
Logistics
SpecOps
Sounds great to me (even if I might not catch all the subtle details), and also a little familiar for some reason, like we've had bits of discussion on similar concepts in the past, it just hasn't been done a lot. Adding more layers and phases to world gen surely would help make nicer worlds, and we've definitely talked about the idea of having a larger world-map scale fundamental ingredient to then blend in more local noise-based details.

Like first generating something like a PlaTec map (yay tectonics!) then using that as just one layer of noise, but at a very high level. That should help avoid the fractal noise repeating forever like standard Minecraft (or indeed our Perlin) worlds.

"Local" tectonic shifting to cause overhangs I think I understand and sounds reasonable :)

Right now I think we lack the ability to store a larger world map generated by whatever means, to then generate on top of in tiny patches for regular world gen. Most our world gen is more local.

Pinging @msteiger @Skaldarnar @Josharias @Marcin Sciesinski @Cpt. Crispy Crunchy for relevance
 

manu3d

Active Member
Contributor
Architecture
By the way, one of the earliest applications I thought of would be a deformer to distort @msteiger excellent hexagon-based terrain generator. That particular implementation is already doing a lot of cool things. The one thing that could do better is to hide the hexagons. =)

Right now I think we lack the ability to store a larger world map generated by whatever means, to then generate on top of in tiny patches for regular world gen. Most our world gen is more local.
Hmmm... I'd like to point out that the noise I've been talking about would be fully deterministic and would not require additional phases nor additional storage: it can be just as local. The important thing is that the mapping from world coordinates to sample coordinates can be arbitrary, but this could be done internally by the generator, it doesn't have to be done by an actual "Deformers" class (even though that might eventually be something to look into at some point.
 

Cervator

Org Co-Founder & Project Lead
Contributor
Design
Logistics
SpecOps
I think a big world map as I'm thinking about would generate the same, but then persist and be available for changes over time, such as macro effects from climate change, city growth outside of loaded areas, disasters, and so on. Probably some of that would be handled entity-style, but wouldn't really need to be present in the engine like current entities are (more like background elements you never need for regular gameplay)

But at the same time I'm not a world gen expert so I could just be making up stuff that makes little sense ... :)
 

Cpt. Crispy Crunchy

Member
Contributor
It would definitely be a fun experiment! Though I see some problems with it: Most worldgenerators work with a 2D Noise for the surface height. Taking an other nearby vector would only distort the pattern a bit. The same results could be achieved by taking adding one or two more noise functions. Now you want to make this with 3D noise, which is a bit more complicated to use as a surface but things like you proposed would then become more possible. A fun thing to try out would be to mask a certain area and say I want some cool deformations here! Then you would try to start with a simple 3D noise which sort of has to replace the 2D noise here and then you would add the deformations. Though they would be no real way to influence/predict them by just moving the samplepoint. You would need to modify the noisefunctions first, so that e.g. taking a sample 100 blocks above would really be more likely to result in an air block.
That are just some random thoughts and there are surely a lot of solutions to those problems :).

I think we haven't even explored plain 3D noise in the current world generators enough. I found it way more harder to get nice results in my initial tryouts, though with some time and dedication there would be a lot possible like overhangs and cracks in the world. In addition with a masking layer it would become way more controllable. That would be my way to start and then see what I could do with additional deformations.
Not the same thing, but filtering techniques can achieve similar results too imho and are way more predictable. I have made some good experience with an erosion filter in ShatteredPlanes.
 

Cervator

Org Co-Founder & Project Lead
Contributor
Design
Logistics
SpecOps

oniatus

Member
Contributor
Architecture
Some proof of concept:

I always started with a 3D fractal brownian motion (sorry for wrong math terms here :whistle:). Maybe something like this:
(z = 0, so the view is a vertical slice through the world).

Subtracting y from all values to get a surface squeezes the noise to a gradient:

Sampling the gradient with everything < 0 to rock and everything >= 0 to air gives

Playing with the settings (mainly lowering the amplitude) creates some plains (1px = 1 block)


In the next step i created a second 2D-Noise for the distribution of the terrain.
The basic idea here was to change the distribution of the noise by shifting the interval and applying some simple exponential functions on it, then clamping the values back in a [0-1] range.
For the mountains, this may look like this. One main point here was to get areas with clear 1-1-1-1-1 values next to each other for a "pure" terrain and also a soft edge-out to blend in the neighbouring terrain (see below).

Same for the plains with bigger spots and softer edge-out:


Now when calculating the block at a given position i iterate over all different terrain types (always a pair of 3d-density/2d-distribution-noise) and get the relative distribution of each type.
So a block may be 20% mountains, 70% plains and 10% hills.
Then i multiply the density of each type with the percentage. Maybe the mountains are very dense at this point but the plains are not, then this is likely to give a soft hill.
To fill empty terrain, i placed a copy of the plains with a constant distribution and a low value. This does not lower the other densities too much but filles in if nothing else wants.

Testing ingame with only Plains and the mountains combined:


Some drawbacks and notes:
  • The computation of the cunks gets very expensive compared to the 2d heightmap (~1-5 per second with only the two terrain types and no object sampling)
  • It takes tons of parameter tuning to get this running without boring slopes or floating blocks
  • Surface must be sampled based on the density and there may be multiple surfaces on one y-axis (makes object sampling more difficult and my spawnpoint messed up multiple times with a NPE when mountains got crazy), both not done by me.
  • No offsets so far, mountains generate lakes as deep as the mountains are high (lowering the sea level does not fix the issue because the offset depends on the current terrain type)
I can upload my experiment code to my repo when it looks less crappy and whoever wants can step in and spend his time with value tuning and merging with the object sampling and biome generator :D
 

Attachments

Top