Question

I'm currently using value noise I believe it is called in combination with fractal Brownian motion to generate terrain in a 3D environment. I generate a 2D height-map from the noise, with values ranging between -1 and +1. I typically just multiply that return value by 10 or so to set the height and that generates rolling hills.

What I'd like to do is somehow combine calls to the algorithm to have some areas very hilly, others quite flat, while some are nearly mountainous. How do you go about something like that without having edges between areas be extremely obvious (like jutting cliffs segregating them)?

Edit: This is needed to be completely procedural in a near infinite environment.

Based on ananthonline's answer, I'm taking a low frequency call to my noise generator as the mask. With two biome types, I take the 'impact' of the biome, subtract the absolute value of the mask value minus the 'location' on the mask, and divide that whole value by the 'impact' value again.

(Impact- abs(Mask - Location)) / Impact

That gives me a value that when positive, I can multiply towards the return value of a specific noise call with specific frequencies, amplitudes, etc (such as rolling hills or mountains or ocean).

The primary issue here is that if my mask returned values of 0 through 1 as an example, I'd need to (in a two biome scenario) set one biome's location to .25 and the other to .75 with a strength of .5 each for them to blend together properly. At least, if I wanted even distribution of each biome type AND to blend them together properly. I'd struggle quite a bit if I wanted, say, mountains to show up twice as often as rolling hills.

I do so hope that makes sense. The math works out fantastically, but I certainly don't think I'm explaining it well with my limited mathematics background and knowledge. Maybe some code would help (if my cruddy uncommented code means something to someone), note that GetNoise2d returns values between 0 and 1:

    float GetHeight(float X, float Z)
    {
        float fRollingHills_Location = .25f, fRollingHills_Impact = .5f, fRollingHills = 0;
        float fMountains_Location = .75f, fMountains_Impact = .5f, fMountains = 0;

        float fMask = GetNoise2d(0, X, Z, 2, .01f, .5f, false, false);
        float fRollingHills_Strength = (fRollingHills_Impact - Math.Abs(fMask - fRollingHills_Location)) / fRollingHills_Impact;
        float fMountains_Strength = (fMountains_Impact - Math.Abs(fMask - fMountains_Location)) / fMountains_Impact;

        if (fRollingHills_Strength > 0)
            fRollingHills = fRollingHills_Strength * (GetNoise2d(0, X, Z, 2, .05f, .5f, false, false) * 10f + 25f);

        if (fMountains_Strength > 0)
            fMountains = fMountains_Strength * (GetNoise2d(0, X, Z, 2, .1f, .5f, false, false) * 25f + 10f);

        return fRollingHills + fMountains;
    }

If a problem with the above code needs to be specified, then let it be that to do this with say 10 different biomes would require some extreme thought to be put into the exact 'location' and 'impact' values so ensure the blending is flawless. I'd rather code it in such a way to ensure that's already taken care of.

Was it helpful?

Solution

How about generating low frequency noise (white-black) in a texture that is 1/8th or smaller than the terrain texture, blurring it and then using this as the mask to blend the two heightmaps together (perhaps as part of the rendering algorithm itself)?

Note that you can also paint this "blending" texture by hand, allowing fine control of cliffs vs smooth transition areas (sharper edges vs blurry edges).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top