Saturday, October 30, 2010

Project 1 - Moving the camera, part 3

Last time I cobbled together the very basics for a camera. Today I mean to make it somewhat more robust, and add mouse input.

Right now the camera is a bunch of variables, and lacking some important functionality. My plan is to create a class to hold all of the camera information. To know what the camera is looking at, we need a position and a bearing. The position is easy enough to describe. Bearing is a little more complex. Finding a good way to describe it is important since I will need to know the current bearing in order to be able to move forwards, sideways or back.

The bearing can be described in terms of the angle on two axis. We take the natural camera bearing (looking towards the negative z axis) as centered on the y and x axis. Increasing the angle with respect to the y axis turns the camera to the left, decreasing it turns it towards the right. Increasing the angle with respect to the x axis, on the other hand, makes the camera look up, while decreasing it makes the camera look down.

I will eventually need to add a third angle, twisting the camera with respect to the z axis. This would roll the camera one way or the other, but due to the affect that can have on further mouse movement I'll leave it aside for now.

I will need to ensure that the camera angles are always between 0° and 360° on the y axis and between 0° and +/-180° on the x axis. Allowing the x axis to perform a full revolution would cause the world to end up bottom-up if you look 'up' too much. This could be confusing, at least until I get the roll movement down.

All this means that there will be two distinct camera modes I will need. One, the one I'm working on now, follows FPS conventions. It properly represents someone walking on a fixed surface. However, it is very poor for a flying or space sim, or people in freefall. The second should provide free movement on all axis, and would be well suited to the rest of the game. It would be simpler overall to create the first type out of the second one, by adding the limitations I described above, but for now I want to be able to move around and the first type of camera is quicker to build.

It also occurs to me that there may be a better way around determining the position and orientation of the camera. The translate and rotate functions I spoke about before, and which I use to move the camera about ultimately create a matrix, which ModelView uses to render the scene. Instead of trying to deal with the trigonometry in the camera class, wasting CPU, I can use some of the OpenGL functions and work on a matrix with these, then feed the matrix directly to ModelView. I'll need to think about how best to do this.

Another good idea is to try and decouple the camera from the keys themselves. I am already using boolean variables for determining if the camera has to be moving. By having a pointer to them in the camera class that can be changed to look at a different key, it should be easy to reconfigure the controls if required.

Matrices in OpenGL are stored as arrays of 16 GLfloats or GLdoubles. Unfortunately, all matrix operations are applied to the current matrix, so it's all the same. I'll still need to do all the work on my own. Pity. I may still be able to use this to be quicker, however. The translation matrix is trivial to make, leaving only the rotation matrix left to finish up. First, we make room for the coordinates.

Now, the bearing. I'll use structs for these, to keep things tidy. We initialize all these to 0. When I move, I need to adjust my position on all three axis... no, this will not work. Too messy. There has to be a more elegant solution. What I have works on a fixed bearing, but as soon as I look around it will break down.

So, back to the drawing board. Thinking about it, there is no reason I can't do translations and rotations during the loop fase, and have the camera already set up for the rendering portion. If I push at the beginning of rendering, and pop at the end, I can work on the camera's position without problem. So, let's see how that works.

Well, it's kind of embarrasing after a couple of day's work, but these few lines of code:

void Camera::update()
{
    if (*moveForward)
    {
        glTranslatef(0 , 0 , 1) ;
    }
    if (*moveBackward)
    {
        glTranslatef(0 , 0 , -1) ;
    }
    if (*strafeLeft)
    {
        glTranslatef(1 , 0 , 0) ;
    }
    if (*strafeRight)
    {
        glTranslatef(-1 , 0 , 0) ;
    }
} ;

are all I ended up needing. They should work even as the bearing changes. I will however need a way to work out my position and bearing later. But for now, this is good. Let's see about adding the mouse then.

Well, the mouse works, but it's not behavinf the way I'd like it to. Probably because of the way the coordinate system works. Still, I have some ideas about how to get around that. Will continue later.

No comments:

Post a Comment