Pages

Tuesday 18 February 2014

OpenGL 2D Camera Tutorial

One might assume it's a trivial task to create a 2D camera with OpenGL, but it's not quite. For the more experienced programmer this may be obvious, but (as an amateur) I had a lot of trouble with this. I'm writing this in hopes that someone in the same position may stumble across this and have a little less to worry about after reading. It's written in Java, however, it's not very complex, and can be easily to translate to other languages. Hopefully this can help everyone!

So, the troubles with a 2D camera include zooming in/out to/from the center of the screen, having translation not effected by zoom/scale, and having zooming it's self not effected by zoom/scale. I'll start off with a class that addresses none of these issues, and is only useful for basic functionality.

As you can see, this class merely translates and scales by the position and scale. Any scaling performed will merely scale everything form the origin, regardless of the position of the camera. Changes in position are pushed right through to the final "glTranslatef" in the "use" method, likewise, changes in scale have absolutely no relation to the current scale. With the current camera zooming out far will cause translations to become slow, and zooming in close will cause them to become fast. Zooming in will also taper off and get slower the more you zoom in, then the further you zoom out the faster it goes. This is not the kind of behaviour we want. So we'll start with making the origin of zoom the center of the screen.

Now the camera will zoom in/out from the center of the screen instead of the origin. To explain a little, we first translate everything to the camera coordinates (GL commands pushed into stack first will be the last executed, so all GL commands should be ordered in reverse), then scale, then once again translate to the center of the display. This gives the effect that the scaling has happened in the center of the display, when in reality, the point where the center of the display would be is being kept in place after scaling. Next we'll make translations ambiguous.

What we did here was divide any changes in position by the current scale. If △x is 12 and scale is 3, the actual change in GL coordinates will be 4. This gives the illusion that the translations are happening based on the screen coordinates. Finally, we'll get rid of the tapering effect scaling normally causes.

Here we simply multiplied the change in scale by the current scale. If △scale is 32 and scale is 0.5, the change in scale will be 16, appearing to be independent of the current zoom.

After all this messing with the translation and scaling we get the class below: a 2D OpenGL camera that translates, and scales independently of the current zoom, and always does it to the center of the display. Now that we're done with this, it may seem pretty simple (and it is now!), but I find the order of GL calls and how do compensate for effects of scaling to be difficult to understand. I hope I helped you and anyone else who read this, not just to make a better 2D camera, but to better understand the way OpenGL works.

Here you go, the final product, and have a great day with it!