Understanding OpenGL terrain?

This is a discussion on Understanding OpenGL terrain? within the Game Programming forums, part of the General Programming Boards category; I have a simple DrawFloor() method here that came with my book. It doesn't share what the algorithm is here... ...

  1. #1
    Software engineer
    Join Date
    Aug 2005
    Location
    Oregon
    Posts
    283

    Understanding OpenGL terrain?

    I have a simple DrawFloor() method here that came with my book. It doesn't share what the algorithm is here... it just plots down some code and moves on. I tried doing this on paper. The camera is at (0,0,0) and it seems like 5 lines are ahead, and five lines are behind. I'm assuming whatever the extent is, it'll be double in the scene. I knocked it down to an extent of 5 instead of 20, and I thought it would clear some things up, but I'm lost in keeping track with where each line is being drawn. I would like to know what the pattern is anyway. This is along the XZ plane. If you can share what it is doing, I will email a cookie. Thanks, my mind is always wondering what algorithm was used before the code. This book is known for some code dumps.

    Code:
    void DrawGround(void)
    {
    	GLfloat fExtent = 5.0f;
    	GLfloat fStep = 1.0f;
    	GLfloat y = -0.4f;
    	GLint iLine;
    
    	glBegin(GL_LINES);
    		for (iLine = -fExtent; iLine <= fExtent; iLine += fStep) {
    			glVertex3f(iLine, y, fExtent);
    			glVertex3f(iLine, y, -fExtent);
    
    			glVertex3f(fExtent, y, iLine);
    			glVertex3f(-fExtent, y, iLine);
    		}
    	glEnd();
    }
    Here's a second code dump for your mind to boggle on. If there's an explanation on this second one too, I would be greatful. The end result draws a ground similar to the above, but it also places a 128x128 texture and it continues to repeat until the last line is drawn. I would like to see the pattern of these algorithms instead of code dumps. It is a good book but... argh! Are there any good sites that explain this kind of stuff?

    Code:
    void DrawGround(void) {
        GLfloat fExtent = 20.0f;
        GLfloat fStep = 1.0f;
        GLfloat y = -0.4f;
        GLint iStrip, iRun;
        GLfloat s = 0.0f;
        GLfloat t = 0.0f;
        GLfloat texStep = 1.0f / (fExtent * .075f);
        
        glBindTexture(GL_TEXTURE_2D, g_texState[TEX_GRASS]);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
        
        for(iStrip = -fExtent; iStrip <= fExtent; iStrip += fStep) {
            t = 0.0f;
            glBegin(GL_TRIANGLE_STRIP); 
                for(iRun = fExtent; iRun >= -fExtent; iRun -= fStep) {
                    glTexCoord2f(s, t);
                    //glNormal3f(0.0f, 1.0f, 0.0f);   // All Point up
                    glVertex3f(iStrip, y, iRun);
                    
                    glTexCoord2f(s + texStep, t);
                    //glNormal3f(0.0f, 1.0f, 0.0f);   // All Point up
                    glVertex3f(iStrip + fStep, y, iRun);
                    
                    t += texStep;
                    }
            glEnd();
            s += texStep;
         }
    }
    Last edited by dxfoo; 09-28-2006 at 04:49 PM.

  2. #2
    Software engineer
    Join Date
    Aug 2005
    Location
    Oregon
    Posts
    283
    Regarding the first one, I took a little extra time in figuring it out by taking out the bottom two glVertex3f() functions and watch what it does. I swapped them and saw what it was doing. The first two glVertex3f() functions draw the lines verticle, and the second two functions draw lines from left to right. I'm learning here...

  3. #3
    The Right Honourable psychopath's Avatar
    Join Date
    Mar 2004
    Location
    Where circles begin.
    Posts
    1,070
    The second one is the same concept as the first. The difference is that it renders a solid plane instead of a grid, and draws a texture. The texture coords are set based on the current step. It also uses seperate loops for X and Z, where iStrip is the X, and iRun is the Z.
    Memorial University of Newfoundland
    Computer Science

    Mac and OpenGL evangelist.

  4. #4
    Super Moderator VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,586
    There are a million approaches to terrain, but I highly recommend sticking with a regular grid. Some algos use a TIN or triangle irregular network but real time mesh deformation becomes a chore with those.

    The simplest grid I can come up with is. Some of this is Direct3D but most of it is non API specific.

    CTerrain.h

    Code:
    #define TERRAINVERTEX_FVF D3DFVF_XYZ | D3DFVF_TEX1
    
    struct TerrainVertex
    {
      float x,y,z;
      float TexU,TexV;
    
      static const DWORD FVF;
    
      TerrainVertex(float fx,float fy,float fz,float fu,float fv):
                            x(fx),y(fy),z(fz),TexU(fu),TexV(fv) { }
    
      TerrainVertex():x(0.0f),y(0.0f),z(0.0f),TexU(0.0f),TexV(0.0f) { }
    };
    
    
    class CTerrain
    {
      protected:
        TerrainVertex *m_pVerts;
    
        //For quad tree
        CBoundingBox *m_pBoundingVolume;
    
        ....
        ....
    };
    Code:
    #include "TerrainVertex.h"
    #include "CTerrain.h"
    
    void CTerrain::Create(int iWidth,int iDepth,int iCellSize,float fTexWrap)
    {
      //Compute verts per row and col
      m_iNumVertsPerCol=iDepth;
      m_iNumVertsPerRow=iWidth;
    
      //Compute cells per row and col
      m_iNumCellsPerCol=m_iNumVertsPerCol-1;
      m_iNumCellsPerRow=m_iNumVertsPerRow-1;
    
      //Compute total verts and number of triangles 
      m_iNumVerts=m_iNumVertsPerCol*m_iNumVertsPerRow;
      m_iNumTris=m_iNumCellsPerCol*m_iNumCellsPerRow*2;
    
      //For index buffer if needed - not used in this sample
      m_iNumIndices=m_iNumTris*3;
    
      //Allocate vertex buffer
      m_pVerts=new TerrainVertex[m_iNumVerts];
      if (!m_pVerts)
      {
        //Bail gracefully here since we could not allocate enough memory for vertex buffer
        ...
        ...
        return;
      }
    
      
      //Compute starting world locations for grid
      int iStartX=-(iWidth>>1)*iCellSize;
      int iStartZ=(iDepth>>1)*iCellSize;
      int iEndX=-iStartX;
      int iEndZ=-iStartZ;
    
      //Texture coordinate information
      float u=0.0f,v=0.0f;
      float fUInc=fTexWrap/(float)iWidth;
      float fVInc=fTexWrap/(float)iDepth;
    
      //Vertex height
      float fHeight=0.0f;
    
    
      //Row and col counters and index into array of verts
      int iRow=0,iCol=0;
      int iIndex=0;
    
      for (int z=iStartZ;z<iEndZ;z-=iCellSize)
      {
         for (int x=iStartX;x<iEndX;x+=iCellSize)
         {
            float fHeight=(float)m_pHeightMap->GetHeight(row,col);
    
            m_pVerts[iIndex]=TerrainVertex((float)x,fHeight,(float)z,(float)iRow*fUInc,(float)iCol*fVInc);
     
            iIndex++;
            iCol++;
         }
          iCol=0;
          iRow++;
        
       }
    
    
    }

    If I coded everything correctly there it will give you a simple regular grid of vertices. I coded this from memory while sitting here so I'm not guaranteeing it will work as is. After this you could create an index buffer and index into this vertex buffer to form each triangle. Or you can brute force it and do this while rendering.

    Note that since we get the value from a heightmap if you alter the heightmap and the corresponding vertex in the vertex buffer, you can deform the terrain. This can also be used to make a water plane applying a simple or complex water wave equation to produces waves across the grid. This gets into the area of displacement mapping and so I won't go into it.

    An ideal system would use the above algo to create a quadtree of the entire terrain world. Then at runtime you compute which areas are inside the frustum and draw those. The algo I presented can be changed to produce sections of regular grids all lined up next to each other.

    A simple quad tree structure would be:

    Code:
    enum TERRAIN_NODE_TYPE
    {
      LEAF_NODE,
      BRANCH_NODE
    };
    
    struct TerrainNode
    {
      TERRAIN_NODE_TYPE  iNodeType;
      CTerrain  *pUpperLeft;
      CTerrain  *pUpperRight;
      CTerrain  *pLowerLeft;
      CTerrain  *pLowerRight;
    };
    This should get you headed on the right track. Lots more info can be found at www.vterrain.org.

    This screenshot was produced with the above algo, with some added 'stuff'.
    Last edited by VirtualAce; 03-12-2011 at 10:42 AM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Difficult time understanding generating terrain (from file)
    By indigo0086 in forum Game Programming
    Replies: 3
    Last Post: 06-07-2007, 11:36 PM
  2. Continous LOD Terrain Source... Released!
    By Perspective in forum Game Programming
    Replies: 13
    Last Post: 04-17-2006, 11:21 PM
  3. OpenGL Window
    By Morgul in forum Game Programming
    Replies: 1
    Last Post: 05-15-2005, 12:34 PM
  4. OpenGL terrain demo (EDITOR)
    By Jeremy G in forum Game Programming
    Replies: 2
    Last Post: 03-30-2003, 07:11 PM
  5. OpenGL .dll vs video card dll
    By Silvercord in forum Game Programming
    Replies: 14
    Last Post: 02-12-2003, 06:57 PM

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21