2

I am trying to implement an opengl camera that rotates the position of the camera around a specified world coordinate. I am trying to do this using glm math library; my code is as follows

void Camera::dolly(double angle_x, double angle_y, const double& loc_x, const double& loc_y, const double& loc_z, const double& dt) {

  glm::vec3 target = glm::vec3(loc_x,loc_y,loc_z);

  glm::quat Q;glm::vec3 axis0(0.0f,1.0f,0.0f);
  glm::quat R;glm::vec3 axis1(1.0f,0.0f,0.0f);

  position = position - target;

  //glm::normalize(axis0);
  glm::normalize(axis1);

  Q = glm::gtx::quaternion::angleAxis( float(angle_x ), axis0 );;
  R = glm::gtx::quaternion::angleAxis( float(andl_y ), axis1 );;

  glm::quat final =  R*Q;

  position =  final * position;

  position = position + target;
  cout << "\tPosition: " << position.x << " " << position.y << " " << position.z <<endl;
}

When I test the code, rotation using quat Q works fine, but quat R causes "choppy" rotation. What am I doing wrong?

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
ukaku
  • 191
  • 1
  • 11
  • 2
    1) AFAIK, dolly means moving the camera on a straight line. 2) What do you mean by choppy? Where do `x` and `y` come from? It's not clear at all how the code doesn't produce the results you want. – Andreas Haferburg May 25 '13 at 22:55
  • 1) forgive the miss named function name; 2)by choppy i mean that when I rotate position using Q = glm::gtx::quaternion::angleAxis( float(angle_x ), axis0 ); the rotation about axis(0,1,0) is perfectly circular and continues, however when i go to add rotation axis(1,0,0) suddenly the roation from this axis causes the camera position to in unexpected ways. – ukaku May 26 '13 at 01:32

2 Answers2

4

note: copied from my answer here.

All you have done is effectively implement Euler angles with quaternions. That's not helping.

The problem with Euler angles is that, when you compute the matrices, each angle is relative to the rotation of the matrix that came before it. What you want is to take an object's current orientation, and apply a rotation along some axis, producing a new orientation.

You can't do that with Euler angles. You can with matrices, and you can with quaternions (as they're just the rotation part of a matrix). But you can't do it by pretending they are Euler angles.

This is done by not storing angles at all. Instead, you just have a quaternion which represents the current orientation of the object. When you decide to apply a rotation to it (of some angle by some axis), you construct a quaternion that represents that rotation by an angle around that axis. Then you right-multiply that quaternion with the current orientation quaternion, producing a new current orientation.

When you render the object, you use the current orientation as... the orientation.

Community
  • 1
  • 1
Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • 1
    thank you for this answer. my question now is: if i represent all my orientations as quaternions and apply new orientation using new orientation angle and orientation axis and then apply it to the previous orientation to obtain a new orientation(sorry for the long sentence), can I then convert my quaternion to mat4 and still be free of gimbal lock? – ukaku May 26 '13 at 14:34
  • @ukaku: That's a new question, so you should ask it with the "Ask a Question" button. It's also one that you should *try* to implement before asking us. – Nicol Bolas May 26 '13 at 14:54
2

Copied from the question:

EDIT 05/26/2013 How I solved this Problem:

The problem with my code was the when it came to rendering the scene i used:

    matrix = glm::lookAt(position,looking_at, upDirection);

Then I used this matrix to put the scene into the perspective of the camera/basically the render the camera. However, when i called my "Camera::dolly"(which really should not be called dolly, as i aim to rotate the camera) function, i rotated the camera position without rotating/updating the upDirection(which is initialized to (0,1,0) variable. This caused the "choppy" problem that I described because rotating by axis(1,0,0) has the consequence of changing the direction in which the upDirection is pointing to. The new code is as follows:

glm::quat orient = glm::gtx::quaternion::angleAxis(float(0),0.0f, 0.0f, 1.0f);

void Camera::rotate(double angle_x, double angle_y, const double& loc_x, const double& loc_y, const double& loc_z, const double& dt) { glm::vec3 target = glm::vec3(loc_x,loc_y,loc_z);

position = position - target;

angle_x *= dt;
angle_y *= dt;

glm::quat old_orient = orient;

glm::normalize(orient);
glm::quat q_x_axis = glm::gtx::quaternion::angleAxis(float(angle_y),1.0f, 0.0f, 0.0f) ;
glm::quat q_y_axis = glm::gtx::quaternion::angleAxis(float(angle_x), 0.0f, 1.0f, 0.0f);

orient = orient * q_x_axis * q_y_axis;

upDirection = upDirection * orient;
position = position * (orient);

orient = old_orient;

position = position + target;
Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982