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;
}
}
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 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?
-
1\$\begingroup\$ 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? \$\endgroup\$DMGregory– DMGregory ♦2021年06月30日 22:38:40 +00:00Commented Jun 30, 2021 at 22:38
-
\$\begingroup\$ @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. \$\endgroup\$Ludvig Åslund– Ludvig Åslund2021年07月01日 08:16:49 +00:00Commented Jul 1, 2021 at 8:16
1 Answer 1
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! enter image description here