texturing question

I’m using a .RAW height map and want to apply two textures to the terrain, but without using mulitexturing. My scaled terrain height ranges between 0 to 40, I have taken a simple texture for grass, copied it and modified it for my snow texture. I have a variable called SNOW_CAP (approx scaled height 32) which is the starting point for the “snow-line”, above this value I want to use my snow texture, below this value I will use a grass texture. Currently in trying to use a multi-pass approach:

  1. draw the terrain above the “snowline” with the snow texture (1st pass)
  2. draw the grass section below the “snowline”.(2nd pass)
  3. draw the water level (scaled height of 8 - 3rd pass)

here is the initializing code


        image.Load("grass.tga");
        glGenTextures(1, &m_grassTexture);
        glBindTexture(GL_TEXTURE_2D, m_grassTexture);
        gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB, image.GetWidth(), 
		image.GetHeight(), GL_RGB, GL_UNSIGNED_BYTE, image.GetImage());
	image.Release();

	image.Load("snow.tga");
	glGenTextures(1, &m_snowTexture);
	glBindTexture(GL_TEXTURE_2D, m_snowTexture);
	gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB, image.GetWidth(),
		image.GetHeight(), GL_RGB, GL_UNSIGNED_BYTE, image.GetImage());
	image.Release();

	image.Load("water.tga");
	glGenTextures(1, &m_waterTexture);
	glBindTexture(GL_TEXTURE_2D, m_waterTexture);
	gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB, image.GetWidth(),
		image.GetHeight(), GL_RGB, GL_UNSIGNED_BYTE, image.GetImage());
	image.Release();

And this is my drawing function:


void CGfxOpenGL::DrawTerrain()
{
	 
	//draw the terrain using the snow texture  ABOVE  SNOW_CAP
	//first pass
	glBindTexture(GL_TEXTURE_2D, m_snowTexture);
	//glTexEnvfv(GL_TEXTURE_ENV,GL_TEXTURE_ENV_COLOR,WHITE);
	glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE);
	for (int z = 0; z < TERRAIN_SIZE - 1; ++z)
	{
		glBegin(GL_TRIANGLE_STRIP);
		for (int x = 0; x < TERRAIN_SIZE ; ++x)
		//for (int x = TERRAIN_SIZE; x < 0; --x)
		{
			if ((heightmap[z * TERRAIN_SIZE + x] / SCALE_FACTOR) >= SNOW_CAP)
			{
				// render two vertices of the strip at once
				float scaledHeight = heightmap[z * TERRAIN_SIZE + x] / SCALE_FACTOR;
				float nextScaledHeight = heightmap[(z + 1)* TERRAIN_SIZE + x] / SCALE_FACTOR;
				float color = 0.35 + 1.0f * scaledHeight / MAX_HEIGHT;
				float nextColor = 0.35 + 1.0f * nextScaledHeight / MAX_HEIGHT;
				glColor3f(color, color, color);
				glTexCoord2f((GLfloat)x/TERRAIN_SIZE*8, (GLfloat)z/TERRAIN_SIZE*8);
				glVertex3f(static_cast<GLfloat>(x - TERRAIN_SIZE/2), scaledHeight,
					static_cast<GLfloat>(z - TERRAIN_SIZE/2));
				glColor3f( nextColor, nextColor, nextColor);
				glTexCoord2f((GLfloat)x/TERRAIN_SIZE*8, (GLfloat)(z+1)/TERRAIN_SIZE*8);
				glVertex3f(static_cast<GLfloat>(x - TERRAIN_SIZE/2), nextScaledHeight, 
					static_cast<GLfloat>(z + 1 - TERRAIN_SIZE/2));
			}
		}
   		glEnd();
	}
	
	//second pass
	//only draw the area BELOW the
	//SNOW_CAP
	glBindTexture(GL_TEXTURE_2D, m_grassTexture);
	glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_REPLACE);
	for (int z = 0; z < TERRAIN_SIZE - 1; ++z)
	{
		glBegin(GL_TRIANGLE_STRIP);
		for (int x = 0; x < TERRAIN_SIZE; ++x)
		//for (int x = TERRAIN_SIZE; x < 0; --x)
		{	
			if((heightmap[z * TERRAIN_SIZE + x] / SCALE_FACTOR) <= SNOW_CAP)
			{
				// render two vertices of the strip at once
				float scaledHeight = heightmap[z * TERRAIN_SIZE + x] / SCALE_FACTOR;
				float nextScaledHeight = heightmap[(z + 1)* TERRAIN_SIZE + x] / SCALE_FACTOR;
				float color = 0.5 + 1.0f * scaledHeight / MAX_HEIGHT;
				float nextColor = 0.5 + 1.0f * nextScaledHeight / MAX_HEIGHT;
				glColor3f(color,color,color);
				glTexCoord2f((GLfloat)x/TERRAIN_SIZE*8, (GLfloat)z/TERRAIN_SIZE*8);
				glVertex3f(static_cast<GLfloat>(x - TERRAIN_SIZE/2), scaledHeight, 
					static_cast<GLfloat>(z - TERRAIN_SIZE/2));
				glColor3f(nextColor, nextColor, nextColor);
				glTexCoord2f((GLfloat)x/TERRAIN_SIZE*8, (GLfloat)(z+1)/TERRAIN_SIZE*8);
				glVertex3f(static_cast<GLfloat>(x - TERRAIN_SIZE/2), nextScaledHeight, 
					static_cast<GLfloat>(z + 1 - TERRAIN_SIZE/2));
			}
		}
		glEnd();
	} 
	
	//draw the water (functional)
	glBindTexture(GL_TEXTURE_2D, m_waterTexture);
	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
	glBegin(GL_QUADS);
		glTexCoord2f(0.0, 0.0);
		glVertex3f(-TERRAIN_SIZE/2.1f, WATER_HEIGHT, TERRAIN_SIZE/2.1f);
   		glTexCoord2f(TERRAIN_SIZE/4.0f, 0.0);
		glVertex3f(TERRAIN_SIZE/2.1f, WATER_HEIGHT, TERRAIN_SIZE/2.1f);
   		glTexCoord2f(TERRAIN_SIZE/4.0f, TERRAIN_SIZE/4.0f);
		glVertex3f(TERRAIN_SIZE/2.1f, WATER_HEIGHT, -TERRAIN_SIZE/2.1f);
   		glTexCoord2f(0.0, TERRAIN_SIZE/4.0f);
		glVertex3f(-TERRAIN_SIZE/2.1f, WATER_HEIGHT, -TERRAIN_SIZE/2.1f);
	glEnd();
}

At this point I get a "snow bridge from one snow cap peak to another, and I have “wholes” in a few locations are ound the snow line, How can I correct this?

Try drawing each pass separately to determine if they work as expected. Can you supply a screen shot of the issue?

@BionicBytes
I have tried segregating the first terrain pass with the second. The first pass, that draws above the “snow line” always shows artifacts connecting the two highest points of the terrain. The second pass, also shows artifacts, connecting spaces that are not being mapped by the grass texture(I assumed this would not be a problem, because once the snow is correctly mapped, the only way to see the grass texture artifacts would be to look at them from the underside of the terrain map - which culling should eliminate, and compensate for the performance hit by actually drawing the land in two passes).

What I also tried to do, during the first pass, was to map the entire terrain in the snow texture. Then run the second pass with the grass texture and only texture the vertices below the snow line. I initially thought that this would be a better method, with less possible artifact problems, but when trying it, I can never get the second pass with the grass texture to be visible in the scene.

glBegin(GL_TRIANGLE_STRIP);
  for (int x = 0; x < TERRAIN_SIZE ; ++x) {
    if ((heightmap[z * TERRAIN_SIZE + x] / SCALE_FACTOR) >= SNOW_CAP)

Here it is.
You need to skip the whole triangle, not just the vertex which is below the snow cap.
Otherwise your tristrip will of course continue to the next vertex which is above snow cap.
Try adapting your rendering with GL_TRIANGLES, then test each of the 3 vertices, if any is above snowcap, draw snow triangle, otherwise draw grass triangle.

ZbuffeR is dead right - the triangle is started but not finished as you expected.

On another note entirely - becareful with: glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_REPLACE);

…as your next step is most likely to add lighting - and this REPLACE environment mode will not react to fixed function OpenGL lighting as you might expect. Use GL_MODULATE instead.

@BionocBytes


  float color = 0.5 + 1.0f * scaledHeight / MAX_HEIGHT;

-GL_REPLACE seems to negate any adjustment(like the code above) and it shows up noticeably when I use the snow texture for the entire terrain.

@BionicBytes & ZbuffeR
I created a struct in my fx.cpp file (where the terrain draw function is


struct vertex {
    int x;
    int y;
    int z;
};

then created three holding variables vertex0, vertex1, vertex2 and added them within the drawing nested loops


 vertex vertex0, vertex1, vertex2;

	//draw the terrain using the snow texture  
	//first pass
	glBindTexture(GL_TEXTURE_2D, m_snowTexture);
	//glTexEnvfv(GL_TEXTURE_ENV,GL_TEXTURE_ENV_COLOR,WHITE);
	glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE);
	for (int z = 0; z < TERRAIN_SIZE - 1; ++z)
	//for(int z = (TERRAIN_SIZE-1); z >=0; --z)
	{
		glBegin(GL_TRIANGLE_STRIP);
		for (int x = 0; x < TERRAIN_SIZE ; ++x)
		//for (int x = TERRAIN_SIZE; x < 0; --x)
		{
				vertex0.x = (x - TERRAIN_SIZE/2);
				vertex0.y = heightmap[z * TERRAIN_SIZE + x] / SCALE_FACTOR;  ;
				vertex0.z = (z - TERRAIN_SIZE/2);
				vertex1.x = ((x+1) - TERRAIN_SIZE/2);
				vertex1.y = heightmap[(z + 1)* TERRAIN_SIZE + x] / SCALE_FACTOR;
				vertex1.z = ((z+1) - TERRAIN_SIZE/2);
				vertex2.x = ((x+2) - TERRAIN_SIZE/2);
				vertex2.y = heightmap[(z + 2)* TERRAIN_SIZE + x] / SCALE_FACTOR ;
				vertex2.z = ((z+2) - TERRAIN_SIZE/2);
						
			if((vertex0.y >= SNOW_CAP) || (vertex1.y >= SNOW_CAP) || (vertex2.y >= SNOW_CAP))			
			{
				// render two vertices of the strip at once
				float scaledHeight = heightmap[z * TERRAIN_SIZE + x] / SCALE_FACTOR;
				float nextScaledHeight = heightmap[(z + 1)* TERRAIN_SIZE + x] / SCALE_FACTOR;
				float color = 0.35 + 1.0f * scaledHeight / MAX_HEIGHT;
				float nextColor = 0.35 + 1.0f * nextScaledHeight / MAX_HEIGHT;
				glColor3f(color, color, color);
				glTexCoord2f((GLfloat)x/TERRAIN_SIZE*8, (GLfloat)z/TERRAIN_SIZE*8);
				glVertex3f(static_cast<GLfloat>(x - TERRAIN_SIZE/2), scaledHeight,
					static_cast<GLfloat>(z - TERRAIN_SIZE/2));
				glColor3f( nextColor, nextColor, nextColor);
				glTexCoord2f((GLfloat)x/TERRAIN_SIZE*8, (GLfloat)(z+1)/TERRAIN_SIZE*8);
				glVertex3f(static_cast<GLfloat>(x - TERRAIN_SIZE/2), nextScaledHeight, 
					static_cast<GLfloat>(z + 1 - TERRAIN_SIZE/2));
			}
		}
   		glEnd();
	}

My if statement checks each of the 3 vertices, but only the y component(the part mapped by the heightmap), I still get the “landbridge” connecting the peaks and a small number of artifact tris, should my if statement make 3 OR checks as above or should it make 9 OR checks, one for each x,y,z component?

Here is what I did to get to this screen shot

  1. map the entire terrain using the snow texture
  2. map the terrain below the “snow line” with the grass texture, but adjusted the height for every vertex drawn by +0.1
  3. map the water texture

void CGfxOpenGL::DrawTerrain()
{
	 vertex vertex0, vertex1, vertex2;

	//draw the terrain using the snow texture  
	//first pass
	glBindTexture(GL_TEXTURE_2D, m_snowTexture);
	glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE);
	for (int z = 0; z < TERRAIN_SIZE - 1; ++z)
	{
		glBegin(GL_TRIANGLE_STRIP);
		for (int x = 0; x < TERRAIN_SIZE; ++x)
		{
		 		// render two vertices of the strip at once
				float scaledHeight = heightmap[z * TERRAIN_SIZE + x] / SCALE_FACTOR;
				float nextScaledHeight = heightmap[(z + 1)* TERRAIN_SIZE + x] / SCALE_FACTOR;
				float color = 0.35 + 1.0f * scaledHeight / MAX_HEIGHT;
				float nextColor = 0.35 + 1.0f * nextScaledHeight / MAX_HEIGHT;
				glColor3f(color, color, color);
				glTexCoord2f((GLfloat)x/TERRAIN_SIZE*8, (GLfloat)z/TERRAIN_SIZE*8);
				glVertex3f(static_cast<GLfloat>(x - TERRAIN_SIZE/2), scaledHeight,
					static_cast<GLfloat>(z - TERRAIN_SIZE/2));
				glColor3f( nextColor, nextColor, nextColor);
				glTexCoord2f((GLfloat)x/TERRAIN_SIZE*8, (GLfloat)(z+1)/TERRAIN_SIZE*8);
				glVertex3f(static_cast<GLfloat>(x - TERRAIN_SIZE/2), nextScaledHeight, 
					static_cast<GLfloat>(z + 1 - TERRAIN_SIZE/2));
		}
		glEnd();
	}
	
	//second pass - only draw the area BELOW the SNOW_CAP
	glBindTexture(GL_TEXTURE_2D, m_grassTexture);
	glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_COMBINE);
	glTexEnvf(GL_TEXTURE_ENV,GL_COMBINE_RGB,GL_MODULATE);
	for (int z = 0; z < TERRAIN_SIZE - 1; ++z)
	{
		glBegin(GL_TRIANGLE_STRIP);
		for (int x = 0; x < TERRAIN_SIZE; ++x)
		{	
				//vertex0.x = (x - TERRAIN_SIZE/2);
				vertex0.x = x;
				vertex0.y = heightmap[z * TERRAIN_SIZE + x] / SCALE_FACTOR;  ;
				vertex0.z = z;
				vertex1.x = (x+1);
				vertex1.y = heightmap[(z + 1)* TERRAIN_SIZE + x] / SCALE_FACTOR;
				vertex1.z = (z+1);
				vertex2.x = (x+2);
				vertex2.y = heightmap[(z + 2)* TERRAIN_SIZE + x] / SCALE_FACTOR ;
				vertex2.z = (z+2);
						
			if((vertex0.x <= SNOW_CAP) || (vertex0.y <= SNOW_CAP) || (vertex0.z <= SNOW_CAP) || 
			   (vertex1.x <= SNOW_CAP) || (vertex1.y <= SNOW_CAP) || (vertex1.z <= SNOW_CAP) ||
			   (vertex2.x <= SNOW_CAP) || (vertex2.y <= SNOW_CAP) || (vertex2.z <= SNOW_CAP))
			{
				// render two vertices of the strip at once
				float scaledHeight = (heightmap[z * TERRAIN_SIZE + x] / SCALE_FACTOR) + .1;
				float nextScaledHeight = (heightmap[(z + 1)* TERRAIN_SIZE + x] / SCALE_FACTOR) + .1;
				float color = 0.3 + 1.0f * scaledHeight / MAX_HEIGHT;
				float nextColor = 0.3 + 1.0f * nextScaledHeight / MAX_HEIGHT;
				glColor3f(color,color,color);
				glTexCoord2f((GLfloat)x/TERRAIN_SIZE*8, (GLfloat)z/TERRAIN_SIZE*8);
				glVertex3f(static_cast<GLfloat>(x - TERRAIN_SIZE/2), scaledHeight, 
					static_cast<GLfloat>(z - TERRAIN_SIZE/2));
				glColor3f(nextColor, nextColor, nextColor);
				glTexCoord2f((GLfloat)x/TERRAIN_SIZE*8, (GLfloat)(z+1)/TERRAIN_SIZE*8);
				glVertex3f(static_cast<GLfloat>(x - TERRAIN_SIZE/2), nextScaledHeight, 
					static_cast<GLfloat>(z + 1 - TERRAIN_SIZE/2));
			}
		}
		glEnd();
	} 
	
	//draw the water (functional)
	glBindTexture(GL_TEXTURE_2D, m_waterTexture);
	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
	glBegin(GL_QUADS);
		glTexCoord2f(0.0, 0.0);
		glVertex3f(-TERRAIN_SIZE/2.1f, WATER_HEIGHT, TERRAIN_SIZE/2.1f);
   		glTexCoord2f(TERRAIN_SIZE/4.0f, 0.0);
		glVertex3f(TERRAIN_SIZE/2.1f, WATER_HEIGHT, TERRAIN_SIZE/2.1f);
   		glTexCoord2f(TERRAIN_SIZE/4.0f, TERRAIN_SIZE/4.0f);
		glVertex3f(TERRAIN_SIZE/2.1f, WATER_HEIGHT, -TERRAIN_SIZE/2.1f);
   		glTexCoord2f(0.0, TERRAIN_SIZE/4.0f);
		glVertex3f(-TERRAIN_SIZE/2.1f, WATER_HEIGHT, -TERRAIN_SIZE/2.1f);
	glEnd();
}

I guess my question now is, would this be considered a viable solution?

What part of “Try adapting your rendering with GL_TRIANGLES” you did not understand ?

@ZbuffeR
I haven’t abandoned your solution to use GL_TRIANGLES, I just haven’t got it running yet, sometimes to figure a coding problem out, I go “old school” (aka pen & paper) :wink:

i would say in your if statement (to check which zone its in) if its in a different zone than your drawing on that pass, then call glEnd() and resume drawing when you hit the next peak by calling glBegin(GL_TRIANGLE_STRIP). your getting land bridges because you’re using GL_TRIANGLE_STRIP. I ran into this problem a lot rendering terrain…

k so I got the grass texture to process through GL_TRIANGLES but there is an obvious problem, not only did I not properly line up the tris but there are untextured gaps, if you look at the screen shot(04)(thanks to ZbuffeR’s keen observation) versus the previous one a few posts up (prior to the “Zs” keen observation) I think the terrain is starting to look more realistic and less tiled.

Here’s the code(I used GL_BLEND to make the grass tex easier to spot


        vertex[6];
	float Height[6];
	float color[6];

	//draw the terrain using the snow texture  - first pass
	glBindTexture(GL_TEXTURE_2D, m_snowTexture);
	glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE);
	for (int z = 0; z < TERRAIN_SIZE - 1; ++z)
	{
		glBegin(GL_TRIANGLE_STRIP);//I will change this once I get the grass working
		for (int x = 0; x < TERRAIN_SIZE; ++x)
		{
		 		// render two vertices of the strip at once
				float scaledHeight = heightmap[z * TERRAIN_SIZE + x] / SCALE_FACTOR;
				float nextScaledHeight = heightmap[(z + 1)* TERRAIN_SIZE + x] / SCALE_FACTOR;
				float color = 0.35 + 1.0f * scaledHeight / MAX_HEIGHT;
				float nextColor = 0.35 + 1.0f * nextScaledHeight / MAX_HEIGHT;
				glColor3f(color, color, color);
				glTexCoord2f((GLfloat)x/TERRAIN_SIZE*8, (GLfloat)z/TERRAIN_SIZE*8);
				glVertex3f(static_cast<GLfloat>(x - TERRAIN_SIZE/2), scaledHeight,
					static_cast<GLfloat>(z - TERRAIN_SIZE/2));
				glColor3f( nextColor, nextColor, nextColor);
				glTexCoord2f((GLfloat)x/TERRAIN_SIZE*8, (GLfloat)(z+1)/TERRAIN_SIZE*8);
				glVertex3f(static_cast<GLfloat>(x - TERRAIN_SIZE/2), nextScaledHeight, 
					static_cast<GLfloat>(z + 1 - TERRAIN_SIZE/2));
		}
		glEnd();
	}

	//second pass - only draw the area BELOW the SNOW_CAP
	glBindTexture(GL_TEXTURE_2D, m_grassTexture);
	glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_DECAL);	
	//glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_COMBINE);
	//glTexEnvf(GL_TEXTURE_ENV,GL_COMBINE,GL_MODULATE);
	for (int x = 0; x < TERRAIN_SIZE ; ++x)
	{
		glBegin(GL_TRIANGLES);
		for (int z = 0; z < TERRAIN_SIZE-1; ++z)
		{
				//verts for 1st tri
				vertex[0].x = x;
				vertex[0].z = z;
				vertex[0].y = heightmap[vertex[0].z * TERRAIN_SIZE + vertex[0].x] / SCALE_FACTOR;
				Height[0] = (heightmap[vertex[0].z * TERRAIN_SIZE + vertex[0].x] / SCALE_FACTOR);
				color[0] = x + 1.0f * Height[0] / MAX_HEIGHT;

				vertex[1].x = vertex[0].x + 1;
				vertex[1].z = z;
				vertex[1].y = heightmap[vertex[1].z * TERRAIN_SIZE + vertex[1].x] / SCALE_FACTOR;
				Height[1] = (heightmap[vertex[0].z * TERRAIN_SIZE + vertex[1].x] / SCALE_FACTOR);
				color[1] = x + 1.0f * Height[1] / MAX_HEIGHT;
				
				vertex[2].x = vertex[0].x + 1;
				vertex[2].z = vertex[0].z + 1;
				vertex[2].y = heightmap[vertex[2].z * TERRAIN_SIZE + vertex[2].x] / SCALE_FACTOR;
				Height[2] = (heightmap[vertex[2].z * TERRAIN_SIZE + vertex[1].x] / SCALE_FACTOR);
				color[2] = x + 1.0f * Height[2] / MAX_HEIGHT;
				  
				//verts for 2nd tri				
				vertex[3].x = vertex[0].x;
				vertex[3].z = vertex[0].z;
				vertex[3].y = heightmap[vertex[3].z * TERRAIN_SIZE + vertex[3].x] / SCALE_FACTOR;
				Height[3] = Height[0];
				color[3] = x + 1.0f * Height[3] / MAX_HEIGHT;
				
				vertex[4].x = vertex[1].x;
				vertex[4].z = vertex[2].z;
				vertex[4].y = heightmap[vertex[4].z * TERRAIN_SIZE + vertex[4].x] / SCALE_FACTOR;
				Height[4] = Height[2];
				color[4] = x + 1.0f * Height[4] / MAX_HEIGHT;
				
				vertex[5].x = vertex[0].x;
				vertex[5].z = vertex[2].z +1;
				vertex[5].y = heightmap[vertex[5].z * TERRAIN_SIZE + vertex[5].x] / SCALE_FACTOR;
				Height[5] = (heightmap[vertex[2].z * TERRAIN_SIZE + vertex[0].x] / SCALE_FACTOR);
				color[5] = x + 1.0f * Height[5] / MAX_HEIGHT;
				
						
			if((vertex[0].x <= SNOW_CAP) || (vertex[0].y <= SNOW_CAP) || (vertex[0].z <= SNOW_CAP) || 
			   (vertex[1].x <= SNOW_CAP) || (vertex[1].y <= SNOW_CAP) || (vertex[1].z <= SNOW_CAP) ||
			   (vertex[2].x <= SNOW_CAP) || (vertex[2].y <= SNOW_CAP) || (vertex[2].z <= SNOW_CAP) ||
			   (vertex[3].x <= SNOW_CAP) || (vertex[3].y <= SNOW_CAP) || (vertex[3].z <= SNOW_CAP) || 
			   (vertex[4].x <= SNOW_CAP) || (vertex[4].y <= SNOW_CAP) || (vertex[4].z <= SNOW_CAP) ||
			   (vertex[5].x <= SNOW_CAP) || (vertex[5].y <= SNOW_CAP) || (vertex[5].z <= SNOW_CAP))
			{  
				// render two triangles(6vertices) of the terrain at once
				for(int q = 0; q < 6; ++q)
				{
					glColor3f(color[q],color[q],color[q]);
					glTexCoord2f((GLfloat)vertex[q].x/TERRAIN_SIZE*8, (GLfloat)vertex[q].z/TERRAIN_SIZE*8);
					glVertex3f(static_cast<GLfloat>(vertex[q].x - TERRAIN_SIZE/2), Height[q], 
						static_cast<GLfloat>(vertex[q].z - TERRAIN_SIZE/2));
				}
			}   
		}
		glEnd();
	} 

…am I on the right track with the algorithms for calculating the vertecies for the 2 tris?

@ZbuffeR,
I have a working render of the terrain using on GL_TRIANGLES, but the terrain now looks like it was made from LEGOs (stepped changes in elevation - like in TR 1). I reduced my vertices for the triangles from 6 to 4(260x260 map - 2 vertices removes more than 135,000 calculations). Can I expect to achieve a smooth terrain surface with the following code(once it runs correctly, or do I need to revert back to a 6 vertex terrain model to get a smooth terrain surface?


//first pass - only draw the area above the SNOW_CAP
//2nd pass identical - only draw below SNOW_CAP
	glBindTexture(GL_TEXTURE_2D, m_snowTexture);
	glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_DECAL);
	for (int z = 0; z < TERRAIN_SIZE - 1; ++z)
	{
		glBegin(GL_TRIANGLES);
		for (int x = 0; x < TERRAIN_SIZE; ++x)
		{
			//verts for 1st tri
			vertex[0].x = x; vertex[0].z = z;
			vertex[0].y = heightmap[z * TERRAIN_SIZE + x] / SCALE_FACTOR;				
			color[0] = MAX_FOG_HEIGHT + 1.0f * vertex[0].y / MAX_HEIGHT;
			
			vertex[1].x = x + 1; vertex[1].z = z + 1;
			vertex[1].y = heightmap[(z+1) * TERRAIN_SIZE + (x+1)] / SCALE_FACTOR;
			color[1] = MAX_FOG_HEIGHT + 1.0f * vertex[1].y / MAX_HEIGHT;
				
			vertex[2].x = x; vertex[2].z = z +1;
			vertex[2].y = heightmap[(z+1) * TERRAIN_SIZE + x] / SCALE_FACTOR;
			color[2] = MAX_FOG_HEIGHT + 1.0f * vertex[2].y / MAX_HEIGHT;
			  
			//vert for 2nd tri				
			vertex[3].x = x + 1; vertex[3].z = z;
			vertex[3].y = heightmap[(z) * TERRAIN_SIZE + (x+1)] / SCALE_FACTOR;
			color[3] = MAX_FOG_HEIGHT + 1.0f * vertex[3].y / MAX_HEIGHT;
				
										
			if((vertex[0].y > SNOW_CAP) || (vertex[1].y > SNOW_CAP) || (vertex[2].y > SNOW_CAP) ||
				(vertex[3].y > SNOW_CAP))
			{  
				// render two triangles(4 vertices) of the terrain at once
				glColor3f(1,1,1);
				//glColor3f(color[0],color[1],color[2]);
				// Vertex 00
				glTexCoord2f((GLfloat)vertex[0].x/TERRAIN_SIZE*8, (GLfloat)vertex[0].z/TERRAIN_SIZE*8);
				glVertex3f(static_cast<GLfloat>(vertex[0].x - TERRAIN_SIZE/2), vertex[0].y,
					static_cast<GLfloat>(vertex[0].z - TERRAIN_SIZE/2));
				// Vertex 01
				glTexCoord2f((GLfloat)vertex[3].x/TERRAIN_SIZE*8, (GLfloat)vertex[3].z/TERRAIN_SIZE*8);
				glVertex3f(static_cast<GLfloat>(vertex[3].x - TERRAIN_SIZE/2), vertex[3].y,
					static_cast<GLfloat>(vertex[3].z - TERRAIN_SIZE/2));
				// Vertex 02
				glTexCoord2f((GLfloat)vertex[1].x/TERRAIN_SIZE*8, (GLfloat)vertex[1].z/TERRAIN_SIZE*8);
				glVertex3f(static_cast<GLfloat>(vertex[1].x - TERRAIN_SIZE/2), vertex[1].y,
					static_cast<GLfloat>(vertex[1].z - TERRAIN_SIZE/2));
				
				glColor3f(1,1,1);
				//glColor3f(color[3],color[3],color[3]);
				// Vertex 00
				glTexCoord2f((GLfloat)vertex[0].x/TERRAIN_SIZE*8, (GLfloat)vertex[0].z/TERRAIN_SIZE*8);
				glVertex3f(static_cast<GLfloat>(vertex[0].x - TERRAIN_SIZE/2), vertex[0].y,
					static_cast<GLfloat>(vertex[0].z - TERRAIN_SIZE/2));
				// Vertex 03
				glTexCoord2f((GLfloat)vertex[1].x/TERRAIN_SIZE*8, (GLfloat)vertex[1].z/TERRAIN_SIZE*8);
				glVertex3f(static_cast<GLfloat>(vertex[1].x - TERRAIN_SIZE/2), vertex[1].y,
					static_cast<GLfloat>(vertex[1].z - TERRAIN_SIZE/2));
				// Vertex 01
				glTexCoord2f((GLfloat)vertex[2].x/TERRAIN_SIZE*8, (GLfloat)vertex[2].z/TERRAIN_SIZE*8);
				glVertex3f(static_cast<GLfloat>(vertex[2].x - TERRAIN_SIZE/2), vertex[2].y,
					static_cast<GLfloat>(vertex[2].z - TERRAIN_SIZE/2));
			}  		
		}
		glEnd();
	}

Such stepping generally means integer conversion somewhere where it should not be.
Nothing to do with number of vertices.
Example :


vertex[2].y = heightmap[(z+1) * TERRAIN_SIZE + x] / SCALE_FACTOR;

Does heightmap[] contain int ?
Is SCALE_FACTOR an int ?
If “yes” is the answer to both questions, then “/” does an integer division.
Try that instead to force floating point :


vertex[2].y = heightmap[(z+1) * TERRAIN_SIZE + x] * 1.0 / SCALE_FACTOR;

Then I hope vertex.xyz are floats too …

@ZbuffeR
changing the types for xyz from int to float did the trick. I was thinking because I had a smooth surface with 6 vertices, then switched to 4, that the problem could only be with how I had set up the triangle patterns to receive the textures.

Thanks.