OpenGL and OOP
I am currently refreshing my OpenGL knowledge and mixing it up with mordern C++. I have done what probably most of you guys would do and have created a bunch of class objects for shaders, programs, meshes, textures and so on. Each object hooks into the OpenGL API and calls appropriate functions to set state.
However, after reading a bit, I am not sure if this is the right approach. For example, in the FAQ! one problem is discussed. And after all, OpenGL is a big global state machine.
One alternative which I have found a couple of times is to implement a global management class for the GL context. Immediate advantages would be the ability to write a state stack and prevent unnecessary state switches easily. Disadvantages would be that this would be hard to get right in a multithreaded environment.
I know this probably falls under the chapter of premature optimizations but I am interested in how you guys manage your OpenGL contexts.
Posted Jan 5, 2015, 1:41 PM UTC
Personally, I have a
Meshclass that contains vertices and indices, and is the only class that does the draw calls.Rendererclasses are, well, renderers that set the context in certain way. EachRendererhasbegin(),render()andend()functions. In the first one, the renderer initializes the states as required (e.g.DeferredRendererbinds the G-buffer). In the second one, all the required meshes are drawn. In the last one, everything "leaky" is unbound (shaders and framebuffers, mainly). Each renderer is responsible for setting the GL states in thebegin()function (i.e. enabling or disabling depth test and depth writes).In the
render()phase, each renderer can reference any number ofRenderContentProviderclasses. This is just an interface that each "content provider" can implement. These content providers do the actual drawing to the surrounding renderer context. Examples are 3D model rendering system, 2D sprite rendering system, text rendering system and so on.So, in practice, the render loop goes like this:
After this "main" part, I call the quad renderer to output a quad in certain way (either output an intermediate texture like the depth buffer, or compose the final image), along with any full-screen post-processing effects (vignette, color effects, pixelization...).
And here's how my classes look like:
And so on. The main thing I've tried to keep in mind when designing the engine is to keep data separate from the functionality and making every GL-related portion responsible for their own state changes. I can't really help you with multi-threadedness, since my engine is single-threaded (although the program logic can be run in separate threads if needed).
Well, that's nice info. Especially the begin()/end() functions are a nice idea. Otherwise I guess I am not making much different to your approach. Thank you for the answer.
this is essentially what I settled on as well.
Could you explain a little more about your Renderers? I mean: why do you have multiple renderers? Do you have an OpenGL + D3D renderer?
Also, out of curiosity, how do you handle skinned/animated meshes?
The multiple renderers I currently have are a deferred renderer (the main bulk of the scene), a forward renderer (special cases layered on top of the deferred scene), and a GUI system. At the moment there's only OpenGL support in the engine, but if I would add D3D support, I'd probably do an abstraction layer to the base
Rendererclass that would hide the OpenGL and D3D specific code.The current iteration of the engine doesn't have support for animated meshes. However, I'd probably implement it as a component that's attached to the entities, and have separate render queues in the renderers for the animated meshes.