Working on the IndexedFaceSet support this afternoon and evening (with a birthday party for a friend in the middle). IndexedFaceSet's are very generic ways of defining face geometry, which makes it easy to hand-edit VRML files with them. Unfortunately, that generality means they are also rather involved to prepare for rendering, you basically have to do a lot of up-front compilation to turn the VRML97 mesh into something OpenGL compatible.
OpenGLContext has had (disabled) code to use display lists for IFS display for a very long time. It was disabled because it was slower than the array-based geometry path. The code that got used was a very generic mechanism that used the ArrayGeometry class to render the IFS. ArrayGeometry is rendered with a straightforward call to glDrawArrays().
glDrawArrays says "draw X primitives from all active arrays starting at a given index in the arrays". It allows you to use a single call to render the arrays, but the arrays have to be in "expanded" form, that is, if you have three triangles that all share a vertex (extremely common) you will wind up with 3 copies of the vertex in the arrays. The major advantage of this approach is that the code to produce the expanded form for the general case of an IFS is fairly straightforward. That is, expanding any IFS to an ArrayGeometry can be done robustly and (fairly) simply.
Obviously, however, there is a downside to the ArrayGeometry approach. The expanded form uses a lot of memory and memory bandwidth, particularly for the (extremely common) case of geometry that shares vertices. What we'd like is a way to tell the GL to render an array of indices into the active arrays, rather than a range of indices. Enter the glDrawElements function. It works like glDrawArrays, save that you specify an array of indices to render, rather than a start and count.
Thing is, glDrawElements is a bit more involved to prepare from an IFS than glDrawArrays. You have to track more data in order to map the final tessellated vertices to the values in the original, and doing the mapping in the general case doesn't make sense, as in a lot of cases you'll wind up breaking down to a fully expanded set anyway.
Luckily, we already have the fallback code :) . I wrote a quick test function that determines which algorithm is appropriate for a given piece of geometry and uses glDrawElements (IndexedPolygons) only when it might provide an advantage over glDrawArrays (and is easy to generate).
I still need to alter IndexedPolygons to use VBOs and push/pop attribute operations, but once that's done common modeller-created IFS's in OpenGLContext should be a little bit faster and a lot more space-efficient. At some point we could even try creating an glInterleavedArrays implementation, as the code is now set up to handle different IFS compilers.
Anyway, the code is still very rough, but I'm rather happy with the day's work.
Pingbacks are closed.