1
\$\begingroup\$

After 2 weeks of reading many math formulas and such I know what is a Quaternion, an Axis Angles and Matrices. I have made my own math libary (Java) to use on my game (LWJGL). But I'm really confused about all this.

I want to have a 3D first person camera. The move (translation) is working fine but the rotation isnt working like I need. I need a camera to rotate arround world Axis and not about its own axis. But even using Quaternions, this doesnt work and no matter how much I read about Euler Angles, everybody says to me dont touch on it!

This is a little piece of code that i'm using to make the rotation:

    Quaternion qPitch = Quaternion.createFromAxis(cameraRotate.x, 1.0f, 0.0f, 0.0f);
    Quaternion qYaw = Quaternion.createFromAxis(cameraRotate.y, 0.0f, 1.0f, 0.0f);

    this.multiplicate(qPitch.toMatrix4f().toArray());
    this.multiplicate(qYaw.toMatrix4f().toArray());

Where this is a Matrix4f view matrix and cameraRotate is a Vector3f that just handle the angles to rotate obtained from mouse move. So I think I'm doing everything right:

  1. Translate the view Matrix
  2. Rotate the Move Matrix

So, after reading all this, I just want to know: To obtain a correct first person camera rotate, I must need to use Quaternios to make the rotations, but how to rotate around world axis?

EDIT:

OK, i'm following @Sean Middleditch solution and this should be good, but I think i've missed something...here is the code:

public Matrix4f getView() {
    if (!viewChanged) return viewMatrix; 
    if (position == null) position = Vector3f.createEmpty();
    if (rotation == null) rotation = Vector3f.createEmpty();

    viewMatrix = Matrix4f.createIdentity();
    viewMatrix.rotate(rotation);

    Vector4f forward = Vector4f.multiplicate(viewMatrix, new Vector4f(0, 0, -1, 0));
    Vector4f up = Vector4f.multiplicate(viewMatrix, new Vector4f(0, 1, 0, 0));
    Vector4f right = Vector3f.cross(forward.toVector3f(), up.toVector3f()).toVector4f();

    viewMatrix = new Matrix4f(new float[]{
            right.x,                                        up.x,                                       -forward.x,                                     0,
            right.y,                                        up.y,                                       -forward.y,                                     0,
            right.z,                                        up.z,                                       -forward.z,                                     0,
            -Vector4f.dot(right, position.toVector4f()),    -Vector4f.dot(up, position.toVector4f()),   -Vector4f.dot(forward, position.toVector4f()),  1   
    });

    setViewChanged(false);
    return viewMatrix;
}

Everything seems to be right, but the "Camera" is rotating now over the origin axis...and I think the problem is because I didnt understand the following:

construct a regular rotation matrix, and then multiply the standard camera vectors by that matrix

Thanks for reading it.

Best regards,

Afonso Lage

\$\endgroup\$
  • \$\begingroup\$ multiplicate ? \$\endgroup\$ – Sean Middleditch Jul 3 '13 at 3:02
  • \$\begingroup\$ Sorry? multiplicate = *... \$\endgroup\$ – Afonso Lage Jul 3 '13 at 3:10
  • \$\begingroup\$ I haven't seen that operation called multiplicate before; doesn't mean it's wrong, I've just never seen it. Doesn't LWJGL just call it mul ? \$\endgroup\$ – Sean Middleditch Jul 3 '13 at 3:17
  • \$\begingroup\$ Yes but i'm creating my own math library, and because this i've wanted to use multiplicate instead of mul. \$\endgroup\$ – Afonso Lage Jul 3 '13 at 5:07
3
\$\begingroup\$

Don't use quaternions here. Whoever told you to avoid Euler angles for first-person cameras was not speaking from experience.

A possible choice, if you really want to avoid Euler angles, is to store explicit view (forward) and right vectors. You can then modify your yaw by rotating both vectors around (0,1,0). I assume you have an implicit "always up" vector like this; most FPS games do. You can modify pitch by rotating both vectors around the right vector, which is cross(view,up).

It's easier still to just store the Euler angles, construct a regular rotation matrix, and then multiply the standard camera vectors by that matrix.

// if you don't store the vectors pre-calculated
rotation = rotate(yaw,pitch,row)
forward = rotation * vec4(0,0,-1,0)
up = rotation * vec4(0,1,0,0)
right = cross(forward, up)

// maybe the transpose for your matrix class, don't know
camera = mat44(
   right.x, right.y, right.z, -dot(right, pos),
   up.x, up.y, up.z, -dot(up, pos),
   -forward.x, -forward.y, -forward.z, -dot(forward, pos),
   0, 0, 0, 1)

Euler angles can cause some problems in some contexts, but not generally here. Unless you're making a free-form space shooter, odds are that you will have constraints on the pitch (something like (-pi/2,+pi/2)) and will not allow free control of roll. The problems with gimbal lock, which are made out to be a much larger problem than they really are, will not be an issue for you in this use case.

Take a look at gluLookTo for more information on constructing a camera matrix.

\$\endgroup\$
  • \$\begingroup\$ I'd also be suspect of that camera matrix example I gave. I can never for the life of me remember exactly how it goes. Swapping back and forth between LHS/row-major and RHS/column-major doesn't help, either. \$\endgroup\$ – Sean Middleditch Jul 3 '13 at 3:20
  • \$\begingroup\$ thanks for the answer, this seems to be the right way to do it, but I think i'm missing something because now the Camera is rotating over the origin axis...I've updated my question with my current code based on your answer. Thanks for helping me! \$\endgroup\$ – Afonso Lage Jul 3 '13 at 5:06
  • \$\begingroup\$ just double check that math, work out the values of forward, up, and right and viewMatrix for some "easy" rotations like "90degree left" and make sure you get in the computer what you get on paper. I wouldn't trust any math I provided, I am the king of screwing up basic formulas. \$\endgroup\$ – Sean Middleditch Jul 3 '13 at 6:25

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.