Multiple textures in Vertex Arrays

I am having a problem with Textures and Vertex arrays, i have a large vertex array that stores my entire game level but i want to use more than one texture, i dont mean having two textures on each face i mean having something like texture1 on faces 1 and 3 and texture2 on face 2 etc, and i just want to know if there is a smoother way to do this than the way im doing it now, which is bind the texture then display the face eg.

	glBindTexture(GL_TEXTURE_2D,TexLib[0]);
	glDrawArrays(GL_QUADS, 0, 4);
	
	glBindTexture(GL_TEXTURE_2D,TexLib[1]);
	glDrawArrays(GL_QUADS, 4, 4);

	glBindTexture(GL_TEXTURE_2D,TexLib[0]);
	glDrawArrays(GL_QUADS, 8, 4);

etc,etc…

Is there a simpler or faster way of doing this?

[This message has been edited by Twixn (edited 03-12-2004).]

Yep, that’s pretty much it. One thing that will help (in terms of rendering speed) is batching everything up according to which texture it uses, e.g.

glBindTexture(GL_TEXTURE_2D, TexLib[0]);
glDrawArrays(GL_QUADS, 0, 4);
glDrawArrays(GL_QUADS, 8, 4);

glBindTexture(GL_TEXTURE_2D, TexLib[1]);
glDrawArrays(GL_QUADS, 4, 4);

Alternatively, you could pack the two textures to a single texture page and alter the texture coordinates of your quads to select which image you want mapped. The drawback to this is you have to be careful not to sample from other images on the texture when using any filtering other than nearest, oh yeah, and mipmapping tends to break.

Personally I would (and, in fact, do) go for the first method. Batch geometry according to the rendering state it requires.

[This message has been edited by SmutMonkey (edited 03-13-2004).]

ok, thanks, that helps a lot but it brings up another problem… what if the texlib[] had a variable controlling it like

glBindTexture(GL_TEXTURE_2D,TexLib[Firsttexture]);
glDrawArrays(GL_QUADS, 0, 4);

glBindTexture(GL_TEXTURE_2D,TexLib[Secondtexture]);
glDrawArrays(GL_QUADS, 4, 4);

glBindTexture(GL_TEXTURE_2D,TexLib[Thirdtexture]);
glDrawArrays(GL_QUADS, 8, 4);

and you dont know what they are, is it better just to keep it like the way above??

*** skip to the bottom for the quick answer, I do have a habit of rambling on ***

It all depends on how complex you’re willing to make your rendering system. At one end of the scale you wouldn’t worry about any of this and you just set the new textures and render the geometry, and hope that the driver and card don’t mind all the state setting.

At the other extreme is a full scenegraph. Basically you put all of your objects into a big tree, the nodes of which represent state changes. I’ll try to do an ascii scenegraph tree

|
±alpha blend off
| |
| ±alpha test off
| | |
| | ±texenv modulate
| | |
| | ±texture 0
| | | |
| | | ±geometry
| | | |
| | | ±more geometry
| | |
| | ±texture 1
| | |
| | ±a bit more geometry
| |
| ±alpha test on
| |
| ±texenv decal
| |
| ±texture 2
| |
| ±yep, more geometry
|
±alpha blend on
|
±alpha test on
|
±texenv modulate
|
±texture 0
|
±last bit of geometry

That’s just an example, of course. A real scenegraph would have way more levels, and way more stuff tracked. The levels of hierarchy in the scenegraph should be ordered by how expensive it is to set that state. Setting a texture would be reasonably cheap, setting a fragment program could be expensize, so you’d have fragment programs nearer the root of the tree than textures.

You can see that if you use a scenegraph, then you just need to walk the tree, setting state and rendering geometry, and you should be able to minimize the cost of state changes. Unfortunately, maintaining the tree, and just writing the code in the first place can be a major hassle.

A compromise is to encapsulate a bunch of state information in a single object (let’s call it a shader, just for kicks), and try to minimize changes between shaders. It’s simpler than a full scenegraph, but can still give reasonable benefits.

As for your specific problem, if you don’t want to get into the details of wrapping state changes into objects or making a scenegraph of your own, then a simple solution would be to collect all the geometry you want to render and sort by the GL texture id. Quick, dirty, but you can get it working quickly and it will give some benefits. The actual benefit you gain is proportional to how much geometry you render and how many state changes there would be if you didn’t sort. Of course, you should also be able to see that you incur a per-frame hit for the sort, instead of a one-time tree/shader maintenance cost.

*** the quick answer, as promised ***
If you want proper state tracking, and are willing to spend a lot of time on it, then a scenegraph can be good (although I prefer just encapsulating shader state and sorting by shader)

If you just want to render geometry in texture order then sort the geometry according to the GL texture id it uses.

Oh yeah, and don’t forget to filter state changes. Don’t bind a texture if you don’t need to, it saves calling into the API, which is always a good thing.

Ok, thanks, you have been a big help.

At the moment though i may just stick to the way i said before but testing to see if the texture needed is alreadly loaded so i dont load it twice, i’ll try to keep it simple for now, but as i gain experience i think i will convert to a scenegraph.

Thanks again.