# Terrain grid and OGL implementation

This topic is 4888 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

Hi, I'm trying to generate a terrain grid (say a simple 10X10 )but I can't work out the order of calls I need to make to glvertex() or glNormal() to calculate the polygon normals or vertex normals. I've got the tex coords right but can't work out how to get the triangles happening for my terrain. I've been pulling my hair out for days trying to get this right I'd be grateful if someone could help out . Regards :) glBegin(GL_TRIANGLE_STRIP); for (x = 0; x < MAP_SIZE; x++) { for (y = 0; y < MAP_SIZE; y++) { // for texturing float_x = (float) x /MAP_SIZE; float_y = (float) y /MAP_SIZE; float_xb = (float) (x + 1) / MAP_SIZE; float_yb = (float) (y + 1) / MAP_SIZE; glTexCoord2f(float_x, float_y); u.X = x; u.Y = y; u.Z = pHeightMap[x][y]; v.X = x; v.Y = y + 1; v.Z = pHeightMap[x][y + 1]; n = crossproduct(u,v); n = Normalize(n); glNormal3f(n.X,n.Y,n.Z); glVertex3f(x, y, pHeightMap[x][y]); glTexCoord2f(float_x, float_yb); glVertex3f(x , y + 1,pHeightMap[x][y + 1]); glTexCoord2f(float_xb, float_yb); u.X = x + 1; u.Y = y + 1; u.Z = pHeightMap[x + 1][y + 1]; v.X = x + 1; v.Y = y; v.Z = pHeightMap[x + 1][y]; n = crossproduct(u,v); n = Normalize(n); glVertex3f(x + 1, y + 1, pHeightMap[x + 1][y + 1]); glTexCoord2f(float_xb, float_y); glVertex3f(x + 1,y, pHeightMap[x + 1][y]); } } glEnd();

##### Share on other sites
Here's my terrain drawing code that I made yesterday, you'll have to figure out how it works tho :)

Some weirdnesses that you probably can't know: a, b and c are 3 outer corners of the terrain map. The variables cam and ot define the transformation from object to camera space. Scalar is the same as the type double. sizex and sizey are the number of squares of the terrain (or the number of values of the heightmap). The colormap multiplies colors with all the squares of the terrain and is as big as the heightmap. There are 2 triangles per terrain square.

void draw3DTerrain(Vector3 a, Vector3 b, Vector3 c, Scalar* heightMap, int sizex, int sizey, Texture &t, Vector2 texa, Vector2 texb, Vector2 texc, ColorRGB color, bool enableColorMap, Texture &colorMap, Camera &cam, ObjectTransformator &ot)
{
CamAndOtToMODELVIEW(cam, ot);

Vector3 d = b + c - a;

//you give 3 points, the 4th corner will be so that the shape is a parallellogram

Vector3 sw = (b - a) / (sizex - 1); //width of a single terrain square
Vector3 sh = (c - a) / (sizey - 1); //height of a single terrain square
Vector3 up = normalize(normalOfTriangle(a, b, c)); //the direction used for the heights of the terrain

Vector2 texsw = (texb - texa) / (sizex - 1);
Vector2 texsh = (texc - texa) / (sizey - 1);

glColor4ub(color.r, color.g, color.b, color.a);
glEnable(GL_TEXTURE_2D);
bindTexture(t);

//for every square of the terrain (each square will be made of 2 or 4 triangles btw)
glBegin(GL_TRIANGLES);
for(int tx = 0; tx < sizex - 1; tx++)
for(int ty = 0; ty < sizey - 1; ty++)
{
Vector3 ta = a + sw * (tx + 0) + sh * (ty + 0);
Vector3 tb = a + sw * (tx + 1) + sh * (ty + 0);
Vector3 tc = a + sw * (tx + 0) + sh * (ty + 1);
Vector3 td = a + sw * (tx + 1) + sh * (ty + 1);

Scalar heighta = heightMap[sizey * (ty + 0) + (tx + 0)];
Scalar heightb = heightMap[sizey * (ty + 0) + (tx + 1)];
Scalar heightc = heightMap[sizey * (ty + 1) + (tx + 0)];
Scalar heightd = heightMap[sizey * (ty + 1) + (tx + 1)];

ta = ta + up * heighta;
tb = tb + up * heightb;
tc = tc + up * heightc;
td = td + up * heightd;

Vector2 ttexa = texa + texsw * (tx + 0) + texsh * (ty + 0);
Vector2 ttexb = texa + texsw * (tx + 1) + texsh * (ty + 0);
Vector2 ttexc = texa + texsw * (tx + 0) + texsh * (ty + 1);
Vector2 ttexd = texa + texsw * (tx + 1) + texsh * (ty + 1);

if(enableColorMap) glColor4ub(colorMap.getPixel(tx + 0, ty + 0, 0), colorMap.getPixel(tx + 0, ty + 0, 1), colorMap.getPixel(tx + 0, ty + 0, 2), colorMap.getPixel(tx + 0, ty + 0, 3));
glTexCoord2f(ttexa.x, ttexa.y); glVertex3d(ta.x, ta.y, ta.z);
if(enableColorMap) glColor4ub(colorMap.getPixel(tx + 1, ty + 0, 0), colorMap.getPixel(tx + 1, ty + 0, 1), colorMap.getPixel(tx + 1, ty + 0, 2), colorMap.getPixel(tx + 1, ty + 0, 3));
glTexCoord2f(ttexb.x, ttexb.y); glVertex3d(tb.x, tb.y, tb.z);
if(enableColorMap) glColor4ub(colorMap.getPixel(tx + 0, ty + 1, 0), colorMap.getPixel(tx + 0, ty + 1, 1), colorMap.getPixel(tx + 0, ty + 1, 2), colorMap.getPixel(tx + 0, ty + 1, 3));
glTexCoord2f(ttexc.x, ttexc.y); glVertex3d(tc.x, tc.y, tc.z);

if(enableColorMap) glColor4ub(colorMap.getPixel(tx + 1, ty + 1, 0), colorMap.getPixel(tx + 1, ty + 1, 1), colorMap.getPixel(tx + 1, ty + 1, 2), colorMap.getPixel(tx + 1, ty + 1, 3));
glTexCoord2f(ttexd.x, ttexd.y); glVertex3d(td.x, td.y, td.z);
if(enableColorMap) glColor4ub(colorMap.getPixel(tx + 0, ty + 1, 0), colorMap.getPixel(tx + 0, ty + 1, 1), colorMap.getPixel(tx + 0, ty + 1, 2), colorMap.getPixel(tx + 0, ty + 1, 3));
glTexCoord2f(ttexc.x, ttexc.y); glVertex3d(tc.x, tc.y, tc.z);
if(enableColorMap) glColor4ub(colorMap.getPixel(tx + 1, ty + 0, 0), colorMap.getPixel(tx + 1, ty + 0, 1), colorMap.getPixel(tx + 1, ty + 0, 2), colorMap.getPixel(tx + 1, ty + 0, 3));
glTexCoord2f(ttexb.x, ttexb.y); glVertex3d(tb.x, tb.y, tb.z);

}
glEnd();

glMatrixMode(GL_MODELVIEW);
}

And now I'm going to try to implement quadtrees for optimization.

##### Share on other sites
The usual approach for smoothing normals it to firstly calculate face normals (this is equivalent to flat shading). A second pass then constructs the vertex normals by, for each vertex, adding the normals of all faces that this vertex is a part of, and normalising the result (best to do this normalising in a third pass). This will mean that the effect that a given flat surface has on a vertex normal is proportional to the area of this flat surface, which produces quite a nice effect. Therefore, in pseudo-code, you have something like this:

//this stores 3 indices into an array of vertices - the points of the triangle,
//and one normal - the face normal
structure Triangle
{
int vertex_index[3];
Vector face_normal;
}

Array triangles[ NUM_TRIANGLES_IN_MAP ]
for i = 0 to NUM_TRIANGLES_IN_MAP
{
//find the face normals and store them
triangles.face_normal = CrossProduct( vertices[ triangles.vertex_index[0] ] - vertices[ triangles.vertex_index[1] ], vertices[ triangles.vertex_index[0] ] - vertices[ triangles.vertex_index[2] ] );
}

Array vertex_normals[ NUM_VERTICES_IN_MAP ];
//you might need to make sure that these vertex normals are all
//initialised to (0, 0, 0)
for i = 0 to NUM_TRIANGLES_IN_MAP
{
//construct the unnormalised vertex normals
for j = 0 to 3
{
vertex_normals[ triangles.vertex_index[j] ] += triangles.face_normal;
}
}

//normalise them
for( i = 0 to NUM_VERTICES_IN_MAP
{
vertex_normals.Normalise();
}

//.....................................
//Now when drawing, you can do something like:

glNormal3fv( &vertex_normals[ triangles.vertex_index[j] ] );
glVertex3fv( &vertices[ triangles.vertex_index[j] ] );

That should hopefully give you enough to get started with.

##### Share on other sites
There may be a problem with the the glBegin( GL_TRIANGLE_STRIP ) -- glEnd() calls ..
For a point grid in 2 dimensions the code should look like this ::

for( int i =0;i<I_MAP_SIZE;++i){
glBegin( GL_TRIANGLE_STRIP );
for( int j=0;j<J_MAP_SIZE:++j ){
glNormal();
glVertex();
glNormal();
glVertex();
}
glEnd();
}
The idea is that u need to end the strip after a row and start a new strip for the next row.

##### Share on other sites
Thanks Guys, Much appreciated , I'll see how I go.

Regards

##### Share on other sites
Hey, I just changed the code to use trianglestrips instead of triangles, because it goes so much faster. This code is the same as the code I posted above except now it uses trianglestrips:

void draw3DTerrain(Vector3 a, Vector3 b, Vector3 c, Scalar* heightMap, int sizex, int sizey, Texture &t, Vector2 texa, Vector2 texb, Vector2 texc, ColorRGB color, bool enableColorMap, Texture &colorMap, Camera &cam, ObjectTransformator &ot)
{
CamAndOtToMODELVIEW(cam, ot);

Vector3 d = b + c - a;

//you give 3 points, the 4th corner will be so that the shape is a parallellogram
//the terrain will be made out of terrain squares that depend on the heightmap

Vector3 sw = (b - a) / (sizex - 1); //width of a single terrain square
Vector3 sh = (c - a) / (sizey - 1); //height of a single terrain square
Vector3 up = normalize(normalOfTriangle(a, b, c)); //the direction used for the heights of the terrain

Vector2 texsw = (texb - texa) / (sizex - 1);
Vector2 texsh = (texc - texa) / (sizey - 1);

glColor4ub(color.r, color.g, color.b, color.a);
glEnable(GL_TEXTURE_2D);
bindTexture(t);

for(int tx = 0; tx < sizex - 1; tx++)
{
glBegin(GL_TRIANGLE_STRIP);

Vector3 ta = a + sw * (tx + 0) + sh * (0 + 0);
Vector3 tb = a + sw * (tx + 1) + sh * (0 + 0);
Vector3 tc = a + sw * (tx + 0) + sh * (0 + 1);
Vector3 td = a + sw * (tx + 1) + sh * (0 + 1);

int hIndexa = sizey * (0 + 0) + (tx + 0);
int hIndexb = sizey * (0 + 0) + (tx + 1);
int hIndexc = sizey * (0 + 1) + (tx + 0);
int hIndexd = sizey * (0 + 1) + (tx + 1);

Scalar heighta = heightMap[hIndexa];
Scalar heightb = heightMap[hIndexb];
Scalar heightc = heightMap[hIndexc];
Scalar heightd = heightMap[hIndexd];

ta = ta + up * heighta;
tb = tb + up * heightb;

Vector2 ttexa = texa + texsw * (tx + 0) + texsh * (0 + 0);
Vector2 ttexb = texa + texsw * (tx + 1) + texsh * (0 + 0);
Vector2 ttexc = texa + texsw * (tx + 0) + texsh * (0 + 1);
Vector2 ttexd = texa + texsw * (tx + 1) + texsh * (0 + 1);

if(enableColorMap) glColor4ub(colorMap.getPixel(tx + 0, 0 + 0, 0), colorMap.getPixel(tx + 0, 0 + 0, 1), colorMap.getPixel(tx + 0, 0 + 0, 2), colorMap.getPixel(tx + 0, 0 + 0, 3));
glTexCoord2f(ttexa.x, ttexa.y); glVertex3d(ta.x, ta.y, ta.z);
if(enableColorMap) glColor4ub(colorMap.getPixel(tx + 1, 0 + 0, 0), colorMap.getPixel(tx + 1, 0 + 0, 1), colorMap.getPixel(tx + 1, 0 + 0, 2), colorMap.getPixel(tx + 1, 0 + 0, 3));
glTexCoord2f(ttexb.x, ttexb.y); glVertex3d(tb.x, tb.y, tb.z);

for(int ty = 0; ty < sizey - 1; ty++)
{
heightc = heightMap[hIndexc];
heightd = heightMap[hIndexd];
//add current height to the vectors
tc = tc + up * heightc;
td = td + up * heightd;
//give OpenGL the vertices of the next triangles of the triangle strip
if(enableColorMap) glColor4ub(colorMap.getPixel(tx + 0, ty + 1, 0), colorMap.getPixel(tx + 0, ty + 1, 1), colorMap.getPixel(tx + 0, ty + 1, 2), colorMap.getPixel(tx + 0, ty + 1, 3));
glTexCoord2f(ttexc.x, ttexc.y); glVertex3d(tc.x, tc.y, tc.z);
if(enableColorMap) glColor4ub(colorMap.getPixel(tx + 1, ty + 1, 0), colorMap.getPixel(tx + 1, ty + 1, 1), colorMap.getPixel(tx + 1, ty + 1, 2), colorMap.getPixel(tx + 1, ty + 1, 3));
glTexCoord2f(ttexd.x, ttexd.y); glVertex3d(td.x, td.y, td.z);

//subtract current hight off of it again, because tc and td at "ground level" will be reused for next loop
tc = tc - up * heightc;
td = td - up * heightd;
//make the values ready for the next loop
tc = tc + sh;
td = td + sh;
hIndexc += sizex;
hIndexd += sizex;
ttexc = ttexc + texsh;
ttexd = ttexd + texsh;
}
glEnd();
}

glMatrixMode(GL_MODELVIEW);
}

##### Share on other sites
Hope u see how Lode has ended the glBegin( GL_TRI_STRIP ) within the inner loop . Thats exactly what i said

• ### What is your GameDev Story?

In 2019 we are celebrating 20 years of GameDev.net! Share your GameDev Story with us.

• 13
• 9
• 15
• 14
• 46
• ### Forum Statistics

• Total Topics
634059
• Total Posts
3015291
×