I remember I once composed a FPS viewing transformation, as a composition of 3 rotations, each with an angle as a parameter. The first angle specified the left/right rotation around the y-axis, the second angle the up/down rotation around the x-axis, and the third around the z-axis. The viewing transformation was therefore specified by 3 angles. Naturally, this transformation had a gimbal lock, depending in what order the transformation were performed. What should I look at to derive my viewing transformation without the gimbal lock? I know the "lookAt" method already, but I consider that cumbersome.


MY first guess is to do the first 2 transformations to get a viewing direction and then the axis-angle rotation on this axis.

  • \$\begingroup\$ I know the "lookAt" method already, but I consider that cumbersome. Any insight on that please? \$\endgroup\$
    – Kromster
    Sep 8 '14 at 9:35
  • \$\begingroup\$ @KromStern It is an old GLU function, AFAIK, and GLU is deprecated. Also, the interface is cumbersome, in my view. \$\endgroup\$ Sep 8 '14 at 9:40
  • \$\begingroup\$ gluLookAt is just a method of constructing a matrix opengl.org/wiki/GluLookAt_code, not much different from any other matrix construction methods (perspective, orthographic, rotation, etc) \$\endgroup\$
    – Kromster
    Sep 8 '14 at 9:51
  • \$\begingroup\$ @KromStern I just don't like its interface, as regards FPSs. The function is generic, but I want it to be FPS-specific. Maybe propose a better method to construct a FPS viewing matrix? \$\endgroup\$ Sep 8 '14 at 10:00
  • \$\begingroup\$ What exactly you don't like in specifying eyePosition3D, targetPosition3D and upVector3D ? \$\endgroup\$
    – Kromster
    Sep 8 '14 at 12:02

I honestly do not get this FPS/Arcball/Whatever camera nonsense that is going on. Just implement a general purpose camera, with either a transformation as 4x4 matrix or a position as R3 vector and orientation as a 3x3 matrix or quaternion. Then think about how that camera is moving though space.

For example I have implemented a general purpose camera with a a 4x4 matrix. The view matrix setup is straight forward:

mat4 transform;

// get column vectors x, y, z from transform
vec3 x = transform[0];
vec3 y = transform[1];
vec3 z = transform[2];

// set x, y, z as inverse into the matrix
// NOTE: column and rows are swapped
mat4 orientation(x[0], y[0], z[0], 0,
                 x[1], y[1], z[1], 0,
                 x[2], y[2], z[2], 0,
                    0,    0,    0, 1);

vec3 p = transform[3];

mat4 translation(    1,     0,     0, 0,
                     0,     1,     0, 0, 
                     0,     0,     1, 0,
                 -p[0], -p[1], -p[2], 1);

mat4 view = orientation * translation;

See no need to pass the anything though lookat or whatever. BTW the code is basically what lookat does, except it needs to compute x, y and z form eye, center and up and p is eye.

Now to the FPS part. The actual logic is a bit more complicated since you need to collide something, like a capsule with the world, but I will outline the basics with the help of "fyling".

The basic jest is you handle the rotation as follows:

// assuming (0, 0, 1) is up and (1, 0, 0) is forward
float x, y; // mouse input

// NOTE: again columns and rows are swapped in code
mat4 yaw( cos(x), sin(x), 0, 0,
         -sin(x), cos(x), 0, 0,
               0,      0, 1, 0,
               0,      0, 0, 1);

mat4 pitch( cos(y), 0, -sin(y), 0,
                 0, 1,       0, 0,
            sin(y), 0,  cos(y), 0,
                 0, 0,       0, 1);

transform = transform * pitch * yaw; 

The motion is similar:

// only forward

float speed;
float dt; // time difference since last frame

float ds = speed * dt;
mat4 translate( 1, 0,  0, 0,
                0, 1,  0, 0,
                0, 0,  1, 0,
               ds, 0,  0, 1);

transform = transform * translate; 

If you need answers how to handle transformations the Matrix and Quaternion FAQ is always very helpfull.

  • \$\begingroup\$ assumptions, assumptions, I'll post my own solution too, if I manage to arrive at it, but for now, your // assuming (0, 0, 1) is up and (1, 0, 0) is forward are exactly what I want to avoid. \$\endgroup\$ Apr 10 '14 at 10:00
  • \$\begingroup\$ What is wrong about clarifying the underlying assumptions in the code. It is not that hard to swap z with y and x with -z. The given assumptions does not mean the camera if facing this way now, just that the given transformation code thinks the input is expected that way. (It does not change the fact that the camera starts out looking down the z axis from the start.) \$\endgroup\$
    – rioki
    Apr 10 '14 at 10:04
  • \$\begingroup\$ Well, swapping is not hard, yes, but it is kind of lame. I mean, I did not say, that I was not able to make a viewing transformation, I just wanted a more generic one, sophisticated, if you like. I'll put my thinking hat on and write something up soon. \$\endgroup\$ Apr 10 '14 at 10:54
  • \$\begingroup\$ This is a general case camera, it will not get more generic. The movement is an example of how you can move it. Also, instead of writing quips about my answer, how about actually contributing a an answer that is better than mine. \$\endgroup\$
    – rioki
    Apr 10 '14 at 12:08
  • 1
    \$\begingroup\$ I think it's worth noting that you were able to take the transpose of the rotational part of the transformation matrix as the inverse, because the matrix is orthogonal (the rows and columns are orthonormal). Also, should the bottom right value in the pitch matrix be a 1 instead of a 0? And your link is broken. \$\endgroup\$
    – gsingh2011
    Jun 26 '15 at 4:27

I'm using this transform:

x' = [cos(phi), 0, sin(phi)]
y' = [-sin(phi)sin(theta),cos(theta),cos(phi)sin(theta)]
z' = [-sin(phi)cos(theta),-sin(theta),cos(phi)cos(theta)]

Where phi is the angle of rotation around the y axis, theta the angle of rotation around the x axis and alpha the angle of rotation around the z' (transformed) axis. Write these expressions into rows and you've got yourself a transformation matrix. The third parameter alpha (rotation around the z' axis), can be handled like this:

x'' = x'cos(alpha) - y'sin(alpha)
y'' = x'sin(alpha) + y'cos(alpha)
z'' = z'

Where x', y' and z' are vectors. No gimbal lock as far as I can see.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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