I’ve recently been converting a model viewer of mine to use vertex arrays instead of display lists. I’ve nearly finished the conversion, and I’m even using glLockArraysEXT and glUnlockArraysEXT. However, a few questions have come up…
First of all, how do I do flat shading with vertex arrays? It seems to me that vertex arrays were designed with per-vertex normals rather than having a normal for every face.
Secondly, from what I understand, vertex arrays can’t be used in display lists, yet if I’m not mistaken, several web pages make vague referrences to exactly that. Can I use the two together, and if so, is it implementation dependant?
Lastly, I don’t seem to be getting any significant performance increase by using vertex arrays over display lists. Is there an advantage to using vertex arrays, and if so, when does it provide the most benefit?
You can do flat shading with vertex arrays, just call glShadeModel(GL_FLAT). Of course its not maximum efficient because you still have to send one normal per vertex but at least the lighting computation is done once per face. As for performance issues, vertex arrays are not the fastest way of drawing primitives (usually display lists are. You should check a document at nVidia’s site about GeForce optimisations. There’s as section comparing the different means of sending geometry) but they are faster than just glBegin() glEnd() an much faster if you reuse a lot of vertices in the index array. Its also possible to use vertex arrays and DLs. The advantage of vertex arrays over DLs is the memory overhead (the vertex data is not duplicated on the server side) and the dynamic nature of the data. DLs are static and if you want to change the vertex data you have to recompile your list (time consuming) whereas vertex arrays need you to send the vertex data at each frame. Data can change from frame to frame at no cost.
I know about glShadeModel(GL_FLAT). That’s not the problem. The problem is that Vertex Arrays seem to be structure in such a way that they assume shading is per-vertex rather than per-face. As a result there are only two solutions I can think of to get proper shading:
Assign the flat shaded normal to the first vertex of every triangle.
It’s been my observation that when OpenGL shading is set to GL_FLAT, it appears to only use one of the vertex normals for information, probably the first one. Assuming this is true, the above solution should work in theory, but the problem is, if even one pair of triangles share their first vertex, this method doesn’t work properly.
Break up the verticies so that they’re unique for each polygon.
This ends up being either a performance hit, a waste of memory or both. I could hide the vertex splitting time in the model loading and use the seperated vertices for smooth shading as well, which eliminates the need to store two copies of the model data, but it’s still going to use more memory than I care for, and it’d be a really pain in the &^^@#$@#$ to debug. It’s probably be easier to just use Display Lists for flat shading, although that would eat up some memory as well.
As for using vertex arrays in display lists, I don’t just want to know if it’s possible. I want to know if it’s OpenGL kosher. Does it work on all platforms and on all cards? Will it cause problems on some configurations?
It is OK to use vertex arrays in display lists. However, the vertex arrays get dereferenced at compile time. The display list will remember the actual vertex data, not the indices.
If you want to have facet normals, you will have to specify each vertex multiple times. This may require sending more data – 1 normal per vertex instead of 1 per 3 – but there are efficiency gains from using a vertex array as well.
Try immediate mode, try vertex arrays, try a display list, see which gives the best results.
Just this morning I was looking through my copy of the OpenGL Programming Guide, and I realized that I’d misread it. It says that the gl*****Pointer, glEnableClientState and glDisableClientState calls, et cetera, couldn’t be in a display list, but I had read this to mean that ALL vertex array-related functions were a no-no. Turns out that glArrayElement, glDrawElements, glDrawRangeElements and glDrawArrays are not on the dreaded do-not-use-in-a-display-list list. Sorry about that.
What I’ll probably do is use display lists with vertex arrays for smooth shading, then use just straight display lists for flat shading. That way, I don’t have to play around with the vertices, and since I’ll be using the same display list for either shading method, there won’t be seperate data stored for each one. Theorietically, I could speed things up in the instantaneous stitch between shading methods by keeping two display lists per model, but since my model viewer is an MDI application intended for viewing large groups of ASCII model files, I don’t think that’s wise.
Why try immediate mode? Is that actually faster on some systems?
Immediate mode will allow you to send 1 normal every 3 vertices. Depending on the specifics of how a given implementation works, it may or may not be faster than vertex arrays.
The best thing to do is to try all three and see what seems to work best.