Assigning biome colors

In this lesson, we present the strategy for creating a flat colored world map from a noise generator.

We’re going to extract values from a noise texture to do so. The images produced with NoiseTexture store the same values in the red, green, and blue channels. Because of this, we can pick any channel to work with. We’ll go with red.

We use this idea through the tutorial. All the shader’s textures store information in their red channel.

Let’s now see how we can map noise values to colors in a shader.

Create a new test scene with a TextureRect as the root node. In the Inspector, assign a new NoiseTexture to the Texture property. Don’t forget to add an OpenSimplexNoise resource to Texture > Noise.

Now add a new shader material with the following code:

shader_type canvas_item;

void fragment() {
    float red = texture(TEXTURE, UV).r;
    COLOR.rgb = vec3(red);
}

Nothing changed on the screen, which shows that all we need for our calculations is indeed the red channel.

Let’s now add a GradientTexture as input to our shader to experiment with assigning colors to the noise values.

After the shader_type line add a new texture input as a uniform:

uniform sampler2D color_map : hint_black;

In the Inspector, under Material > Shader > Shader Param, we can find a new property called Color Map. Assign a GradientTexture with a new Gradient to this Color Map and give it a couple of color stops.

Now replace the fragment() shader function with the following code:

void fragment() {
    float noise = texture(TEXTURE, UV).r;
    COLOR = texture(color_map, vec2(noise, 0.0));
}

Notice how the image changes color using the gradient’s color stops. We call this method gradient mapping.

Play with the Color Map gradient color stops to see changes in real-time. Here, we assign colors from color_map to noise values stored in the NoiseTexture. The GradientTexture is a 1-pixel height image that we can sample using our noise as U coordinates: vec2(noise, 0.0).

Using colors with a discrete color map

To create a world map with sharp transitions, we need flat colors, not gradients like we have seen in the segment above.

To keep things simple for the explanation, we’ll use the following texture for the next part.

It’s a 512 × 1px image you can find in the folder you copied from the demos project, called discrete-color-map.png. We stretched it here for viewing purposes. Note that we turned off this texture’s import flags Filter and Mipmaps. This way, we preserve the sharp transitions between colors. Doing so prevents the graphics card from interpolating between pixels in the fragment shader, which would add unwanted transition colors.

Assign discrete_color-map.png to Material > Shader Params > Color Map, and you should see something similar to this result:

We gave a dark blue color to all noise values lower than 0.6 and light blue to everything above 0.6 using the discrete color map texture. We preserved the amount of dark and light blue from the image based on its ratio. We will use the same strategy to assign colors to biome types in the next parts.