I'm working on my first 2D OpenGL engine for iOs 5+ using GLKit (that's to say: OpenGL ES 2.0). While I am on a good path and a lot of things are implemented and nicely working, I'd like to share with you my thoughts on a conundrum I'm a bit stuck on, and hopefully have a few high level pointers on the subject: the camera.
First of all, these are the features I'd like to implement (I still don't have a specific use for the engine, so I'd prefer to stay on the "general purpose" side):
- the ability to follow a target, that will appear at (about) the center of the screen
- the ability to define an area around the center of the screen where the target can move without being chased by the camera
- the ability to zoom in and out
- the ability to change the target on the fly, animating the transition over a given amount of time
- the ability to shake the camera
After a couple of days of googling, it seems to me that there are 3 main routes:
Manipulate the orthographic projection matrix by subtracting the current target position coordinates:
GLKMatrix4MakeOrtho( screenSize.width / 2 - target.position.x, screenSize.width / 2 + target.position.x, screenSize.height / 2 - target.position.y, screenSize.height / 2 + target.position.y, -1, 1 );
and then inject this matrix in the vertex shader through the
GLKMatrix4MakeOrthoproduces a matrix like the ES1 glOrtho function does)
Multiply the modelMatrix of every quad on the screen by a view matrix generated by
GLKMatrix4MakeLookAtand then inject this matrix in the vertex shader through the
GLKMatrix4MakeLookAtproduces a matrix like the ES1 gluLookAt function does)
Finally, multiply the modelMatrix of every quad on the screen by the opposite translation matrix of the target object and again inject this matrix in the vertex shader through the
From what I can tell, these are the pros and cons of each approach:
- PROS: it's easy to implement, probably pretty fast and above all it seems to me the solution that can allow for the highest agnosticism: each node are just passed a matrix they pass along to the shader and they don't need to know anything about a target or a camera object.
- CONS: First, it's not "semantically" correct, as the projection should be set once and for all at the beginning. What we really want to modify is the "view" part for the modelviewMatrix. Secondly, it would probably mess up world coordinates and extra steps are needed to get them right back in a collision subsystem (which at the moment I don't have)
- PROS: gluLookAt IS the OpenGL function to "adjust" the camera view (or it was) but (CONS) its realm is 3D. I have done some basic experiment and it's pretty easy to mess up with the Z axis (even with z-buffer disabled). It will allow for extra features though, like camera rotation and can be implemented similarly to the solution above.
- CONS: Again, no one suggests to use it for simple 2D (exception here), and it's probably a little bit slower than 1 and 3 as the math behind the creation of the matrix is just slightly more complex (probably unnoticeable btw)
- PROS: it's the most common solution, it's fast, shouldn't mess up world coordinates (but I think it's up to the implementation)
- CONS: you have to actually move every object and this doesn't sound right to me, because at high level that's not what I'm trying to do. More over, given my current implementation, passing this matrix around is not as elegant as the other approaches (but I'm very open to refactoring)
Because of my lack of experience, I cannot lean toward one of the solution. I fear that at a later stage I could find myself stuck for a bad design decision. If anyone could give me some knowledgeable advice, it would be greatly appreciated.