Terrain Texturing

Started by
3 comments, last by Shamino 18 years, 1 month ago
Alright, I've been looking around for 2 days now looking at articles that are half done.. There really isn't any really good material on texturing a heightmap in opengl. I want some code snippets, not just a theory, I've read all of the theory, seen all of the procedural explainations, they stink. Can someone please attempt to walk me through texturing a terrain, with like, 1 texture? I'm not worried about two textures or more, I'm not worried about blending yet, just someone give me some insight as to how to do this.. Not a theoretical explaination! :) Please and thank you.
----------------------------------------------------------Rating me down will only make me stronger.----------------------------------------------------------
Advertisement
I'm going to assume your map is made of quads, stored as a grid of vertices, say, a Vector3D class: grid[MAX_COLS][MAX_ROWS]
I'm also assuming that, if we're looking from the origin to your map, we're looking into the negative Z axis, with X as width, and Y as height.
For now, let's say your texture is stored at GLuint* texture

To draw a textured map, start iterating through the vertex grid

glBindTexture(GL_TEXTURE_2D, *texture); // bind the texture before you draw anythingglBegin(GL_QUADS);for(int col = 0; col < MAX_COLS - 1; col++){for(int row = 0; row < MAX_ROWS - 1; row++){glTexCoord2f(1.0f, 1.0f); glVertex3f(grid[col + 1][row].x, grid[col + 1][row].y, grid[col + 1][row].z); // the top right cornerglTexCoord2f(0.0f, 1.0f); glVertex3f(grid[col][row].x, grid[col][row].y, grid[col][row].z); // the top left cornerglTexCoord2f(0.0f, 0.0f); glVertex3f(grid[col][row + 1].x, grid[col][row + 1].y, grid[col][row + 1].z); // bottom leftglTexCoord2f(1.0f, 0.0f); glVertex3f(grid[col + 1][row + 1].x, grid[col + 1][row + 1].y, grid[col + 1][row + 1].z); // bottom right}}glEnd();


First off, note that you only iterate to MAX_COLS -1, because you're going to be looking 1 element away from your current position, so you do cover the entire grid.

Second, the order in which you're listing the vertices may seem weird, but listing them in counter-clockwise order makes it so OpenGL properly determines which side is GL_FRONT and which is GL_BACK

That code is basically what I'm using in my GL World terrain engine (Here) simplified a bit. Also, if you're using lighting, don't forget to specify the normals.
"ok, pac man is an old gameand, there are faces which is eatin up shits" - da madface
Thanks alot for that lil snippet, here is my rendering code..

void RenderHeightMap(BYTE pHeightMap[])					// This Renders The Height Map As Quads{	int X = 0, Y = 0;									// Create Some Variables To Walk The Array With.	int x, y, z;										// Create Some Variables For Readability	if(!pHeightMap) return;								// Make Sure Our Height Data Is Valid	if(bRender)											// What We Want To Render		glBegin( GL_QUADS );							// Render Polygons	else 		glBegin( GL_LINES );							// Render Lines Instead	for ( X = 0; X < (MAP_SIZE-STEP_SIZE); X += STEP_SIZE )		for ( Y = 0; Y < (MAP_SIZE-STEP_SIZE); Y += STEP_SIZE )		{			// Get The (X, Y, Z) Value For The Bottom Left Vertex			x = X;										y = Height(pHeightMap, X, Y );				z = Y;										// Set The Color Value Of The Current Vertex			SetVertexColor(pHeightMap, x, z);			glVertex3i(x, y, z);						// Send This Vertex To OpenGL To Be Rendered (Integer Points Are Faster)			// Get The (X, Y, Z) Value For The Top Left Vertex			x = X;													y = Height(pHeightMap, X, Y + STEP_SIZE );  			z = Y + STEP_SIZE ;													// Set The Color Value Of The Current Vertex			SetVertexColor(pHeightMap, x, z);			glVertex3i(x, y, z);						// Send This Vertex To OpenGL To Be Rendered			// Get The (X, Y, Z) Value For The Top Right Vertex			x = X + STEP_SIZE; 			y = Height(pHeightMap, X + STEP_SIZE, Y + STEP_SIZE ); 			z = Y + STEP_SIZE ;			// Set The Color Value Of The Current Vertex			SetVertexColor(pHeightMap, x, z);						glVertex3i(x, y, z);						// Send This Vertex To OpenGL To Be Rendered			// Get The (X, Y, Z) Value For The Bottom Right Vertex			x = X + STEP_SIZE; 			y = Height(pHeightMap, X + STEP_SIZE, Y ); 			z = Y;			// Set The Color Value Of The Current Vertex			SetVertexColor(pHeightMap, x, z);			glVertex3i(x, y, z);						// Send This Vertex To OpenGL To Be Rendered		}	glEnd();	glColor4f(1.0f, 1.0f, 1.0f, 1.0f);					// Reset The Color


We are rendering the terrain with quads, I think we're already looping through each quad individually, so I'm guessing that this wouldn't be too difficult to implement what you just gave me in this bit of code, I'll give it a shot.
----------------------------------------------------------Rating me down will only make me stronger.----------------------------------------------------------
If you know how to stretch a texture across a quad, then it is relatively straightforward to stretch it across a mesh. Both simply assign texture coordinates in the range 0.0 to 1.0 to the vertices. Two corners opposite each other in the single quad will have (0.0,0.0) and (1.0,1.0) respectively. The same thing with the terrain mesh. All of the vertices inbetween are in between 0.0 and 1.0.

Eg, the single quad would look something like this for the U and V texture coordinates

(0.0,1.0)-----(1.0,1.0)  |               |      |               |      |               |      |               |      |               |      |               |    (0.0,0.0)-----(1.0,0.0)


For a 5x5 mesh it would look like this:
   0                  1               2               3               40 (0.00,1.00)-----(0.25,1.00)-----(0.50,1.00)-----(0.75,1.00)-----(1.00,1.00)    |                  |               |               |               |         |                  |               |               |               |         |                  |               |               |               |         |                  |               |               |               |         |                  |               |               |               |         |                  |               |               |               |     1 (0.00,0.75)-----(0.25,0.75)-----(0.50,0.75)-----(0.75,0.75)-----(1.00,0.75)    |                  |               |               |               |         |                  |               |               |               |         |                  |               |               |               |         |                  |               |               |               |         |                  |               |               |               |         |                  |               |               |               |     2 (0.00,0.50)-----(0.25,0.50)-----(0.50,0.50)-----(0.75,0.50)-----(1.00,0.50)    |                  |               |               |               |         |                  |               |               |               |         |                  |               |               |               |         |                  |               |               |               |         |                  |               |               |               |         |                  |               |               |               |     3 (0.00,0.25)-----(0.25,0.25)-----(0.50,0.25)-----(0.75,0.25)-----(1.00,0.25)    |                  |               |               |               |         |                  |               |               |               |         |                  |               |               |               |         |                  |               |               |               |         |                  |               |               |               |         |                  |               |               |               |     4 (0.00,0.00)-----(0.25,0.00)-----(0.50,0.00)-----(0.75,0.00)-----(1.00,0.00)


So your render routine simply need to calculate the appropriate texture coordinate for the vertex it is currently processes. I do it like this:

terrain.size = 5;// texture corrdinate variablesfloat a,b,c;// render heightmap mesh		for ( int row = 0; row < (terrain.size-1); row++ ) {		// X axis	// draw triangle strip	glBegin(GL_TRIANGLE_STRIP);		for ( int col = 0; col < terrain.size; col++ ) {	// Z axis		// caclulate texture coordinates for this vertex		a = (float)row/(terrain.size-1);		b = (float)col/(terrain.size-1);		c = (float)(row+1)/(terrain.size-1);		// set first vertex normal		glNormal3f(terrain.CNormal[row][col].x,terrain.CNormal[row][col].y,terrain.CNormal[row][col].z);		// set texture coordinates for first vertex		if ( terrain.textureMode ) {			glMultiTexCoord2fARB( GL_TEXTURE0_ARB, a, b );			glMultiTexCoord2fARB( GL_TEXTURE1_ARB, a*terrain.detailRepeat, b*terrain.detailRepeat);		}		// draw first vertex		glVertex3f( (terrain.CPoint[row][col].x+terrain.step)*terrain.scale,			    (terrain.CPoint[row][col].y+terrain.step)*terrain.scale,			    (terrain.CPoint[row][col].z+terrain.step)*terrain.scale);			// set second vertex normal		glNormal3f(terrain.CNormal[row+1][col].x,terrain.CNormal[row+1][col].y,terrain.CNormal[row+1][col].z);		// set second vertex texture coordinates		if ( terrain.textureMode ) {			glMultiTexCoord2fARB( GL_TEXTURE0_ARB, c, b );			glMultiTexCoord2fARB( GL_TEXTURE1_ARB, c*terrain.detailRepeat, b*terrain.detailRepeat );		}		// draw second vertex		glVertex3f( (terrain.CPoint[row+1][col].x+terrain.step)*terrain.scale,			    (terrain.CPoint[row+1][col].y+terrain.step)*terrain.scale,			    (terrain.CPoint[row+1][col].z+terrain.step)*terrain.scale);	}	glEnd();}


I use a triangle strip since they require less vertices to render. If you wanted to repeat the same texture for each quad, then you would simply use the coordinates for the single quad.

hth
F451
I thought no matter what the tex coords were always

(1.0, 1.0) - Top Right
(0.0, 1.0) - Top Left
(0.0, 0.0) - Bottom Left
(1.0, 0.0) - Bottom Right

So no matter what the vertices we're working with are, we just need to know which one is the top right, top left, bottom left, and bottom right, then we can just set the tex coords accordingly..

For the top right vertice, we just do this...

Oh wait I just saw you said if you want to repeat a texture just repeat the coords for each quad...

That's what I'm gonna do :)
----------------------------------------------------------Rating me down will only make me stronger.----------------------------------------------------------

This topic is closed to new replies.

Advertisement