2
\$\begingroup\$

So I already have some (currently 2D possibly 3D later) simplex noise generation going, and with some experimenting I can make a map for plains, hills, mountains, etc

The problem now is I want to combine those together to create a larger more interesting map. For each "pixel" in the height map I provide/generate a biome type which has a bunch of parameters to define how the height value is calculated etc. i.e. I want to be able to say mountains here, river through there, flood plains next to it, etc and have them blend together.

The problem is this leaves nasty borders since between them even the simplex input values change suddenly (due to the x/z scaling being different, perhaps not the best way?). I considered just doing like a post process to smooth out the height values along the borders, but this would still leave often steep (and uninteresting near constant gradient) slopes since I could have a valley one side and a mountain peek the other side.

I am sure there must be a better fairly standard way to do this, but have not found much searching around, at least for this sort of noise function (midpoint displacement can be seeded with initial values at a low resolution, but doesn't seem viable if not generating the entire map at once)

double getHeight(int x, int z, Biome biome)
{
    double nx = x;
    double nz = z;
    nx *= biome.xzNoiseScale();//e.g. 1/64
    ny *= biome.xzNoiseScale();
    double noise = fbm(nx, nz, biome.noiseOctaves(), biome.noiseLacunarity(), biome.noiseGain());
    return biome.baseHeight() + noise * biome.heightVariation();
}


double fbm(double x, double z, int octaves, double lacunarity, double gain)
{
    double amp = 1;
    double freq = 1;
    double sum = 0;
    for (int i = 0; i < octaves; ++i)
    {
        sum += amp * noise(x * freq, y * freq);
        amp *= gain;
        freq *= lacunarity;
    }
    return sum;
}
\$\endgroup\$
1
  • 2
    \$\begingroup\$ You write in a comment that biomes determine height. Have you considered making it the other way around? Generate noise functions for height, moisture, and anything else, and then use that to determine biomes. That way, the underlying height, moisture, etc. are all continuous across biomes and won't have any nasty borders. \$\endgroup\$
    – amitp
    Jul 26, 2013 at 16:51

2 Answers 2

2
\$\begingroup\$

I don't know how "standardized" any of the techniques out there are, as PCG is still a nascent field. That said, I immediately thought of this excellent generation-with-biomes article when I read your question:

Source and demos included, even. What a guy. It doesn't seem like it would be particularly hairy to work your "paint the biomes" approach into it, either, though you'd need to port from Actionscript.

There are a lot of resources out there, most of which can be found from this one link:

The PCG Wiki linked therein can be a bit chaotic to navigate, but it has a lot of great links if you're persistent. Can never have too many resources when it comes to designing PCG algorithms!

\$\endgroup\$
0
\$\begingroup\$

There are two possible approaches i can think of.


1.) use many differently scaled FBM noises

Just add the FBM values of many differently scaled FBM noises together

Note Why do you use doubles, its unlikely that you do have mountains with a height of some light seconds.

class NoiseData
{
    NoiseData(float SpartialScale, float HeightScale, float Octaves)
    {
       ...
    }

    public float SpartialScale;
    public float HeightScale;
    public float Octaves;
}

NoiseData []Noises = {new NoiseData(100.0f, 5000.0f, 1), new NoiseData(12.0f, 500.0f, 1), new NoiseData(5.0f, 10.0f, 2), new NoiseData(0.5f, 1.0f, 3)};

float getHeight(float X, float Z)
{
    float ReturnHeight;

    ReturnHeight = 0.0f;

    foreach( CurrentNoise in Noises )
    {
        ReturnHeight = ReturnHeight + fbm(X/CurrentNoise.SpartialScale, Z/CurrentNoise.SpartialScale, CurrentNoise.Octaves, ?, ?)*Currentnoise.HeightScale;
    }
}

Now you can call getHeight to calculate the height of a point in your 2d plane.

Do decide on the returned height and the neightbor bioms which biom you want to generate, not the other way around.

To decide which Biome to generate for a given sector you can take the following things into account:

  • neightbor biome(s)
  • height/height variance
  • ...

2.) Use another technique than FBM noises for basic height generation

To generate the height of a hill you could use as the function the Gaussian function.

You then can use many of these functions added together to get the height of one point in space.

It is also possible to add FBM noise over this for more variation.

\$\endgroup\$
6
  • \$\begingroup\$ The biomes determine the height. At present I am using an image to specific biomes (so I can easily "paint" my large map), so the getHeight needs the biome as an input (and possibly query surrounding biome types). It was this that was causing problems because when say hills (say +-150) and mountains (say +-500) are next to each other, sometimes the noise ended up with a peak and valley next to each other. \$\endgroup\$
    – Will
    Jul 20, 2013 at 13:18
  • \$\begingroup\$ Double was more for the horizontal resolution since might get up to several hundred km (1 unit = 1 meter). Not sure how much it applies to terrain gen, was more concerned about the pos.x += speed*time type thing where pos.x is 1000000 speed is say 0.1 and time 0.01. Recall in the original demo before I changed it to double it started breaking long before that as well. \$\endgroup\$
    – Will
    Jul 20, 2013 at 13:25
  • \$\begingroup\$ then double makes sense... however, why do you prefer painting your world, you could throw the maps with the wrong height profile away (with moving of the x and z coordinates for the height function) \$\endgroup\$
    – Quonux
    Jul 20, 2013 at 14:34
  • \$\begingroup\$ What do you mean by that? Just keep generating completely random maps till it comes up with something I like? As for painting the biomes right now, I am intending to generate that map as well. I did try a bit to do it as one thing, but seemed problematic to get different areas to show up naturally just from a fbm or some other combination of noise output. Just ended up with hills everywhere, or plains everywhere, or perhaps just hills to the north of the origin, etc... \$\endgroup\$
    – Will
    Jul 20, 2013 at 14:51
  • \$\begingroup\$ If you want for example a hill in the left corner on the map and flat land on the right side you can N times randomy generate the XSeed and YSeed coordinates, after that you can sample the map starting from these coordinates and rate the map with a value from 0 to infinity (calculate the rating after the height profile differences you want), safe the rating with the X/Y-Seed values in a list. After finishing this you can pick the saved XSeed and YSeed values with the highest rating and use it to generate your final map. \$\endgroup\$
    – Quonux
    Jul 20, 2013 at 15:03

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .