Blending Biomes in Procedural terrain generation

I've recently picked up procedural generation and it's been going great - until I decided to give Biomes a shot. With my current setup, I can assign a specific point in my world a biome based on its current height in a "global" biome noise generated with Simplex. The issue i'm having (and many others it seems) is to blend these biomes with eachother - while still being able to decide what goes where.

I tried blending it on my own by simply generating a height with a weight-value that could help with blending a biome with its neighbor. I calculated the weight by getting the distance normalized in a 0 to 1 scale, using this as a percentage. So if the "heaviest" biome had a weight of 0.8, the other neighboring biome would then have 0.2.

float totalHeight = (mainBiome * weight) + (otherBiome * (1f - weight));

However this didn't work out as I still got cliff-like borders between different height biomes.

Then I found an algorithm at Parzivail.com that actually worked perfectly in blending a biome with its surrounding biomes. The only issue is that it's pretty much only based on the index of my biomes-array.

float totalHeight = 0.0f;
float n = biomes.Length;
for (int i = 0; i < n; i++)
{
float left = (i - 1f) / (n - 1);
float right = (i + 1f) / (n - 1);
if (left < noiseHeight && noiseHeight < right)
{
var layer = biomes[i];
float w = -Mathf.Abs((n - 1) * noiseHeight - i) + 1f;

layer.Evaluate(x, y, sampleCenter);

totalHeight += w * layer.Height;
layer.Weight = w;
}
}

(desmos.com visualization)

I've tried modifying it in order to determine biomes based on temperaute and not only height, but whatever I do seems to bring the cliffs back.

Current implementation with seamless transition How would I change my way of doing this, so I could set up the placement of biomes in a better way and not be forced to use my array indexes?

• We have quite a lot of past Q&A covering different approaches for blending biomes — can you show us how you've tried applying these existing answers and where they're not serving your needs? Jun 30 '21 at 22:38
• @DMGregory Actually managed to get it to work. Should've kept scrolling down further on one of the questions in your link, as there was a great explanation on how to do it. I'll post an answer with how I solved it below. Jul 1 '21 at 8:16

So, after carefully reading the post at https://gamedev.stackexchange.com/a/164252/85899 I managed to get it to work as I wanted it. I'm currently in the works of adding temperature/moisture levels aswell, but I feel like it won't be an issue with this implementation. I'll share my solution below:

float noiseHeight = BiomeNoise.GetHeight(x, y, sampleCenter); // returning a noise value between 0 and 1
float totalHeight = 0.0f;
float totalWeight = 0.0f;
int n = biomes.Length;
float[] weights = new float[n];
// Evaluate the point (x, y) with each biome
for(int i = 0; i < n; i++)
{
var layer = new BiomeLayer() { Biome = biomes[i] };

// Calculates the noise for a specific point with a given biome
layer.Evaluate(x, y, sampleCenter);

float weight = (layer.Biome.Influence - Mathf.Abs(noiseHeight - layer.Biome.StartHeight)) / layer.Biome.Influence;

// As we don't care about weights below 0, we can just skip blending this biome by setting a weight to 0
weights[i] = Mathf.Max(weight, 0);
layer.Weight = weights[i];
totalWeight += weights[i];

float height = layer.Height * weights[i];
totalHeight += height;
}

// Divide total height by the sum of all weights
totalHeight /= totalWeight;

Result: (Canyons with a mix of grasslands at bottom left, desert at top right) - the pixelation is due to the LOD system. It's perfectly smooth at the biome borders! 