What are some best practices for OpenGL coding (esp. w.r.t. object orientation)?

This semester, I took a course in computer graphics at my University. At the moment, we're starting to get into some of the more advanced stuff like heightmaps, averaging normals, tesselation etc.

I come from an object-oriented background, so I'm trying to put everything we do into reusable classes. I've had good success creating a camera class, since it depends mostly on the one call to gluLookAt(), which is pretty much independent of the rest of the OpenGL state machine.

However, I'm having some trouble with other aspects. Using objects to represent primitives hasn't really been a success for me. This is because the actual render calls depend on so many external things, like the currently bound texture etc. If you suddenly want to change from a surface normal to a vertex normal for a particular class it causes a severe headache.

I'm starting to wonder whether OO principles are applicable in OpenGL coding. At the very least, I think that I should make my classes less granular.

What is the stack overflow community's views on this? What are your best practices for OpenGL coding?


The most practical approach seems to be to ignore most of OpenGL functionality that is not directly applicable (or is slow, or not hardware accelerated, or is a no longer a good match for the hardware).

OOP or not, to render some scene those are various types and entities that you usually have:

Geometry (meshes). Most often this is an array of vertices and array of indices (i.e. three indices per triangle, aka "triangle list"). A vertex can be in some arbitrary format (e.g. only a float3 position; a float3 position + float3 normal; a float3 position + float3 normal + float2 texcoord; and so on and so on). So to define a piece of geometry you need:

  • define it's vertex format (could be a bitmask, an enum from a list of formats; ...),
  • have array of vertices, with their components interleaved ("interleaved arrays")
  • have array of triangles.

If you're in OOP land, you could call this class a Mesh.

Materials - things that define how some piece of geometry is rendered. In a simplest case, this could be a color of the object, for example. Or whether lighting should be applied. Or whether the object should be alpha-blended. Or a texture (or a list of textures) to use. Or a vertex/fragment shader to use. And so on, the possibilities are endless. Start by putting things that you need into materials. In OOP land that class could be called (surprise!) a Material.

Scene - you have pieces of geometry, a collection of materials, time to define what is in the scene. In a simple case, each object in the scene could be defined by: - What geometry it uses (pointer to Mesh), - How it should be rendered (pointer to Material), - Where it is located. This could be a 4x4 transformation matrix, or a 4x3 transformation matrix, or a vector (position), quaternion (orientation) and another vector (scale). Let's call this a Node in OOP land.

Camera. Well, a camera is nothing more than "where it is placed" (again, a 4x4 or 4x3 matrix, or a position and orientation), plus some projection parameters (field of view, aspect ratio, ...).

So basically that's it! You have a scene which is a bunch of Nodes which reference Meshes and Materials, and you have a Camera that defines where a viewer is.

Now, where to put actual OpenGL calls is a design question only. I'd say, don't put OpenGL calls into Node or Mesh or Material classes. Instead, make something like OpenGLRenderer that can traverse the scene and issue all calls. Or, even better, make something that traverses the scene independent of OpenGL, and put lower level calls into OpenGL dependent class.

So yes, all of the above is pretty much platform independent. Going this way, you'll find that glRotate, glTranslate, gluLookAt and friends are quite useless. You have all the matrices already, just pass them to OpenGL. This is how most of real actual code in real games/applications work anyway.

Of course the above can be complicated by more complex requirements. Particularly, Materials can be quite complex. Meshes usually need to support lots of different vertex formats (e.g. packed normals for efficiency). Scene Nodes might need to be organized in a hierarchy (this one can be easy - just add parent/children pointers to the node). Skinned meshes and animations in general add complexity. And so on.

But the main idea is simple: there is Geometry, there are Materials, there are objects in the scene. Then some small piece of code is able to render them.

In OpenGL case, setting up meshes would most likely create/activate/modify VBO objects. Before any node is rendered, matrices would need to be set. And setting up Material would touch most of remaining OpenGL state (blending, texturing, lighting, combiners, shaders, ...).


Object transformations

Avoid depending on OpenGL to do your transformations. Often, tutorials teach you how to play with the transformation matrix stack. I would not recommend using this approach since you may need some matrix later that will only be accessible through this stack, and using it is very long since the GPU bus is designed to be fast from CPU to GPU but not the other way.

Master object

A 3D scene is often thought as a tree of objects in order to know object dependencies. There is a debate about what should be at the root of this tree, a list of object or a master object.

I advice using a master object. While it does not have a graphical representation, it will be simpler because you will be able to use recursion more effectively.

Decouple scene manager and renderer

I disagree with @ejac that you should have a method on each object doing OpenGL calls. Having a separate Renderer class browsing your scene and doing all the OpenGL calls will help you decouple your scene logic and OpenGL code.

This is adds some design difficulty but will give you more flexibility if you ever have to change from OpenGL to DirectX or anything else API related.