OpenGL tips & tricks
A few tips & tricks which might be useful if you write stuff with OpenGL. I use OpenGL for research stuff at the moment, which means I need to get stuff working quickly, and it should be robust so it does not break in case of frequent changes.
Direct state access
If you’re starting fresh with OpenGL, you should definitely take a look at the direct state access extension. OpenGL is originally modelled as a state machine, which brings in one huge problem: Whenever you want to set something, you have to modify the state first, then the target object, and then you can modify the itself. For example, binding a texture requires you to change the active texture unit and it remains changed, unless you query the current one first and set it back afterwards.
With direct state access, all of these problems go away. You can directly set shader parameters, textures, matrices and quite a bit more, without interrupting the state. This is a real time saver, as it solves many cases where some weird state change breaks something.
State management
As already noted, OpenGL maintains a state, and you have to be extremely careful to maintain the correct state for your application. For rapid development, I would recommend to use direct state access and pushing the complete state before every function block. If you are going to render something, push the state, render, pop it, and chances are high that your state afterwards is more or less the same as it was at the beginning.
Shaders
While the fixed function pipeline is nice for prototyping – you just bind a texture, pass on some vertices – using shaders even for simple texturing does have one huge advantage: Debugging. Without shaders, you’ll never know whether your surface is being rendered at all, whether the UVs are completely way off or whether the texture is simply not there. With a shader, you can first render a constant colour to see check point one, then you can render the UV coordinates to check point two, and then you can check whether the texture is properly bound.
What I found to work well is to have a simple class for each individual shader, instead of trying to have a more general mechanism. Usually, the number of shaders in a research application is not too large, so this method is well suited. Plus you can validate the parameters individually, which can catch quite a few bugs.
Random tricks & tips, and notes
Randomly sorted, a few things which would have saved me quite some time:
- For fast resizing, render a fullscreen quad into a framebuffer with the right size.
- Always check your viewport/projection matrix when changing render targets!
- Set strict mode on when loading shaders.
- If a parameter is not used in a shader, binding to it will fail – so make sure you use it somehow (multiplying by 0.00001 and adding to the result is already enough) during development.
- Check your shader version, some features require
#version 110
, while some require 130 or higher – but 130 brings in quite a few changes. gl_FragCoord
is in pixels, so you have to divide by the screen size when addressing fullscreen buffers.- Always check your texture coordinates when you get weird results, maybe you sample only one pixel.
- Beware of imprecise interpolation. If you set a value to be 1.0 on all corners of a triangle, it still might be slightly different in-between – enough to fail in a
== 1.0
test. Had this issue a lot of time, an easy workaround is to check for< 0.5 && > 1.5
if you want “integer” style selection. - When drawing 2D elements, disable the depth test. Be aware that blending always blends against the framebuffer contents, so drawing an opaque quad and a transparent after over it will not result in transparency, as the opaque one has been already blended with the framebuffer! That’s one for the d’uh files, even though it’s obvious :)
So much for today, I hope I could save some trouble :) I’m still not too happy when using OpenGL, even though the immediate mode rendering stuff is very nice during prototyping (with DX10, it takes me 60 LoC in my own framework to draw a fullscreen quad; in OpenGL, it takes me 10).