Monday, 11 March 2013

Tutorial: Terrain Smoothing


Terrain Smoothing

Theory

Take one point. Then take its 9 neighbouring points. Work out the average height of the 9 points, and set it to the original point. Pass it through multiple times to be smoothed more.

Example

The framework already has a function for height generation and a function for random noise generation. It also has a single dimensional array to represent the 2D terrain so the example is in a triple nested for loop. In an ideal world a multidimensional array would better suit the representation of a 2D plane.

  1. The smoothing was put into its own function and called from within the terrain generation function. Strength will be how many times you want to pass the terrain through to smooth it. The higher the number the more it will be smoothed.

bool TerrainClass::GenerateSmoothing(float strength)
{

  1. Then make a for loop to carry out the smoothing as many times as required.
for(int times; times < strength; times++)
{

  1. Start cycling through the terrain array.
for(int j = 0; j < m_terrainHeight; j++)
{

  1. In this example it has to go through 2 loops because it's a single dimensional array.
for(int i = 0; i < m_terrainWidth; i++)
{

  1. Make a temporary variable to hold the value of the average height for the 9 adjacent heights.
float totalAdjacentHeight = 0;

  1. Find each point using the array (see diagram) and add it to the temporary variable.
i+1, j+1
i+1, j
i+1, j-1
i, j + 1
i, j
i, j-1
i-1, j+1
i-1, j
i-1, j-1

totalAdjacentHeight += m_heightMap[(m_terrainHeight * j - 1), i - 1].y;
totalAdjacentHeight += m_heightMap[(m_terrainHeight * j    ), i - 1].y;
totalAdjacentHeight += m_heightMap[(m_terrainHeight * j + 1), i - 1].y;
totalAdjacentHeight += m_heightMap[(m_terrainHeight * j - 1), i    ].y;
totalAdjacentHeight += m_heightMap[(m_terrainHeight * j    ), i    ].y;
totalAdjacentHeight += m_heightMap[(m_terrainHeight * j + 1), i    ].y;
totalAdjacentHeight += m_heightMap[(m_terrainHeight * j - 1), i + 1].y;
totalAdjacentHeight += m_heightMap[(m_terrainHeight * j    ), i + 1].y;
totalAdjacentHeight += m_heightMap[(m_terrainHeight * j + 1), i + 1].y;

7.     Retrieve the original point(the centre position in the diagram) and set it equal to the temporary variable (after you've / 9 (9 for 9 neighbours) this is the average)
m_heightMap[(m_terrainHeight * j), i].y = (float)(totalAdjacentHeight / 9.0);

8.     Close off the function.
}
}
}

return true;
}


Source Code

bool TerrainClass::GenerateSmoothing(float strength)
{
        for(int times; times < strength; times++)
        {
                for(int j = 0; j < m_terrainHeight; j++)
                {
                        for(int i = 0; i < m_terrainWidth; i++)
                        {
                                float totalAdjacentHeight = 0;

                                totalAdjacentHeight += m_heightMap[(m_terrainHeight * j - 1), i - 1].y;
                                totalAdjacentHeight += m_heightMap[(m_terrainHeight * j    ), i - 1].y;
                                totalAdjacentHeight += m_heightMap[(m_terrainHeight * j + 1), i - 1].y;
                                totalAdjacentHeight += m_heightMap[(m_terrainHeight * j - 1), i    ].y;
                                totalAdjacentHeight += m_heightMap[(m_terrainHeight * j    ), i    ].y;
                                totalAdjacentHeight += m_heightMap[(m_terrainHeight * j + 1), i    ].y;
                                totalAdjacentHeight += m_heightMap[(m_terrainHeight * j - 1), i + 1].y;
                                totalAdjacentHeight += m_heightMap[(m_terrainHeight * j    ), i + 1].y;
                                totalAdjacentHeight += m_heightMap[(m_terrainHeight * j + 1), i + 1].y;

                                m_heightMap[(m_terrainHeight * j), i].y = (float)(totalAdjacentHeight / 9.0);
                        }
                }
        }

        return true;
}


No comments:

Post a Comment