Using noise to generate a terrain

While noise is unwanted in many occasions, it is a great tool for procedural generation and has many uses. In this recipe, we'll explore jMonkeyEngine's FractalSum class and generate an image based on the output. This can be used as a heightmap for a terrain, but we are not limited by that. With some tweaking, we could get a basis to cover a forest or city.

Using noise to generate a terrain

Getting ready

This recipe relies on a way to output an image. Either use your own method to do this or refer to the The ImageGenerator class section in Appendix, Information Fragments, which provides an example of how to do it.

How to do it...

To generate a heightmap, perform the following steps:

  1. We will start by creating a class called NoiseMapGenerator.
  2. In its constructor, define a new FractalSum instance and store it in a field called fractalSum.
  3. Next, create a public method called generateNoiseMap that takes an integer parameter called size, a float parameter called frequency, and an integer parameter called octaves as inputs.
  4. Inside the method, configure fractalSum with some of the values and set the amplitude to 0.5f as follows:
    fractalSum.setFrequency(frequency);
    fractalSum.setAmplitude(0.5f);
    fractalSum.setOctaves(octaves);
  5. Then, define a 2D float array called terrain. Its dimension should be [size] x [size].
  6. Now, create a double for loop statement and parse through the size of both dimensions. Inside the loop, we get the value from fractalSum, which is based on your x and y coordinates; add 0.5f to the value. Clamp it to get a value between 0f and 1f and set the value in the terrain array as follows:
    for(int y = 0; y < size; y++){
      for(int x = 0; x < size; x++){
        float value = fractalSum.value(x, 0, y) + 0.5f;
        value = FastMath.clamp(value, 0f, 1f);
        terrain[x][y] = value;
      }
    }
  7. When you're done, call the ImageGenerator class to create the PNG image for us as follows:
    ImageGenerator.generateImage(terrain);

How it works...

With this simple implementation, and by using the supplied ImageGenerator class, we have the basics for a heightmap. We can see the result in our Projects folder under assets/Textures/heightmap.png. It's an image that shifts smoothly between bright and dark areas; here, bright areas represent a high terrain and dark areas, a low terrain. Bright pixels have values that are close to 1, whereas dark pixels have values close to 0. Normally, noise outputs values between -1 and 1. This is why we change the amplitude to 0.5f so that it yields a range between -0.5 and 0.5, and then we add 0.5 to the result.

A noticeable problem is that no matter how much we change the speed and frequency of the noise, the same kind of rolling hills landscape will appear, only in different scales. By changing the octaves' value, we will generate noise in several iterations with decreasing amplitude. The value of each pixel for each iteration is multiplied with the previous one. The result is called fractal noise. Using octaves is a way of adding detail by iterating over the result with different frequencies. For each iteration, the frequency is doubled and the amplitude is halved.

Frequency can be thought of as a scale value where a higher frequency will generate more and smaller features. Having a higher frequency on its own will make peaks and valleys occur more frequently.

A normalization process is not strictly needed for a heightmap, unless we want to save it as an image. Also, if we were generating a large number of heightmaps (for example, during the runtime for a game), we would not want to normalize the terrain based on a particular heightmap's minimum and maximum values or we would end up with very similar and hilly landscapes.

There's more...

Now that we have generated a heightmap and exported it to an image, we can actually use it as a base in Terrain Editor. The process is similar to the one where we created a terrain for our scene in Chapter 1, SDK Game Development Hub.

After creating a new scene (by all means, we can use an existing scene as well) and opening it, we can right-click on the main node in the SceneExplorer window and select Add Spatial.. and then select Terrain...

It's important that we select the same total size as that of the pixels of our image. Then, in the Heightmap screen, we choose Image Based from the HeightMap drop-down menu and select our image.

The Roughness slider will define how much the heightmap will be smoothed out before it is added. A higher smoothness will remove finer details, and this is a must if we want to have characters that will run or drive on top of it.

The Height Scale option will define the maximum altitude that the heightmap can have and scale it accordingly.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.142.40.32