Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I have been struggling to create a first person camera in OpenGL ES 2.0 without using gluLookAt(). I grab the camera's orientation vectors (the way it's looking) from the current modelview matrix, and use that to calculate the new forward/backward (Z) translation value. I then calculate the strafe (X) value from the dot product of Z and Y (which is always 1.0). So, I have all the information I need to create a view matrix, but how do I do that without using gluLookAt? Almost all the examples I've seen use gluLookAt, but no such function exists in OpenGL ES 2.0. Besides, one of the moderators on cprogramming.com mentioned that gluLookAt is not appropriate for FPS cameras:

http://cboard.cprogramming.com/game-programming/135390-how-properly-move-strafe-yaw-pitch-camera-opengl-glut-using-glulookat.html

I am really confused by all the conflicting information I'm getting. I just want to create a first person camera that goes forward (W,S keys), side-to-side (A,D keys) and rotates around its center (Y axis only), Wolfenstein style.

Here's more-or-less my existing code:

vec4 cur_look,dir_move,dir_strafe,cam_pos;
mat4 mat_modelview,mat_rot,mat_temp;
float lr; //left/right keypress increment value
float ud; //up/down keypress increment value

//grab current camera orientation (look at) from the modelview matrix
cur_look[0] = mat_modelview[8];
cur_look[1] = mat_modelview[9];
cur_look[2] = mat_modelview[10];
cur_look[3] = mat_modelview[11];

//rotate the direction vector using the rotation matrix
mat4_identity(mat_rot);
mat4_identity(mat_temp);
mat4_rotate_Y(mat_rot,mat_temp,lr); //create rotation matrix

//multiply the current direction vector by the rotation
//matrix and place the result in dir_move
mat4_mul_vec4(dir_move, mat_rot, cur_look);

//normalize the fwd/back direction vector
vec4_norm(dir_move,dir_move);

//calculate strafe vector using cross product of Z and Y
vec4_cross(dir_strafe,dir_move,(vec4){0.0,1.0,0.0,0.0});

//normalize strafe vector
vec4_norm(dir_strafe,dir_strafe);


//detect key input

//FWD/BACK
if(key_pressed == 'w'){
    cam_pos[2] += (dir_move[2] * -INPUT_SENS_Z); //z
}
if(key_pressed == 's'){
    cam_pos[2] += (dir_move[2] * INPUT_SENS_Z); //z
}

//ROTATION
if(key_pressed == LEFT_ARROW){
    lr += INPUT_SENS_ROT;
}       
if(key_pressed == RIGHT_ARROW){
    lr +=  -INPUT_SENS_ROT;
}


//build new modelview matrix
mat4_identity(mat_modelview);

//multiply modelview matrix by rotation matrix
mat4_mul(mat_modelview,mat_modelview,mat_rot);

//create translation matrix
mat4_translate(mat_tran,-cam_pos[0], 0.0, -cam_pos[2]);
//multiple modelview matrix by translation matrix
mat4_mul(mat_modelview,mat_modelview,mat_tran);


//update uniforms and draw scene using glDrawArrays()
glUniformMatrix4fv(loc_modelview, 1, GL_FALSE, mat_modelview);

Any help on this would be much appreciated!

share|improve this question

2 Answers 2

It seems like you are trying to do things backwards. Here is my preferred way of creating an FPS camera:

Store the position and orientation in client code (Euler Angles)

Define the position and orientations along the x, y, and z axis in the client code. This would would something like this in C++:

float camera_x = 0.0f;
float camera_y = 0.0f;
float camera_z = 0.0f;
float pitch = 0.0f; // The rotation along the x axis
float yaw = 0.0f; // The rotation along the y axis
float roll = 0.0f; // The rotation along the z axis

Then apply these variables before you render your objects in 3D space by writing:

glLoadIdentity();
glRotatef(pitch, 1.0f, 0.0f, 0.0f);
glRotatef(yaw, 0.0f, 1.0f, 0.0f);
glRotatef(roll, 0.0f, 0.0f, 1.0f);
glTranslatef(-x, -y, -z);

In the input handling code I make sure that the angles are never higher than 360 degrees or lower than 0 degrees to prevent precision loss, but this is up to you.

This method is unfortunately prone to the gimbal lock issue. I myself have never experienced this problem with FPS cameras, but you should be wary of it nonetheless. If you wish to avoid this problem, try quaternions. Be warned - they are notoriously difficult to understand.

share|improve this answer
    
This works except that the translation always goes in the same direction and is not affected by rotation. In other words, when I rotate the view 90 degrees to the left, the "forward" key actually goes "right." If I return the view to 0 degrees, "forward" goes "forward" as expected. –  Synthetix Jul 10 '12 at 9:32
    
This requires a basic knowledge of trigonometry. Check out khanacademy for some tutorials on that. –  Oskar Jul 10 '12 at 9:38
    
Should I be multiplying the translation vector (the -x,-y,-z in your example) by the same rotation matrix I used to derive the yaw value (I only ever rotate around the Y axis)? –  Synthetix Jul 10 '12 at 9:43
    
I haven't tried that myself, so I honestly don't know. I divided the yaw angles into four quadrants, each having separate input handling code. Then, using trigonometry, I calculated the new xy position for the camera. Repeat the same steps for the x axis if you want to move in the direction you're looking vertically too. –  Oskar Jul 10 '12 at 9:47
    
I added a code example, if that helps. –  Synthetix Jul 10 '12 at 9:59

I figured out the problem. It had to do with this line:

if(key_pressed == 'w'){
    cam_pos[2] += (dir_move[2] * -INPUT_SENS_Z); //z
}

I was only adding to an individual element in the vector array. I should have been adding to the entire array as a unit:

if(key_pressed == 'w'){
    vec4_add(cam_pos,cam_pos,dir_move); //add dir_move to cam_pos
}

I still need to include the INPUT_SENS_Z value in the example to throttle the speed, but you get the idea. Thank goodness that's solved!

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.