It is currently Thu Apr 27, 2017 9:50 am

All times are UTC - 5 hours




 Page 1 of 1 [ 3 posts ] 
Author Message
 Post subject: I have a generic random Terrain class
PostPosted: Fri Oct 29, 2010 3:38 am 

Joined: Sat Aug 16, 2008 7:58 am
Posts: 447
In this class you will need some functions from vmks later in the serries, such as the uprgraded Math class with all the newer functions. The main functions needed from this class are the Swap Function and Random functions. This also means you need to seed the Random Generator.

The constructor takes a few parameters.

Terrain( float fWidth, float fDepth, float fMinHeight, float fMaxHeight, int iDivX, int iDivZ, bool bSmooth );

The way this class works is similar to the FlatGrid class. The only difference here is that It will create random peaks and valleys depending on the (min & max) height as well as the (DivX & DivZ) values. The last parameter determines if you want a smoother look or feel. Now the implementation takes the cosine of the average of the current, previous, and next height values. At the moment I don't really see that much of a difference in a visual affect, but the alrogithim is a work in progress.

As a note to this as well, I would suggest rendering it with the clovers.tga texture for a better visual then just using a basic material. I have not calculated the Normals to this yet, so for now I just specified the normal to be Vector3( 0.0f, 1.0f, 0.0f ) and it shows up good.

And what you have been waiting for, the CODE!!!

THE HEADER

#ifndef GEOMETRYTERRAIN_H
#define GEOMETRYTERRAIN_H

// ============================================================================================== //
// FileName: GeometryTerrain.h
// Version: 1.0
// Copyright (c) 2010 by Francis R Cugler Jr
// ============================================================================================== //

// Includes
#include "Core.h"
#include "Plane.h"
#include "Geometry.h"

class GeometryTerrain : public Geometry
{
public:
   // Constructor And Destructor
   GeometryTerrain( float fWidth, float fDepth, float fMinHeight, float fMaxHeight, int iDivX, int iDivZ, bool bSmooth = true );
   ~GeometryTerrain();

   // Public Member Functions
   void   Update();
   void   RenderOGL( bool bTexture );
   void   Smooth();

   // Public Member Variables

private:
   // Private Member Functions
   void GenerateHeightMap();

   // Private Member Variables
   float   m_fWidth;
   float   m_fDepth;

   float   m_fMinHeight; // (Y) Directions
   float   m_fMaxHeight;
   
   float   m_fCurrentHeight;

   
   std::vector<Vector3> m_vpHeights;
   
   int      m_iDivX;
   int      m_iDivZ;   
   float    m_bSmooth;
   
   Vector3      *m_pN;   // Normals
   Vector3      *m_pV;   // Vertex  Coord
   Vector2      *m_pT;   // Texture Coord

};

#endif // GEOMETRYTERRAIN_H


THE CPP
// ============================================================================================== //
// FileName: GeometryTerrain.cpp
// Version: 1.0
// Copyright (c) 2010 by Francis R Cugler Jr
// ============================================================================================== //

// Includes
#include "stdafx.h"
#include "GeometryTerrain.h"

// ---------------------------------------------------------------------------------------------- //
// Name: GeometryTerrain()
// Desc: Default Constructor
// ---------------------------------------------------------------------------------------------- //
GeometryTerrain::GeometryTerrain( float fWidth, float fDepth, float fMinHeight, float fMaxHeight, int iDivX, int iDivZ, bool bSmooth )
{   
   m_pV = NULL;
   m_pT = NULL;
   m_pN = NULL;

   // Convert Invalid Values To Valid Ones
   if ( fWidth <= 0 )
   {
      fWidth = 1.0f;
   }
   if ( fDepth <= 0 )
   {
      fDepth = 1.0f;
   }
   if ( iDivX <= 0 )
   {
      iDivX = 1;
   }
   if ( iDivZ <= 0 )
   {
      iDivZ = 1;
   }   

   // The Min Height Must Be Less Then Max Height
   // If Not Swap Values

   // Valid Checks For Min And Max Height
   if ( (fMinHeight > fMaxHeight) || (fMaxHeight < fMinHeight) )
   {
      Math::Swap( fMinHeight, fMaxHeight );
      m_fMinHeight = fMinHeight;
      m_fMaxHeight = fMaxHeight;
   }
   else if ( fMinHeight == fMaxHeight )
   {
      m_fMinHeight = 0.0f;
      m_fMaxHeight = 0.0f;
   }
   else
   {
      m_fMinHeight   = fMinHeight;
      m_fMaxHeight   = fMaxHeight;
   }

   m_fCurrentHeight = 0.0f;
   
   // Store Values
   m_fDepth   = fDepth;
   m_fWidth   = fWidth;
   m_iDivX      = iDivX;
   m_iDivZ      = iDivZ;

   m_bSmooth   = bSmooth;

   GenerateHeightMap();

   if ( m_bSmooth )
   {
      Smooth();
   }

   m_pV = new Vector3[(iDivX+1)*(iDivZ+1)];
   m_pT = new Vector2[(iDivX+1)*(iDivZ+1)];
   if ( m_pV && m_pT )
   {
      for ( int z = 0; z < (iDivZ+1); z++ )
      {
         for ( int x = 0; x < (iDivX+1); x++ )
         {
            // Assign Values To Vertex Coords
            m_pV[x+z*(iDivX+1)].m_fX = -fWidth/2 + x*fWidth/iDivX;
            m_pV[x+z*(iDivX+1)].m_fY =  m_vpHeights[x*z].m_fY;
            m_pV[x+z*(iDivX+1)].m_fZ = -fDepth/2 + z*fDepth/iDivZ;
            
            // Assign Values To Texture Coords
            m_pT[x+z*(iDivX+1)].m_fX = (float)x;
            m_pT[x+z*(iDivX+1)].m_fY = (float)(iDivZ - z);
      
         }   
      }
   }
   else
   {
      // Not Enough Memory
      if ( m_pV )
      {
         SAFE_DELETE_ARRAY( m_pV );
      }
      if ( m_pT )
      {
         SAFE_DELETE_ARRAY( m_pT );
      }
      if ( m_pN )
      {
         SAFE_DELETE_ARRAY( m_pN );
      }
   }

   

}

// ---------------------------------------------------------------------------------------------- //
// Name: ~GeometryTerrain()
// Desc: Default Destructor
// ---------------------------------------------------------------------------------------------- //
GeometryTerrain::~GeometryTerrain()
{
   // Incase Of Memory Leak
   SAFE_DELETE_ARRAY( m_pV );
   SAFE_DELETE_ARRAY( m_pT );
   SAFE_DELETE_ARRAY( m_pN );

} // ~GeometryTerrain()

// ---------------------------------------------------------------------------------------------- //
// Name: GenerateHeightMap()
// Desc:
// ---------------------------------------------------------------------------------------------- //
void GeometryTerrain::GenerateHeightMap()
{
   Vector3 v3CurrentPos;
   v3CurrentPos = Vector3();

   if ( (m_fMinHeight == 0.0f) && (m_fMaxHeight == 0.0f) )
   {
      for ( int iZ = 0; iZ < (m_iDivZ+1); iZ++ )
      {
         for ( int iX = 0; iX < (m_iDivX+1); iX++ )
         {
            m_fCurrentHeight = 0.0f;
            
            v3CurrentPos.m_fX = (float)iX;
            v3CurrentPos.m_fZ = m_fCurrentHeight;
            v3CurrentPos.m_fZ = (float)iZ;
            m_vpHeights.push_back( v3CurrentPos );
         }
      }
   }
   else
   {
      // Variables For Height Manipulation
      float fTempCurr = 0.0f;
      float fTempMin  = m_fMinHeight;
      float fTempMax  = m_fMaxHeight;
      
      for ( int iZ = 0; iZ < (m_iDivZ+1); iZ++ )
      {
         for ( int iX = 0; iX < (m_iDivX+1); iX ++ )
         {
            // Get Random Height At Each (X,Z)
            m_fCurrentHeight = Math::RandomRange( fTempMin, fTempMax );
            
            fTempCurr = m_fCurrentHeight;

            v3CurrentPos.m_fX = (float)iX;
            v3CurrentPos.m_fY = fTempCurr;
            v3CurrentPos.m_fZ = (float)iZ;
            m_vpHeights.push_back( v3CurrentPos );
            
         }
         fTempMin = (cos(fTempMin*0.9f));
         fTempMax = 1/(sin(fTempMax*0.9f));
         fTempCurr = 0.0f; // Reset Var
      }
   }

   for ( int i = 0; i < (int)m_vpHeights.size(); i++ )
   {
      m_vpHeights[i].m_fY = m_vpHeights[i].m_fY - 2.0f; // Downward Vertical Translation Of Entire Plane
   }

} // GenerateHeightMap

// ---------------------------------------------------------------------------------------------- //
// Name: Smooth()
// Desc: Smooth Out The Peaks: Average The Adjacent Vertices
// ---------------------------------------------------------------------------------------------- //
void GeometryTerrain::Smooth()
{
   Vector3 fPrev, fCurr, fNext, fAvg;
   for ( int iZ = 0; iZ < (m_iDivZ+1); iZ++ )
   {
      for ( int iX = 0; iX < (m_iDivX+1); iX++ )
      {
         fPrev.m_fY = m_vpHeights[(iX*iZ)].m_fY;
         fCurr.m_fY = m_vpHeights[(iX*iZ)+1].m_fY;
         fNext.m_fY = m_vpHeights[(iX*iZ)+2].m_fY;
      
         fAvg.m_fX = m_vpHeights[iX].m_fX;
         float fTemp = ((fPrev.m_fY+fCurr.m_fY+fNext.m_fY)/3.0f);
         fAvg.m_fY = cos(fTemp);
         fAvg.m_fZ = m_vpHeights[iZ].m_fZ;
         
         m_fCurrentHeight = fAvg.m_fY;
         m_vpHeights.push_back( fAvg );
      }
   }
} // Smooth

// ---------------------------------------------------------------------------------------------- //
// Name: RenderOGL()
// Desc:
// ---------------------------------------------------------------------------------------------- //
void GeometryTerrain::RenderOGL( bool bTexture )
{
   glNormal3f( 0.0f, 1.0f, 0.0f );

   if ( bTexture )
   {
      // Render Grid With Texture
      for ( int z = 0; z < m_iDivZ; z++ )
      {
         glBegin( GL_TRIANGLE_STRIP );
         for ( int x = 0; x < (m_iDivX+1); x++ )
         {
            glTexCoord2fv( m_pT[x+ z   *(m_iDivX+1)].m_f );
            glVertex3fv  ( m_pV[x+ z   *(m_iDivX+1)].m_f );
   
            glTexCoord2fv( m_pT[x+(z+1)*(m_iDivX+1)].m_f );
            glVertex3fv  ( m_pV[x+(z+1)*(m_iDivX+1)].m_f );
         }
         glEnd();
      }
   }
   else
   {
      // Render Grid Without A Texture
      for ( int z = 0; z < m_iDivZ; z++ )
      {
         glBegin( GL_TRIANGLE_STRIP );
         for ( int x = 0; x < (m_iDivX+1); x++ )
         {
            glVertex3fv  ( m_pV[x+ z   *(m_iDivX+1)].m_f );
            glVertex3fv  ( m_pV[x+(z+1)*(m_iDivX+1)].m_f );
         }
         glEnd();
      }
   }

   return;

} // RenderOGL

// ---------------------------------------------------------------------------------------------- //
// Name: Update()
// Desc:
// ---------------------------------------------------------------------------------------------- //
void GeometryTerrain::Update()
{
} // Update

// ---------------------------------------------------------------------------------------------- //
// Name: OutputTree()
// Desc:
// ---------------------------------------------------------------------------------------------- //
void GeometryTerrain::OutputTree()
{
   char szOutput[1024];
   _snprintf_s( szOutput, 1023, 1023, "Terrain geoID_%Id", this );

   // Show Values If They Are Not Their Defaults
   if ( m_fWidth != 1.0f )
   {
      _snprintf_s( szOutput, 1023, 1023, "%s wid_%f", szOutput, m_fWidth );
   }

   if ( m_fDepth != 1.0f )
   {
      _snprintf_s( szOutput, 1023, 1023, "%s dep_%f", szOutput, m_fDepth );
   }

   if ( (m_fMinHeight != 0.0f) || (m_fMaxHeight != 0.0f) )
   {
      _snprintf_s( szOutput, 1023, 1023, "%s min_%f max_%f", szOutput, m_fMinHeight, m_fMaxHeight );
   }

   if ( m_iDivX != 1 )
   {
      _snprintf_s( szOutput, 1023, 1023, "%s divx_%d", szOutput, m_iDivX );
   }

   if ( m_iDivZ != 1 )
   {
      _snprintf_s( szOutput, 1023, 1023, "%s divz_%d", szOutput, m_iDivZ );
   }

   if ( m_bSmooth == false )
   {
      _snprintf_s( szOutput, 1023, 1023, "%s smooth_0", szOutput );
   }

   s_pErrorHandler->SetError( EC_NoError, "%s", szOutput );
   
} // OutputTree


As a note the includes I have here are not the only includes you need.
I have the following includes in my Core.h file: #include "ColorOGL.h"(Not Needed here), "GeneralMath.h"(Needed), "Vector3.h"(Needed) and "Vector2.h"(Needed). The "Plane.h" here has not been used just yet but will be needed when calculating the Normals. If you have any comments or questions please feel free to post them here. I will try to answer any questions to the best of my knowledge or maybe some else can. I also look forward to your comments! :)

It is far from the state of the art random terrain editors out there, but the implementation is solely mine, thanks to the help of Marek for the basic structure of this class wich is His FlatGrid class. Thank You Marek! Im proud of my work here.


Last edited by skilz80 on Mon Nov 01, 2010 3:23 am, edited 1 time in total.

Offline
 Profile  
 
 Post subject: A Quick Tip!
PostPosted: Fri Oct 29, 2010 3:46 am 

Joined: Sat Aug 16, 2008 7:58 am
Posts: 447
About the above class, I have not yet integrated the players position with the height map, so the get a good viewing of it, check your Camera's or Players EyeLevel, from there set that to be the Terrains MaxHeight, then make the Min Height less. If you specify both of them to bee the same height you get a regular FlatGrid


Offline
 Profile  
 
 Post subject: A few edits to the code above!
PostPosted: Mon Nov 01, 2010 3:20 am 

Joined: Sat Aug 16, 2008 7:58 am
Posts: 447
I missed a crutial part in the smoothing function i forgot to index the prev, curr, and next values from the m_vpHeights. I also updated the generate height function so that the terrain varies in height at different locations across a large plane.. See the the first post for the updated code! Enjoy


Offline
 Profile  
 
Display posts from previous:  Sort by  
 Page 1 of 1 [ 3 posts ] 

All times are UTC - 5 hours


Who is online

Users browsing this forum: No registered users and 1 guest


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Jump to:  

cron