Arc 0World Gen

Terrain Generation 5: Fault Features

In my last post, I worked on making tectonic plates and smooth elevation transitions between plates, coasts, continents, and continental shelves. In this post, I’ll add additional fault features such as mountains and rifts.

At the end of Terrain Generation 4: Plates, Continents, and Coasts
Midway through this post with preliminary fault features
At the end of this post

Also if you’re puzzled by any of my not-very-scientific plate tectonics, check out my post on Tectonic Plates.

Fault Feature Algorithm Overview

To create fault features, which are terrain features which follow faults, such as mountain ranges, I’ll generalize the breadth-first search algorithm for generating coastlines from Plates, Continents, and Coasts.

Once again, I want to minimize the amount of noise used. Whenever possible, I’d like to use noise only to “dress up” the surfaces of the terrain, with the underlying shape controlled by pseudoscientific noise-less functions. For example, if the elevation at a given point in a mountain is 10,000 m above sea level, I’d vastly prefer 5000 m of that being contributed by noise functions and 5000 m contributed by a deterministic tectonic algorithm rather than all 10,000 m being attributable to noise functions.

For the fault features, I will do this by generating large, plain features that will serve as “bones” for the terrain, then noising on top of them. Here is the algorithm at a very high level:

For each fault:

  • Identify the fault type
  • Build a fault elevation and “hilliness” profile
  • Apply the fault profile using a specialized BFS

Finally, apply a ridged noise function scaled by the hilliness.

Fault Classification

I use two parameters to classify faults: convergence and whether they are oceanic or continental. Convergence is equivalent to the speed at which the two plates are converging, and I only consider whether convergence is positive (convergent) or negative (divergent). Since every fault has one convergence number and two plates, and order doesn’t matter for the two plate types, there are 2*3 = 6 possible fault types. The exact list is specified in the following section.

Fault Feature Profiles

My algorithm for generating fault features requires a profile, which is basically a 1D array of the terrain elevation as you travel away from the fault. For example, a simplified mountain profile might be [+8000, +8000, +8000, +6000, +4000, +2000, +0]. It starts at +8000 m right at the fault, then as you travel away from the fault, the elevation drops to 0.

The fault profiles also have a way to store hilliness, which is a factor used later on when applying ridge noise to texture the mountainous areas. I don’t show hilliness through most of this post because it’s simple and arbitrary.

The fault feature algorithm assumes (and requires that):

  • Fault features are symmetrical, i.e. profiles are applied equivalently in all directions from the fault. This allows us to use a BFS to apply profiles.
  • The ends of the fault profiles blend smoothly with existing terrain. The easiest way to do this is make the profiles relative instead of absolute: instead of storing an elevation of 2,500 m, store a relative elevation of +1,000 m which will be added to existing terrain. Then profiles simply have to end with +0 m.

Subduction has an additional trick to create both an oceanic trench and a coastal mountain range shifted on either side of a subduction fault.

Convergent Continental-Continental

Continental Convergent Mountains

Convergent continental plates form huge mountain ranges. Pretty simple. Remember that the profile is relative, so if the underlying terrain isn’t perfectly flat, once the profile is applied, it will reflect the pre-existing terrain profile.

Divergent Continental-Continental

Continental Rift

Divergent continental plates form continental rifts. In real life these are a bit rarer than is the case in my simulation. Possible item for future improvement.

Convergent Oceanic-Oceanic

Convergent oceanic plates subduct, forming an oceanic trench and an oceanic ridge. See below “Convergent Continental-Oceanic” for the similar continent-oceanic subduction profile diagram.

Divergent Oceanic-Oceanic

Oceanic Ridge

Divergent oceanic plates form oceanic ridges. I won’t attempt to model the striping pattern of real oceanic ridges.

Convergent Continental-Oceanic


Convergent continental-oceanic faults subduct. Subduction generates two fault features: a mountain range and an oceanic trench. These fault features will propagate from ghost fault lines which are shifted a distance from the real fault line. In the picture above, only the bolded sections will be generated by fault features. The continental shelf, seafloor, etc. already exist from Plates, Continents, and Coasts.

Divergent Continental-Oceanic

Divergent continental-oceanic form beaches, i.e. we’ll add nothing to these faults. This is not exactly scientific but without it we’d have no smooth coasts left.

Applying Fault Feature Profiles with Noised BFS

With fault feature profiles applied, before noise texturing
  1. Seed the BFS queue with every tile directly on the fault (or ghost fault). Add a couple tiles to either side of the fault to ensure there are no gaps (using the line-rasterization algorithm from Plates, Continents, and Coasts). Every tile in the queue remembers its seed tile. For all of these initial tiles, the seed tile is the tile itself.
  2. Commence a BFS with the seeded queue. For the next tile in the queue:
    1. Calculate the distance to the seed tile and use that distance to index into the fault feature profile array. This step can include a noise function to perturb the width of the fault features so they aren’t regular oblong shapes.
    2. If we’re far enough from the fault (i.e. reached the end of the fault profile array), don’t continue to 3.
    3. Add all adjacent tiles (which haven’t been through the queue already) to the queue. Pass on the pointer to the seed tile.

Noising It Up

After two noise functions are applied

Finally, we add a couple of noise functions. A very small, low-frequency noise function is applied uniformly to the map, and a high-frequency, larger amplitude ridge noise function is scaled by the hilliness factor. The ridge noise I used is the absolute value of a simplex noise function flipped upside down (e.g. 1-abs(simplexNoise) assuming simplexNoise returns [0, -1)).

Next Up

That’s about it for terrain. It’s time to embark into the second half of Arc 0 which is climate simulation. The first step (besides research) will be groundwater and surface water modeling with erosion. It’ll make a good transition step as the erosion will affect the terrain map a little. Then I’ll enter the full climate circulation model.

As a preview, currently my climate simulation is stable but too uniform to be interesting. If I can’t figure out a way to fix that soon, I might skip to some other topics then return to climate simulation later when I have a better idea of what I need from it.


  • Reduce mountains. Right now any ocean-continent fault has a 50% chance of producing a coastal mountain range, which means in many of my maps mountains dominate the continents. I’d like to reduce this a little. In fact, now that I mention it, it would be pretty easy to convert a percentage of subductions to plain coasts. Same for continental rifts. [11/26/18: A percentage of continental rifts were turned into smooth continent transitions.]
  • Rifts are still handled poorly. Continental rifts tend to look like weird oblong lakes, and oceanic trenches are abysmal 😉 [11/26/18: Continental rifts have been improved some.]
  • The seafloor in general is not very accurate. Oceanic ridges have characteristic patterns which are missing in my simulation. However for the time being, I don’t think I’ll be using the seafloor elevations for anything, and I’m satisfied with its current visual appearance.