You are on page 1of 30

3D Terrain

Generate 3D Terrain

 Prepare / design a grid of vertices


Generate 3D Terrain
 Prepare a height map (usually in RAW format)
Load the height map (*.RAW)
struct SHEIGHT_DATA{
unsigned char* m_pucData; //the height data
int m_iSize; //the height size (power of 2)
} m_heightData;

bool LoadHeightMap( char* szFilename, int iSize ) {


FILE* pFile;

m_heightData.m_pucData= new unsigned char [iSize*iSize];

if( m_heightData.m_pucData==NULL ){ //If the memory failed to allocated


return false;
}

fread( m_heightData.m_pucData, 1, iSize*iSize, pFile ); //read the heightmap


fclose( pFile ); //close the file

m_heightData.m_iSize= iSize; //set the size data


return true;
}
Generate 3D Terrain
 Render the terrain using a brute force algorithm
Brute Force 3D Terrain Rendering Algorithm
void BruteForceRender( int m_iSize ){
int iZ, iX;

//cull non camera-facing polygons


glEnable( GL_CULL_FACE );

//loop through the Z-axis of the terrain


for( iZ=0; iZ<m_iSize-1; iZ++ ){
//begin a new triangle strip
glBegin( GL_TRIANGLE_STRIP );
//loop through the X-axis of the terrain
for( iX=0; iX<m_iSize-1; iX++ ){
//use height-based coloring (high-points are light, low points are dark)
ucColor= GetTrueHeightAtPoint( iX, iZ );
glColor3ub( ucColor, ucColor, ucColor );
glVertex3f( ( float )iX, GetScaledHeightAtPoint( iX, iZ ), ( float )iZ );

ucColor= GetTrueHeightAtPoint( iX, iZ+1 );


glColor3ub( ucColor, ucColor, ucColor );
glVertex3f( ( float )iX, GetScaledHeightAtPoint( iX, iZ+1 ), ( float )iZ+1 );
}
glEnd( );
}
}
3D Terrain Generator

 Generate a heightmap to be
used as the “blueprint” for the
terrain.
 Fault Formation
 Midpoint Displacement

 Genetic Algorithm

 Etc.
Fault Formation
 process of generating
“faults” in terrain
 add a random line to a
blank height field
 add a random height
to one of the sides.
Fault Formation
 How to create Random Line?

//pick two points at random from the entire height map


iRandX1= rand( )%m_iSize;
iRandZ1= rand( )%m_iSize;

//check to make sure that the points are not the same
do
{
iRandX2= rand( )%m_iSize;
iRandZ2= rand( )%m_iSize;
} while ( iRandX2==iRandX1 && iRandZ2==iRandZ1 );
Fault Formation
 we want to elevate one side of the line,
and we want to raise the height value of
every point on that side of the line.
How?
 Scan all pixels of the entire heightmap, if
the pixel is in the right side, elevate it.
Fault Formation
 Create a vector from (iRandX1, iRandZ1)
to (iRandX1, iRandZ1).

//iDirX1, iDirZ1 is a vector going the same


//direction as the line
iDirX1= iRandX2-iRandX1;
iDirZ1= iRandZ2-iRandZ1;
Pixel Tracking
 Vector Dot Product
Formula 1:
Normalized u & v
Formula 2:
Pixel Tracking

Left or Right ???


Fault Formation
for( x=0; x<m_iSize; x++ ) {
for( z=0; z<m_iSize; z++ ){

//iDirX2, iDirZ2 is a vector from iRandX1, iRandZ1 to the


//current point (in the loop).
iDirX2= x - iRandX1;
iDirZ2= z - iRandZ1;

//if the result of ( iDirX2*iDirZ1 - iDirX1*iDirZ2 ) is “up”


//(above 0), then raise this point by iHeight
if( ( iDirX2*iDirZ1 - iDirX1*iDirZ2 )>0 )
fTempBuffer[( z*m_iSize )+x]+= ( float )iHeight;
}
}
Midpoint Displacement
 Fault formation works great for a scene
composed of some small hills.
 What if you want something more
chaotic than that, such as a mountain
range?
 Midpoint Displacement is the answer.
 This algorithm is also known as the plasma
fractal or the diamond-square algorithm.
Midpoint Displacement
 ll we are doing is taking a single line’s
midpoint and displacing it.
Midpoint Displacement

- Calculate the midpoint for all four lines (AB, BD, DC, CA). The resulting point, E,
should be directly in the middle of the square.
- Displace E by taking the average of A, B, C, and D’s height values, and then we
add a random value in the range of –fHeight/2 to fHeight/2 .
Midpoint Displacement
 Calculate the height values for each of the
midpoints that is found earlier.
 Average the height values of the surrounding vertices and
add a random height value in the range of –fHeight/2 to
fHeight/2
Texturing Terrain
 Simple Texture Mapping
 “stretch” one texture over an entire terrain mesh.
Simple Texture Mapping
LoadTexture( "../Data/grass_1.tga" );
glEnable( GL_TEXTURE_2D );
glBindTexture( GL_TEXTURE_2D, m_texture.GetID( ) );

OpenGL Texture coordinates


Simple Texture Mapping
for( z=0; z<m_iSize-1; z++ ){
glBegin( GL_TRIANGLE_STRIP );
for( x=0; x<m_iSize-1; x++ ){

//calculate the texture coordinates


fTexLeft = ( float ) x / m_iSize;
fTexBottom = ( float ) z / m_iSize;
fTexTop = ( float ) ( z+1 ) / m_iSize;

//set the color with OpenGL, and render the point


glColor3ub( 255, 255, 255 );
glTexCoord2f( fTexLeft, fTexBottom );
glVertex3f( ( float )x, GetScaledHeightAtPoint( x, z ), ( float ) z );

//set the color with OpenGL, and render the point


glColor3ub( 255, 255, 255 );
glTexCoord2f( fTexLeft, fTexTop );
glVertex3f( ( float )x, GetScaledHeightAtPoint( x, z+1 ), ( float ) z+1 );
}
//end the triangle strip
glEnd( );
}
Simple Texture Mapping?
Multiple Textures Mapping
 Procedural texture generation:
 Use multiple textures image / tile to build a texture
map.
 using the terrain’s heightmap to generate the
texture map that will coincide with it.
 go through each pixel of the texture map,
 finding the height that corresponds to that pixel
 figuring out each texture tile’s presence at that pixel
 Each tile has a “region” structure that defines its
areas of influence.
The Region System
 create a structure to hold the region
information for each tile.

struct STRN_TEXTURE_REGIONS {
int m_iLowHeight; //lowest possible height (0%)
int m_iOptimalHeight; //optimal height (100%)
int m_iHighHeight; //highest possible height (0%)
};
The Region System
 How it work?

Height Map (70% texture’s presence)


The Region System (RegionPercent( ))
//height is lower than the region's boundary
if( ucHeight < m_regions[tileType].m_iLowHeight )
return 0.0f;

//height is higher than the region's boundary


else if( ucHeight > m_regions[tileType].m_iHighHeight )
return 0.0f;

//height is exactly the same as the optimal height


else if( ucHeight == m_regions[tileType].m_iOptimalHeight )
return 1.0f;
The Region System
//height is below the optimum height
if( ucHeight < m_regions[tileType].m_iOptimalHeight ){

//calculate the texture percentage for the given tile's region


fTemp1= ( float ) ucHeight - m_regions[tileType].m_iLowHeight;
fTemp2= ( float ) m_regions[tileType].m_iOptimalHeight -
m_regions[tileType].m_iLowHeight;

return ( fTemp1 / fTemp2 );


}
The Region System
//height is above the optimal height
else if( ucHeight > m_regions[tileType].m_iOptimalHeight ){

//calculate the texture percentage for the given tile's region


fTemp1= (float) m_regions[tileType].m_iHighHeight -
m_regions[tileType].m_iOptimalHeight;

return ( ( fTemp1 - ( ucHeight -


m_regions[tileType].m_iOptimalHeight ) ) / fTemp1 );
}
Creating the Texture Data
for( z=0; z<uiSize; z++ ){
for( x=0; x<uiSize; x++ ){
//set our total color counters to 0.0f
fTotalRed = 0.0f;
fTotalGreen= 0.0f;
fTotalBlue = 0.0f;

for( i=0; i<TRN_NUM_TILES; i++ ){


if( textureTiles[i].IsLoaded( ) ){
uiTexX= x;
uiTexZ= z;

//get texture coordinates


GetTexCoords(textureTiles[i], &uiTexX, &uiTexZ );
//get the current color in the texture at the coordinates that we got in
//GetTexCoords
textureTiles[i].GetColor( uiTexX, uiTexZ, &ucRed, &ucGreen, &ucBlue );
Creating the Texture Data
//get the current coordinate's blending percentage for this tile
fBlend[i]= RegionPercent( i, InterpolateHeight( x, z, fMapRatio ) );

//calculate the RGB values that will be used


fTotalRed += ucRed*fBlend[i];
fTotalGreen+= ucGreen*fBlend[i];
fTotalBlue += ucBlue*fBlend[i];
}
}

//set our terrain's texture color to the one that we previously calculated
m_texture.SetColor( x, z, ( unsigned char )fTotalRed,
( unsigned char )fTotalGreen,
( unsigned char )fTotalBlue );
}
}

InterpolateHeight() -> Interpolate the heights in the height map so that the generated texture
map does not look incredibly blocky

You might also like