*** 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
±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.