Skip to main content
GameDev.net gamedev.net
🔒 Locked

*resolved* VBO's and Multitextured terrain

Started by DaAnde Jan 6, 2008 at 4:14 PM 6 replies 2.3k views
Original Post
DaAnde
DaAnde
Hey, I currently had a terrain drawn and multi-textured(1 large texture stretched over the entire thing and 1 detail texture) like this:

for (int z = 0; z < MAP_Z; z++)
		{
			glBegin(GL_TRIANGLE_STRIP);
			for (int x = 0; x < MAP_X; x++)
			{
				// draw vertex 0
				glMultiTexCoord2fARB(GL_TEXTURE0_ARB, tCoord[x][z][0], tCoord[x][z][1]);
				glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 0, 0);
				glNormal3f(tNorm[x][z][0].getX(),tNorm[x][z][0].getY(),tNorm[x][z][0].getZ());
				glVertex3f(terrain[x][z][0], terrain[x][z][1], terrain[x][z][2]);
				// draw vertex 1
				glMultiTexCoord2fARB(GL_TEXTURE0_ARB, tCoord[x][z][2], tCoord[x][z][1]);
				glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 0, 1);
				glVertex3f(terrain[x+1][z][0], terrain[x+1][z][1], terrain[x+1][z][2]);
				// draw vertex 2
				glMultiTexCoord2fARB(GL_TEXTURE0_ARB, tCoord[x][z][0], tCoord[x][z][3]);
				glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 1, 0);
				glNormal3f(tNorm[x][z][1].getX(),tNorm[x][z][1].getY(),tNorm[x][z][1].getZ());
				glVertex3f(terrain[x][z+1][0], terrain[x][z+1][1], terrain[x][z+1][2]);	
				//draw vertex 3
				glMultiTexCoord2fARB(GL_TEXTURE0_ARB, tCoord[x][z][2], tCoord[x][z][3]);
				glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 1, 1);
				glVertex3f(terrain[x+1][z+1][0], terrain[x+1][z+1][1], terrain[x+1][z+1][2]);
			}
			glEnd();


Now to improve performance I am now using VBO's which and draw them like this but how would I go about applying the multitexture to them properly?

//in init
for (int z = 0; z < MAP_Z+1; z++){
			for (int x = 0; x < MAP_X+1; x++){
				tex[cnt].u = tCoord[x][z][0];
				tex[cnt].v = tCoord[x][z][1];
				vert[cnt].x = terrain[x][z][0];
				vert[cnt].y = terrain[x][z][1];
				vert[cnt++].z = terrain[x][z][2];

				tex[cnt].u = tCoord[x][z][0];
				tex[cnt].v = tCoord[x][z][1];
				vert[cnt].x = terrain[x][z+1][0];
				vert[cnt].y = terrain[x][z+1][1];
				vert[cnt++].z = terrain[x][z+1][2];
	
				tex[cnt].u = tCoord[x][z][2];
				tex[cnt].v = tCoord[x][z][3];
				vert[cnt].x = terrain[x+1][z][0];
				vert[cnt].y = terrain[x+1][z][1];
				vert[cnt++].z = terrain[x+1][z][2];

				tex[cnt].u = tCoord[x][z][2];
				tex[cnt].v = tCoord[x][z][3];
				vert[cnt].x = terrain[x+1][z+1][0];
				vert[cnt].y = terrain[x+1][z+1][1];
				vert[cnt++].z = terrain[x+1][z+1][2];
			
			}
glGenBuffersARB(1, &buffer);
		glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffer);
		glBufferDataARB(GL_ARRAY_BUFFER_ARB, cnt*3*sizeof(float), vert, GL_STATIC_DRAW_ARB);
		glGenBuffersARB(1, &tBuffer);
		glBindBufferARB(GL_ARRAY_BUFFER_ARB, tBuffer);
		glBufferDataARB(GL_ARRAY_BUFFER_ARB, cnt*2*sizeof(float), tex, GL_STATIC_DRAW_ARB);
		delete [] vert; vert = NULL;
		delete [] tex; tex = NULL;
//in draw
glEnableClientState(GL_VERTEX_ARRAY);
		glEnableClientState(GL_TEXTURE_COORD_ARRAY);
		glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffer);
		glVertexPointer(3, GL_FLOAT, 0, (char *) NULL);
		glBindBufferARB(GL_ARRAY_BUFFER_ARB, tBuffer);
		glTexCoordPointer( 2, GL_FLOAT, 0, (char *) NULL );
		glDrawArrays(GL_TRIANGLE_STRIP, 0, cnt);
		glDisableClientState(GL_TEXTURE_COORD_ARRAY);
		glDisableClientState(GL_VERTEX_ARRAY);



[Edited by - DaAnde on January 8, 2008 2:09:28 AM]
Krohm
Krohm
If VBOs are difficult to understand, I suggest to go for standard client-side arrays before using VBOs.

In immediate mode you say: attribute (ex: texCoord1) has value TC1 thuru a single call.

For arrays instead you have a blob of data with a vertex stride in bytes (effectively saying there's a value V).
Thuru *Pointer calls you instruct GL on decoding/unpacking the blob (effectively saying there's an attribute texCoord, which value is in the blob).
Previously "Krohm"
Arex
Arex
Alright, you have 1 large texture stretched over the terrain. What's the problem with VBO's & texturing?

You are generating the same geometry data, but just using VBO to render the geometry, that should not change the way you apply your texture.
V-man
V-man
It's simple

glEnableClientState(GL_VERTEX_ARRAY);glEnableClientState(GL_TEXTURE_COORD_ARRAY);glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffer);glVertexPointer(3, GL_FLOAT, 0, (char *) NULL);glBindBufferARB(GL_ARRAY_BUFFER_ARB, tBuffer);glTexCoordPointer( 2, GL_FLOAT, 0, (char *) NULL );glClientActiveTexture(GL_TEXTURE1);glBindBufferARB(GL_ARRAY_BUFFER_ARB, tBuffer2);glTexCoordPointer( 2, GL_FLOAT, 0, (char *) NULL );glClientActiveTexture(GL_TEXTURE0);//Return back to zeroglDrawArrays(GL_TRIANGLE_STRIP, 0, cnt);
DaAnde
DaAnde
The problem currently is that the texture is being stretched properly and the terrain is being rendered correctly except that the detail texture is not combining with the large texture.
ndhb
ndhb

Well, uhm. You are using fixing functionality and have multitexturing work correctly in immediate mode? As already mentioned there's no reason why it wouldn't work when supplying the geometry (vertices and texcoords) with VBO's.

Are you absolutely sure you init and bind BOTH arrays of texture coordinates (as V-man points out in his code)? From the code in your first post, it looks like you only supply ONE set of texture coordinates and forget to bind the other set when rendering.

kind regards,
Nicolai

DaAnde
DaAnde
This is my current code

Init:
for (int z = 0; z < MAP_Z+1; z++){			for (int x = 0; x < MAP_X+1; x++){				tex[cnt].u = tCoord[x][z][0];				tex[cnt].v = tCoord[x][z][1];				tex2[cnt].u = 0.0;				tex2[cnt].v = 0.0;				vert[cnt].x = terrain[x][z][0];				vert[cnt].y = terrain[x][z][1];				vert[cnt++].z = terrain[x][z][2];				tex[cnt].u = tCoord[x][z][0];				tex[cnt].v = tCoord[x][z][3];				tex2[cnt].u = 1.0;				tex2[cnt].v = 0.0;				vert[cnt].x = terrain[x][z+1][0];				vert[cnt].y = terrain[x][z+1][1];				vert[cnt++].z = terrain[x][z+1][2];					tex[cnt].u = tCoord[x][z][2];				tex[cnt].v = tCoord[x][z][1];				tex2[cnt].u = 0.0;				tex2[cnt].v = 1.0;				vert[cnt].x = terrain[x+1][z][0];				vert[cnt].y = terrain[x+1][z][1];				vert[cnt++].z = terrain[x+1][z][2];				tex[cnt].u = tCoord[x][z][2];				tex[cnt].v = tCoord[x][z][3];				tex2[cnt].u = 1.0;				tex2[cnt].v = 1.0;				vert[cnt].x = terrain[x+1][z+1][0];				vert[cnt].y = terrain[x+1][z+1][1];				vert[cnt++].z = terrain[x+1][z+1][2];						}		}		cnt--;		glGenBuffersARB(1, &buffer);		glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffer);		glBufferDataARB(GL_ARRAY_BUFFER_ARB, cnt*3*sizeof(float), vert, GL_STATIC_DRAW_ARB);		glGenBuffersARB(1, &tBuffer[0]);		glBindBufferARB(GL_ARRAY_BUFFER_ARB, tBuffer[0]);		glBufferDataARB(GL_ARRAY_BUFFER_ARB, cnt*2*sizeof(float), tex, GL_STATIC_DRAW_ARB);		glGenBuffersARB(1, &tBuffer[1]);		glBindBufferARB(GL_ARRAY_BUFFER_ARB, tBuffer[1]);		glBufferDataARB(GL_ARRAY_BUFFER_ARB, cnt*2*sizeof(float), tex2, GL_STATIC_DRAW_ARB);


Draw:

glPushMatrix();	//set active texture unit to 0	glActiveTextureARB(GL_TEXTURE0_ARB);	glEnable(GL_TEXTURE_2D);	glBindTexture(GL_TEXTURE_2D, TextureArray[0]);	glMatrixMode(GL_TEXTURE);	glLoadIdentity(); //clear our texture matrix	glMatrixMode(GL_MODELVIEW); //switch back to our model matrix	// set active texture unit to 1	glActiveTextureARB(GL_TEXTURE1_ARB);	glEnable(GL_TEXTURE_2D);	glBindTexture(GL_TEXTURE_2D, TextureArray[1]);	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB); //set the texture mode to combine the two	glTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 2); //scale the color of this texture by 2	glMatrixMode(GL_TEXTURE); //switch to our texture matrix again	glLoadIdentity(); //clear the matrix	glMatrixMode(GL_MODELVIEW); //switch back to our model matrix	GLfloat whiteDiffuseMaterial[] = {1.0, 1.0, 1.0};	GLfloat greyAmbientMaterial[] = {0.5, 0.5, 0.5}; 	GLfloat whiteSpecularMaterial[] = {1.0, 1.0, 1.0};	glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, whiteDiffuseMaterial);	glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, greyAmbientMaterial);	glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, whiteSpecularMaterial);	if(VArr){		glEnableClientState(GL_VERTEX_ARRAY);		glEnableClientState(GL_TEXTURE_COORD_ARRAY);		glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffer);		glVertexPointer(3, GL_FLOAT, 0, (char *) NULL);		glBindBufferARB(GL_ARRAY_BUFFER_ARB, tBuffer[0]);		glTexCoordPointer( 2, GL_FLOAT, 0, (char *) NULL );		glClientActiveTextureARB(GL_TEXTURE1_ARB);		glBindBufferARB(GL_ARRAY_BUFFER_ARB, tBuffer[1]);		glTexCoordPointer( 2, GL_FLOAT, 0, (char *) NULL );		glDrawArrays(GL_TRIANGLE_STRIP, 0, cnt);				glDisableClientState(GL_TEXTURE_COORD_ARRAY);		glDisableClientState(GL_VERTEX_ARRAY);		glClientActiveTextureARB(GL_TEXTURE0_ARB);	}
DaAnde
DaAnde
I have finally got it working.

I added 1 line to my draw method to get it working:

glEnableClientState(GL_VERTEX_ARRAY);glEnableClientState(GL_TEXTURE_COORD_ARRAY);glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffer);glVertexPointer(3, GL_FLOAT, 0, (char *) NULL);glClientActiveTextureARB(GL_TEXTURE0_ARB);glBindBufferARB(GL_ARRAY_BUFFER_ARB, tBuffer[0]);glTexCoordPointer( 2, GL_FLOAT, 0, (char *) NULL );glClientActiveTextureARB(GL_TEXTURE1_ARB);//NEW LINEglEnableClientState(GL_TEXTURE_COORD_ARRAY);glBindBufferARB(GL_ARRAY_BUFFER_ARB, tBuffer[1]);glTexCoordPointer( 2, GL_FLOAT, 0, (char *) NULL );glDrawArrays(GL_TRIANGLE_STRIP, 0, cnt);glClientActiveTextureARB(GL_TEXTURE0_ARB);glDisableClientState(GL_TEXTURE_COORD_ARRAY);glDisableClientState(GL_TEXTURE_COORD_ARRAY);glDisableClientState(GL_VERTEX_ARRAY);


Here is a screenshot:

Image Hosted by ImageShack.us

The terrain is 262,143 triangles plus there is alot more going on in the scene than the screenshot shows, but before my FPS was about 12-18FPS and now its at a steady 60 FPS which is what anything running on my computer is locked at due to my LCD's. All in all I would have to say its not much work to get these going and once they are its well worth it...saying that I still have my old way of rendering it incase the computer its being ran on does not support VBO's.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.