Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Strategies for managing the OpenGL state machine

I'm currently getting to grips with OpenGL. I started out with GLUT but decided to "graduate" to the SFML libraries. SFML actually provides even less GL utilities than GLUT, but is portable and provides some other functionalities. So it's really just me, GL and GLU. Yes, I'm a sucker for punishment.

I wanted to ask about strategies that people have for managing things such as matrix changes, colour changes, material changes etc.

Currently I am rendering from a single thread following a "Naked Objects" design philosophy. ie. Every graphical object has a Render() function which does the work of drawing itself. These objects may themselves be aggregates of further objects, or aggregates of graphical primitives. When a particular Render() is called it has no information about what transformations/ material changes have been called before it (a good thing, surely).

As things have developed I have settled on certain strategies such as making every function promise to push then pop the matrices if they perform any transformations. With other settings, I explicitly set anything that needs setting before calling glBegin() and take nothing for granted. Problems creep in when one render function makes some changes to less common state variables, and I am starting to consider using some RAII to enforce the reversal of all state changes made in a scope. Using OpenGL sometimes reminds me alot of assembly programming.

To keep this all manageable, and to help with debugging, I find that I am practically developing my own openGL wrapper, so I figured it would be good to hear about strategies that others have used, or thoughts and considerations on the subject. Or maybe it's just time to switch to something like a scene graph library?

Update : 13/5/11

Having now looked into rendering with vertex/normal/colour arrays and VBO's I have decided to consolidate all actual openGL communication into a separate module. The rendering process will consist of getting a load of GL independent spatial/material data out of my objects and then conveying all this information to openGL in an interpretable format. This means all raw array handling and state manipulation will be consolidated into one area. It's adds an extra indirection, and a little computation overhead to the rendering process, but it means that I can use a single VBO / array for all my data and then pass it all at once, once per frame to openGL.

like image 895
EdF Avatar asked May 12 '11 03:05

EdF


2 Answers

So it's really just me, GL and GLU

I see nothing bad in that. I'd even get rid of GLU, if possible.

With other settings, I explicitly set anything that needs setting before calling glBegin() and take nothing for granted.

Also this is a good strategy, but of course you should keep expensive state switches to a minimum. Instead of immediate mode (glBegin / glEnd) you should migrate to using vertex arrays and if available vertex buffer objects.

Problems creep in when one render function makes some changes to less common state variables, and I am starting to consider using some RAII to enforce the reversal of all state changes made in a scope.

Older versions of OpenGL provide you the attribute stack with accessing functions glPushAttrib / glPopAttrib and glPushClientAttrib / glPopClientAttrib for the client states.

But yes, the huge state space of older OpenGL versions was one of the major reasons to slimming down OpenGL-3; what's been covered by a lot of fixed function pipeline states now is configured and accessed through shaders, where each shader encapsulates what would have been dozens of OpenGL state variable values.

Using OpenGL sometimes reminds me alot of assembly programming.

This not a suprise at all, as the very first incarnation of OpenGL was designed assuming some abstract machine (the implementation) on which OpenGL calls are kind of the Operation Codes of that machine.

like image 141
datenwolf Avatar answered Sep 20 '22 04:09

datenwolf


First, try not to use glBegin/glEnd calls for new development. They are deprecated in OpenGL 3 and simply don't work in OpenGL ES (iOS, WebOS, Android). Instead, use vertex arrays and VBOs to consolidate your drawing.

Second, instead of writing your own wrapper, take a look at some recent open source ones to see how they do things. For example, check out the Visualization Library (http://www.visualizationlibrary.com/jetcms/). It's a fairly thin wrapper around OpenGL, so it's worth a look.

like image 36
Nick From Montreal Avatar answered Sep 21 '22 04:09

Nick From Montreal