4
\$\begingroup\$

I've just switched from deprecated opengl functions to using shaders and GLM math library and i'm having a few problems setting up my camera rotations (first person camera). I'll show what i've got setup so far.

I'm setting up my ViewMatrix using the glm::lookAt function which takes an eye position, target and up vector

// arbitrary pos and target values
pos = glm::vec3(0.0f, 0.0f, 10.0f);
target = glm::vec3(0.0f, 0.0f, 0.0f);
up = glm::vec3(0.0f, 1.0f, 0.0f);

m_view = glm::lookAt(pos, target, up);

i'm using glm::perspective for my projection and the model matrix is just identity

m_projection = glm::perspective(m_fov, m_aspectRatio, m_near, m_far);

model = glm::mat4(1.0);

I send the MVP matrix to my shader to multiply the vertex position

glm::mat4 MVP = camera->getProjection() * camera->getView() * model;
// in shader
gl_Position = MVP * vec4(vertexPos, 1.0);

My camera class has standard rotate and translate functions which call glm::rotate and glm::translate respectively

void camera::rotate(float amount, glm::vec3 axis)
{
    m_view = glm::rotate(m_view, amount, axis);
}
void camera::translate(glm::vec3 dir)
{
    m_view = glm::translate(m_view, dir);
}

and i usually just use the mouse delta position as the amount for rotation

Now normally in my previous opengl applications i'd just setup the yaw and pitch angles and have a sin and cos to change the direction vector using (gluLookAt) but i'd like to be able to do this using GLM and matrices.

So at the moment i have my camera set 10 units away from the origin facing that direction. I can see my geometry fine, it renders perfectly. When i use my rotation function...

camera->rotate(mouseDeltaX, glm::vec3(0, 1, 0));

What i want is for me to look to the right and left (like i would with manipulating the lookAt vector with gluLookAt) but what's happening is It just rotates the model i'm looking at around the origin, like im just doing a full circle around it. Because i've translated my view matrix, shouldn't i need to translate it to the centre, do the rotation then translate back away for it to be rotating around the origin? Also, i've tried using the rotate function around the x axis to get pitch working, but as soon as i rotate the model about 90 degrees, it starts to roll instead of pitch (gimbal lock?).

Thanks for your help guys,

and if i've not explained it well, basically i'm trying to get a first person camera working with matrix multiplication and rotating my view matrix is just rotating the model around the origin.

\$\endgroup\$
6
  • \$\begingroup\$ Well, considering the well known truism: "The camera transformation matrix means applying it as an inverse matrix to the poses of the objects in the scene and actually keeping the camera in the fix, universal, almighty coordinate frame".. it can be that you don't end up with an invertible matrix. But it can be that you really manage to stumble upon gimbal lock, although the latter requires a more delicate rotation convention (i.e. axes move in a scene graph/robotic arm manner - you might have multiple solutions for a camera rotation/pose if you use rotation matrices chained together..) \$\endgroup\$
    – teodron
    Jun 21, 2012 at 13:30
  • \$\begingroup\$ Do you mean i should do something like, create a new matrix from axis and angle, then multiply it with the current view matrix? \$\endgroup\$
    – tempvar
    Jun 21, 2012 at 13:35
  • \$\begingroup\$ If you have only one (1) rotation matrix (i.e. rotation against the x by 90 degrees), there's no sense in discussing gimbal lock. If you have two matrices in the chain (rotate_x and rotate_y chained together), the results might not be as expected, but, again, you shouldn't get the lock that easily. Your pondered suggestion is worth trying. In any case, you shouldn't get a gimbal lock. Do things get shrunk all of a sudden when the "gimbal lock" symptom manifests? Try it with normal matrix multiplications and afterwards tell us what happened. Good luck! \$\endgroup\$
    – teodron
    Jun 21, 2012 at 14:44
  • \$\begingroup\$ I guess its not gimbal lock, its expected that once rotating something 90 degrees, a pitch will cause the model to roll. I'm gonna try those things now. \$\endgroup\$
    – tempvar
    Jun 21, 2012 at 14:49
  • \$\begingroup\$ Hm, it shouldn't really, if you rigidly move either of them, with respect to their own frame of reference, they still perform the same. And the perceived behaviour should stay the same - you're just observing the model that's pitching from the top. There's an illusion of this happening if you 'yaw' the camera by 90 degrees (then you align the 'x' axis with the lookAt axis). \$\endgroup\$
    – teodron
    Jun 21, 2012 at 15:03

2 Answers 2

2
\$\begingroup\$

Answer:

Thanks for your help guys.

I just kept track and updated the position and heading variable separately from the view matrix.

glm::vec3 m_position;
glm::vec3 m_direction;

...

// speed is usually 0.1f or something small like that
void camera::rotate(float amount, glm::vec3& axis)
{
    m_direction = glm::rotate(m_direction, amount * m_speed, axis);
}

void camera::translate(glm::vec3& direction)
{
    m_position += direction;
}

// call this once per loop
// m_up is glm::vec3(0, 1, 0) for a first person camera
void camera::update()
{
    m_view = glm::lookAt(m_position, m_position + m_direction, m_up);
}

and just if anyone is curious about strafing of the camera i'll add that code in

enum MovementType {FORWARD, BACKWARD, STRAFE_L, STRAFE_R};

void camera::applyMovement(MovementType movement)
{
    switch (movement)
    {
        case FORWARD:
            m_position += m_direction;
        break;
        case BACKWARD:
            m_position -= m_direction;
        break;
        case STRAFE_LEFT:
            m_position += glm::cross(m_direction, m_up);
        break;
        case STRAFE_RIGHT:
            m_position -= glm::cross(m_direction, m_up);
        break;
    }
}
\$\endgroup\$
2
  • 1
    \$\begingroup\$ You're passing m_direction, a glm::vec3 into glm::rotate, but the first parameter should be a glm::mat4. glm::rotate also returns a glm::mat4, but you are assigning that to m_direction. \$\endgroup\$ Aug 10, 2016 at 20:09
  • 1
    \$\begingroup\$ @ArchieGertsman I just came to mention that there is a glm::rotate that has this signature; you just have to include glm/gtx/rotate_vector.hpp. \$\endgroup\$ Jul 17, 2017 at 17:09
1
\$\begingroup\$

This problem doesn't sound like gimbal lock to me.

It seems to be a case of your translation matrix and rotation matrix being combined together and in the wrong order.

The correct way to do this would be to apply the rotation matrix to the object first, then simply ADD the translation vector, rather than multiplying it in. This will then translate the object on the world axes rather than the objects transformed local axes. This means that the final rotation matrix will rotate irrespective of the translation vector applied afterwards, thus pivoting around its local origin, rather than orbiting around the world origin as you have described.

\$\endgroup\$
3
  • \$\begingroup\$ My problem is not gimbal lock, its just that i'm not sure how to make it look like im rotating my 'camera', not the model. \$\endgroup\$
    – tempvar
    Jun 21, 2012 at 15:33
  • \$\begingroup\$ A dirty fix: target = Rotate(target-pos, params) + pos; ` up = Rotate(up, params);` m_view = glm::lookAt(pos, target, up); - written in a dirty procedural style. The camera stays in place, but pivots around the axis embedded in params. \$\endgroup\$
    – teodron
    Jun 21, 2012 at 16:14
  • \$\begingroup\$ Thank you, i will try that tomorrow (gotta sleep). I'll post an answer when i'ts solved. \$\endgroup\$
    – tempvar
    Jun 21, 2012 at 16:33

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .