Setting up the WorldMap scene

Let’s prepare our scene and shader.

First, create a new Godot project and copy the WorldMap folder from Procedural Generation demo project into your local project. It contains some textures and resources we need for this tutorial.

Create a new scene and select User Interface in the Scene docker. We use Control nodes in this tutorial because they provide a natural canvas to develop the shaders.

We need a node that spans the entire viewport area. Add a ColorRect to the scene tree and, in the toolbar, apply Layout > Full Rect, so the ColorRect spans the whole viewport.

Rename the Control node to WorldMap and the Color Rect to Viewer, then save the scene.

Preparing the shader material

Let’s start by setting up the shader. We’ll rely on its input textures to generate data for the world map in GDScript.

Select the Viewer node and in the Inspector, add a new ShaderMaterial to the Material property. Add a new Shader to the material and click on it to open the Shader bottom panel editor.

Define the input uniform variables to the shader and the type of the shader:

shader_type canvas_item;


// A step-wise gradient-map to assign flat colors to the water/land masses and biomes
uniform sampler2D color_map : hint_black;
// An array of positions of the `color_map`'s color stops
// We need them to determine water and land masses
uniform sampler2D color_map_offsets : hint_black;
// The following three variables are noise values for height, heat, and moisture
uniform sampler2D height_map : hint_black;
uniform sampler2D heat_map : hint_black;
uniform sampler2D moisture_map : hint_black;
// GDScript generated texture for rivers.
uniform sampler2D rivers_map : hint_black;

// This is the value of `color_map.gradient.offsets.size()`.
// We need it to get values at the given indices.
uniform int color_map_offsets_n = 0;

// The next two variables store the minimum and maximum values of noise generators
// that we will respectively use to calculate the heat and moisture of our world.
// We use those ranges to normalize our noise values.
uniform vec2 heat_map_minmax = vec2(0.0, 1.0);
uniform vec2 moisture_map_minmax = vec2(0.0, 1.0);

After defining these uniforms, several properties appear in the Inspector under Material > Shader > Shader Param. We will manipulate most of them from GDScript, but to do so, we first need to assign some textures to them.

Setting up the input textures

Let’s create textures and resources for our shader. Instead of creating them manually following the instructions below, you can use our the premade assets that you copied from the demos project.

If you want to get similar results, apply the following values under Shader Param:

Add a GradientTexture to the Color Map. Set its width to 512 and create a Gradient like the one in the image below.

Assign a NoiseTexture to the Height Map. Create an OpenSimplexNoise resource with the following values:

Add a NoiseTexture with its Width and Height set to 256. Create a new OpenSimplexNoise resource with the following values:

For Moisture Map, add a NoiseTexture with its Width and Height set to 256. Create a new OpenSimplexNoise resource with the following values:

Leave Rivers Map and Color Map Offsets empty because we’ll generate them from GDScript based on the Height Map.

If you change parameters while using our assets, you’ll overwrite the files as you run the project. Keep in mind that it’s easy to mess up the textures, especially GradientTexture.

The purpose of the Color Map, the GradientTexture shown above, is to color-code the water and different biomes. You can use any color you like for it. I chose to use colors from the Pear36 palette. The ones assigned to the Gradient above are the colors you see given to the biomes legend table cells:

Apart from that, we reserve the first two color stops for water areas.

We need to convert Color Map to a discrete version, that is to say, a gradient with sharp transitions, because we need flat colors for ranges of noise values. Doing so results in an image like the one below.

In our final generator, the Color Map colors represent (from left to right):

  1. The color of the deep water. All noise values between the first gradient stop and up to the second will get this color.
  2. The color of shallow water. Same as before, all values up to the third gradient stop will get this color.
  3. The beginning of landmass.
  4. All color stops up to and including the second-to-last represent biome types, based on the legend.
  5. The last stop (pure white in the picture above) isn’t used in the shader. Instead, we use its gradient stop position to create the discrete version of the GradientTexture.

The gradient color stops that matter in calculations, are:

The positions of the gradient color stops we omitted don’t matter, only their associated colors. We’ll see why in the next few parts as we finish coding the shader.