Blending textures according to biome map

Godot Version



I’m creating an infinite procedural terrain generation system for a project. The terrain is split up into square chunks. For a given position in the world, the biome is determined by temperature, and moisture values which are based on perlin noise. When a chunk is generated, a biome map is also created which is an image that specifies what the biome is at a given point.
I’m creating a ShaderMaterial which will render the textures according to each biome. The biome map is passed to the ShaderMaterial of each chunk, and the chunk renders the texture corresponding to the biome at every position. The problem with my approach right now is there is no blending at all between bordering biomes.

This is the current state of the shader

My question is: What would be the best way to implement this preferably in the shader? I would like a nice gradient transition between the different biomes.

Here is my current shader code:

shader_type spatial;

uniform sampler2D biome_map : repeat_disable;
uniform sampler2D albedo_textures[3];
uniform sampler2D normal_textures[3];
uniform sampler2D roughness_textures[3];
uniform float cut_factor;
uniform float border;
uniform float height;
uniform float biome_size;

void fragment() {
	float biome_count = 2.0;
	float biome_index = texture(biome_map, UV).r * (biome_count - 1.0);
	int biome_idx = int(floor(biome_index + 0.5));
	vec3 albedo = texture(albedo_textures[biome_idx], UV).rgb;
    vec3 normal = texture(normal_textures[biome_idx], UV).rgb;
    float roughness = texture(roughness_textures[biome_idx], UV).r * 1.8;
    // Assign shader outputs
    ALBEDO = albedo;
    NORMAL_MAP = normal;
    ROUGHNESS = roughness;

Thanks for any help.

float biome_value = texture(biome_map, UV).r * (biome_count - 1.0);

// Get index for both textures
int biome_idx_bottom = int(biome_value);
int biome_idx_top = int(ceil(biome_value));

// Sample both textures
vec3 albedo_bottom = texture(albedo_textures[biome_idx_bottom], UV).rgb;
vec3 albedo_top = texture(albedo_textures[biome_idx_top], UV).rgb;

// Mix them together (you can use something like smoothstep for more control)
float biome_mix = biome_value - floor(biome_value);
vec3 albedo = mix(albedo_bottom, albedo_top, biome_mix);

// Output the result
ALBEDO = albedo;

This assumes that you only blend between adjacent textures, so if your textures are [sand, grass, snow] you can blend sand to grass and grass to snow but not sand to snow.

Thanks for that. But my goal is for any two biomes that are next to each other to be able to directly blend to each other.