Ground water diffusion from rivers | 0.1.4


Summary

This version makes the initial elevation more varied and interesting. It also allows rivers to spread moisture, this enables vegetation along rivers in the desert (think the Nile). There is also some map filters related to viewing the potential productivity of industries like "farm", which is dependent on environmental factors like temperature and precipitation.

Changes

Initial elevation noise


Previously the elevation of land tiles was made up of 2 perlin noises (both with multiple octaves). One was ridged two give the general looks of mountain ranges, and the other was a low magnitude, high frequency noise to avoid uniform erosion patterns. This created world with 2 kinds of areas; mountainous and plains, but not much in between.

The new system using 5 perlin noises for land tiles.  Here is the code for combining the 5 noises.

_world.tiles[iTile].bedrock = 1f + 300f * roughnessNoise[iTile] + 
                              1.5f * Mathf.Max(Settings.topology.maximumElevation * (mountainRangeNoise[iTile] * peakNoise[iTile] + mountainRangeNoise[iTile]) / 2f, 
                              Mathf.Max(1000f * lowPlateauNoise[iTile], 2000f * highPlateauNoise[iTile]));

All noises are in the range [0, 1]. Roughness noise gives the topology some fine texture.

mountainRangeNoise is used to create the mountain ranges. It is combined with peakNoise to create peaks within the mountain ranges.

There are 2 plateau noises, with different frequencies, that are used to create areas of uniform elevation.

The mountainRangeNoise is a so called ridged noise. Ridged noise can be created by N* = (1 - |N|)^r. N is the initial perlin noise in the range [-1, 1], r is a parameter for changing the "steepness" of the ridges, and N* is the ridged noise. I also use some atan() here, but I'll describe that in more detail for the plateau noise.

mountainRangeNoise[iTile] = (float)NoiseS3D.NoiseCombinedOctaves(
                            _world.tiles[iTile].center[0] / (2f * Settings.topology.continentSize),
                            _world.tiles[iTile].center[1] / (2f * Settings.topology.continentSize),
                            _world.tiles[iTile].center[2] / (2f * Settings.topology.continentSize));
mountainRangeNoise[iTile] = 2f * Mathf.Pow(1f - Mathf.Abs(mountainRangeNoise[iTile]), 10) - 1f;
mountainRangeNoise[iTile] = Mathf.Min(1f, Mathf.Max(0f, 0.5f + Mathf.Atan(5f * mountainRangeNoise[iTile]) / Mathf.PI));
mountainRangeNoise[iTile] = Mathf.Max(0f, mountainRangeNoise[iTile] - 0.2f) / 0.8f;

The 2 plateau noises are both created using atan(). The atan() function maps [-inf, inf] to [-PI/2, PI/2]. Using a parameter inside the atan() one can set the "steepness" of the plateaus. 

The image below show how 1-|x| and atan(x) can be used to get ridges and plateaus.


Using these new layers gives a more interesting and varied world.


Ground water


Ground water diffuses from rivers. Ground water is combined with precipitation to form moisture. Moisture is then used in the ecosystem simulation, instead of precipitation. This enables vegetation in otherwise dry areas. After the landscape evolution algorithm is done, rivers are created. At that step river flow can be calculated and from that I derive ground water.

I perform the diffusion calculation on the GPU using 2 kernels. One main computational kernel, and one update kernel. The calculations are extremely fast, to the degree that I've not even bothered measuring it. Diffusion depends on elevation differences and the ground permeability attribute field. The compute shader used is shows below.

#pragma kernel Diffusion
#pragma kernel Update
StructuredBuffer<float> elevation;
StructuredBuffer<float> waterFlow;
StructuredBuffer<float> groundPermeability;
StructuredBuffer<float> j;
StructuredBuffer<float> k;
StructuredBuffer<float> l;
RWStructuredBuffer<float> groundWaterTemporary;
RWStructuredBuffer<float> groundWater;
[numthreads(64,1,1)]
void Diffusion (uint3 id : SV_DispatchThreadID)
{
    // Elevation dependant diffusion parameters.
    float elevationDifferencej = elevation[j[id.x]] - elevation[id.x];
    float diffusionParameterj = 1.0;
    if(elevationDifferencej > 0)
    {
        diffusionParameterj = exp(-0.001 * elevationDifferencej);
    }
    float elevationDifferencek = elevation[k[id.x]] - elevation[id.x];
    float diffusionParameterk = 1.0;
    if (elevationDifferencek > 0)
    {
        diffusionParameterk = exp(-0.001 * elevationDifferencek);
    }
    float elevationDifferencel = elevation[l[id.x]] - elevation[id.x];
    float diffusionParameterl = 1.0;
    if (elevationDifferencel > 0)
    {
        diffusionParameterl = exp(-0.001 * elevationDifferencel);
    }
    // Diffuse based on elevation.
    groundWaterTemporary[id.x] = ( 
        groundWater[id.x] + 
        diffusionParameterj * groundWater[j[id.x]] + 
        diffusionParameterk * groundWater[k[id.x]] + 
        diffusionParameterl * groundWater[l[id.x]]
        ) / 4.0;
    // Increase if below waterFlow. 
    if (groundWaterTemporary[id.x] < waterFlow[id.x] / 2000.0)
    {
        groundWaterTemporary[id.x] = waterFlow[id.x] / 2000.0;
    }
    // Ground permeability factor.
    groundWaterTemporary[id.x] = (0.8 + 0.2 * groundPermeability[id.x]) * groundWaterTemporary[id.x];
}
[numthreads(64, 1, 1)]
void Update(uint3 id : SV_DispatchThreadID)
{
    groundWater[id.x] = groundWaterTemporary[id.x];
}

Industry productivity factors

Industries like the farm are affected by environmental attributes like moisture and temperature. Previously you could only see this effect after you had built a farm. Now there is a set of map filters for each industry that are dependent on environment attributes. In the image above "farmability" shows where it's best to place farms. For example not on mountains or in the desert.

River adjustments

I've just changed threshold values for when I draw rivers, and how the width scale with water flow. This is purely graphical, and doesn't affect any of the simulations. I thought the previously there was an amazon sized river on pretty much every large continent. Let me know if you'd like to see the option to select between viewing "normal" or "mega" rivers.

TODO

On a short timescale (upcoming weeks) two main features are 2 be added.

Road infrastructure

At the moment resources are transported only on tile which belong to what I call the "transportation network". At the moment this network consist of all tiles with a built industry, and their adjacent tiles. It should be possible to extend the transportation network manually. That is what I will implement. I will most likely make it similar to the industry system in how you construct the roads. 

One way of doing it is imaging different tiers of roads: {trail, small road, medium road, big road, highway}. The different roads could have different construction/operating costs and have different transport capacity. 

One could also imagine a system where there are specific industries that produce the resource "transport capacity". Think a gas station, input would be "oil"/"gasoline", and output would be "transport capacity". "transport capacity" could then be used as input to roads to allow them to operate. Roads without supply to this resource would operate at a lower capacity. 

What implementation I choose to go for only time can tell.

Automatic turns

At the moment it's a bit tedious to press the "end turn" button 100 times when you want to see how resources are being transported. So an automatic turn system like the ones found in "stellaris" or "europa universalis" would be helpful. Figuring out a good way of implementing this (probably multithreaded, with unity coroutines), might take some time to figure out. It's crucial that this system does not lower the fps or in any other way interfere with gameplay. So this system might take a long time to implement correctly. 

Changelog

Features

  • CHANGE:     Initial elevation changes (plateaus and mountain ranges).
  • CHANGE:     Landscape evolution model partially multithreaded.
  • ADDITION: "ground permeability" attribute. Affects ground water diffusion.
  • ADDITION: "ground water" attribute. Diffuses from rivers.
  • ADDITION: "moisture" attribute. Derived from precipitation and ground water.
  • CHANGE:     Moisture <-> ecosystem interaction, replaces the precipitation <-> ecosystem interaction.
  • CHANGE:     Modified ecosystem (flora and fauna) parameters.
  • ADDITION: New industries {Pasture, Flora destroyer, Fauna destroyer, Labor cheat}.
  • REMOVAL:  Removed unused map filters.
  • ADDITION: New map filters: {ground permeability, ground water, moisture}
  • ADDITION: Industry productivity factor map filters. (Only relevant industries are listed)
  • CHANGE:     Scaled down rivers.
  • CHANGE:     Enabled fauna migration.

Bug fixes

  • Industry overlay button didn't scale properly for non 1920x1080 resolution.
  • Wrongly placed tooltip text for non 1920x1080 resolution.

Files

Orbis multiplex 0.1.4.zip 34 MB
Feb 17, 2022

Get Orbis Multiplex

Download NowName your own price

Leave a comment

Log in with itch.io to leave a comment.