Sign in to follow this  

*resolved* VBO's and Multitextured terrain

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

If you intended to correct an error in the post then please contact us.

Recommended Posts

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]

Share this post


Link to post
Share on other sites
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).

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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 zero

glDrawArrays(GL_TRIANGLE_STRIP, 0, cnt);

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites

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

Edited by ndhb

Share this post


Link to post
Share on other sites
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);
}

Share this post


Link to post
Share on other sites
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 LINE
glEnableClientState(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.

Share this post


Link to post
Share on other sites

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

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this