Presumably, sooner or later, you’re going switch to VBO’s or something like that.
You should almost never do ‘b’, as that makes your rendering CPU dependent. The ultimate hope is that you get full async rendering.
The best way to get full speed is to do as few glDraw* calls as possible. That may mean you have to rearchitect your meshes and textures. Make it so that each building can be drawn with a single glDraw* call (concatonate textures and re-texture your meshes).
Here’s a cute trick that works on vertex program-equipped cards.
Put all your building geometry in one large vertex array. For each instance of a building, you have a separate attribute array that contains just the same number repeated over and over (this array is the same size as the other arrays). This attribute array is an index into the per-vertex constant data in the program.
That array contains the center position, in 3D space, of where the building is. All your vertex shader needs to do is offset every vertex position with this value (the w coordinate might even be a uniform scale or some kind of angular rotation, if you need it). This way, you can draw upwards of 80 buildings using a single glDrawElement’s call. All you need to do is make sure the attribute vertex array is correct for each instance. Now, you will have to rebuild your index list per frame, so that your index list contains multiple buildings.
Now, this doesn’t take into account material changes. You need to limit the number of materials you use to something reasonable like 5-15 or so. That way, a scene with 600 buildings only requires, at worst, 15 different material changes. Each material has 40 different buildings (or so).
You can maintain variety by having that array above that you use to index into the constant registers also apply vertex colors. These can be independent of the building’s location (but they should be constant, of course).
Now, if you only have 5 materials, you get 120 different buildings. A 9500 or better can handle that in a vertex program, but a GeForce 3 cannot (it only has 96 registers). To improve upon this, you can make limit the building positions to being 2D, and have each 4-float register represent 2 coordinates. It’ll be a bit tougher in the shader to pull this one off, (especially figuring out which half to offset with), but it can be done.
The key to performance in this case is to limit both the number of material changes and the number of glDrawElements calls. And this method will improve much more if you use VBO (when it gets optimized).
You may have problems integrating this into an LOD scheme, however. But, it may go faster using the full LOD than whatever you come up with without this scheme, so that’s something.
BTW, the above doesn’t quite work as advertised. To get it to work, you’d need to bind one attribute array per instance, so that each instance’s index array get’s loaded up to the shader. Then, it would have to pick which one to use based on some value. Otherwise, you have to still do one glDraw* per building, with gl*Pointer calls inbetween.
Actaully, this would work if OpenGL could allow different attributes to be indexed with different index arrays. This is one of the cases where it would really be useful.
[This message has been edited by Korval (edited 03-26-2003).]
[This message has been edited by Korval (edited 03-26-2003).]
[This message has been edited by Korval (edited 03-26-2003).]