Automating trees' distribution

Placing trees and bushes in an editor is fine for many types of games. There are many cases where you need objects to be in a very specific spot. When it comes to large-scale outdoor games, you might want to have a way of placing common objects in an automatic way, at least as a base. An artist or designer might then move items around to suit the needs of the game.

In this recipe, we'll create one such way that places trees using noise. Once the base is in, we'll take a look at how the pattern can be varied with different settings.

How to do it...

To produce automatic trees' distribution, perform the following steps:

  1. We get right to the center of the things. Create a new class called TreeControl that extends AbstractControl.
  2. Add a TerrainQuad field called terrain, a FractalSum field called fractalSum, a Spatial field called treeModel, and a BatchNode field called treeNode.
  3. Override the setSpatial method. Here, we declare treeNode.
  4. Then, assuming that the supplied Spatial is a Node class, parse its children looking for a Spatial that is an instance of TerrainQuad. Once found, set it to terrain as follows:
    for(Spatial s: ((Node)spatial).getChildren()){
      if(s instanceof TerrainQuad){
        this.terrain = (TerrainQuad) s;
  5. Using terrain's terrainSize, create a nested for loop statement that parses from its negative height and width to its positive.
  6. Inside this loop, grab a value from the fractalSum class based on the x and y coordinates. Then, look for the corresponding terrain height at that location as follows:
    float value = fractalSum.value(x, 0, y);
    float terrainHeight = terrain.getHeight(new Vector2f(x, y)); 
  7. Now, we need to decide how many trees we want. The FractalSum class generates a value between -1 and 1. Start by saying that any value above 0.5 should generate a tree and create an if statement accordingly.
  8. If this is fulfilled, start by cloning treeModel. Set its localTranslation to the x and y coordinates and the current terrainHeight field before attaching it to the treeNode field:
    Spatial treeClone = treeModel.clone();
    Vector3f location = new Vector3f((x), terrainHeight, (y));
    treeClone.setLocalTranslation(location);
    treeNode.attachChild(treeClone);
  9. After parsing the whole terrain, tell the treeNode field to batch its contents to optimize the performance and then attach it to the supplied Spatial.
  10. Now, create an application class to test this. It's recommended that you use a test case such as TestTerrainAdvanced to get a start.
  11. Create a new Node class called worldNode, which we attach to rootNode and then attach the terrain to.
  12. Then, create a new TreeControl class and load and set a suitable model that we can use as treeModel.
  13. Finally, add the TreeControl class to worldNode.

After running the application, we will see trees spread out across the terrain—in valleys as well as on top of the mountains. Depending on the environment, trees might not grow on mountains. If we don't want this, we can add a simple check in the TreeControl class. By adding a field called treeLimit, we can clamp the growth of the tree above a certain height; also, make sure the terrainHeight field is lower than the value supplied from fractalSum.

How it works...

In this example, we let the noise do most of the work for us. All we did was parse through the terrain, and at regular intervals, check whether the noise value at that point indicated whether a tree should be placed.

The noise provides an almost endless amount of variation to our distribution of vegetation and an equally endless amount of tweaking possibilities.

The drawback of using these automatic generation techniques is that we don't have proper control over them, and changing a value ever so slightly might have a large impact on the terrain. Also, even if the generation process is cheap and can be repeated deterministically, we will have to start storing the data as soon as we want to modify it in any way.

There's more...

With the current settings, the example distributes trees across a landscape in a seemingly random pattern. At first glance, it might look natural but trees rarely are so evenly distributed as this. Outside of a forest, you will usually find trees clumped together. We can easily achieve this with noise by changing the frequency. The following examples show how changing the frequency can change the pattern:

  • A frequency of 0.5 produces a very noisy and fairly uniform pattern, as shown in the following screenshot:
    There's more...
  • With a frequency of 0.1, we can distinguish different patterns as follows:
    There's more...
  • A frequency of 0.02 yields even less but larger clumps of vegetation as follows:
    There's more...
..................Content has been hidden....................

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