title: Small Quaternion camera bug? (rotates slightly on Z axis)
body: <p>As I spin my mouse CW the objects on the screen rotate CCW, and vice versa. It's not a huge bug but it seems wrong.</p>
  
  <p>I'm using Eigen for quaternions and vectors so the issue should just fall under the code I have posted.</p>
  
  <p><strong>Camera:</strong></p>
  
  <pre><code>#include &lt;Eigen/Dense&gt;
  #include &lt;cstring&gt;
  #include &lt;math.h&gt;
  
  typedef Eigen::Vector3f vec3;
  typedef Eigen::Quaternionf Quaternion;
  
  namespace vec
  {
      //
      // Constants
      //
      const vec3 i(1, 0, 0);
      const vec3 j(0, 1, 0);
      const vec3 k(0, 0, 1);
      const vec3 zero(0, 0, 0);
      const vec3 ones(1, 1, 1);
  }
  
  class Camera 
  {
  void init();
  
  void moveX(float dist);
  void moveY(float dist);
  void moveZ(float dist);
  
  void rotateX(float radians); //yaw
  void rotateY(float radians); //pitch
  void rotateZ(float radians); //roll
  
  void moveLeft(float dist);
  void moveForward(float dist);
  void moveUp(float dist);
  
  void rotateLeft(float radians); //yaw
  void rotateUp(float radians); //pitch
  void rollLeft(float radians); //roll
  
  void setPosition(const vec3 &amp;pos);
  void setDirection(const vec3 &amp;dir);
  void lookAt(const vec3 &amp;pos); //changes direction
  
  // Camera Vectors
  vec3 left() const;
  vec3 right() const;
  vec3 up() const;
  vec3 down() const;
  vec3 forward() const;
  vec3 backward() const;
  const vec3 &amp;pos() const;
  
  protected:
      Quaternion mRotation;
      vec3 mPos;
  
      void rotateL(float radians, const vec3 &amp;axis);
      void rotateR(float radians, const vec3 &amp;axis);
  };
  </code></pre>
  
  <p><strong>Implementation:</strong></p>
  
  <pre><code>void Camera::init()
  {
      mPos.setZero();
      mRotation.setIdentity();
  }
  
  inline void Camera::rotateL(float radians, const vec3 &amp;axis)
  {
      Quaternion q(Eigen::AngleAxis&lt;float&gt;(radians, axis));
      mRotation = (q * mRotation).normalized();
  }
  
  inline void Camera::rotateR(float radians, const vec3 &amp;axis)
  {
      Quaternion q(Eigen::AngleAxis&lt;float&gt;(radians, axis));
      mRotation = (mRotation * q).normalized();
  }
  
  void Camera::moveX(float dist)
  {
      mPos.x() += dist;
  }
  
  void Camera::moveY(float dist)
  {
      mPos.y() += dist;
  }
  
  void Camera::moveZ(float dist)
  {
      mPos.z() += dist;
  }
  
  void Camera::rotateX(float radians)
  {
      rotateL(radians, vec::i);
  }
  
  void Camera::rotateY(float radians)
  {
      rotateL(radians, vec::j);
  }
  
  void Camera::rotateZ(float radians)
  {
      rotateL(radians, vec::k);
  }
  
  void Camera::moveLeft(float dist)
  {
      mPos += dist * left();
  }
  
  void Camera::moveUp(float dist)
  {
      mPos += dist * up();
  }
  
  void Camera::moveForward(float dist)
  {
      mPos += dist * forward();
  }
  
  void Camera::rotateLeft(float radians)
  {
      rotateL(radians, up());
  }
  
  void Camera::rotateUp(float radians)
  {
      rotateL(radians, left());
  }
  
  void Camera::rollLeft(float radians)
  {
      rotateL(radians, forward());
  }
  
  void Camera::setPosition(const vec3 &amp;pos) 
  {
      mPos = pos;
  }
  
  void Camera::setDirection(const vec3 &amp;dir)
  {
      mRotation.setFromTwoVectors(vec::k, dir);
      mRotation.normalize();
  }
  
  void Camera::lookAt(const vec3 &amp;pos)
  {
      setDirection(mPos - pos);
  }
  
  // Camera Vectors
  vec3 Camera::left() const
  {
      return mRotation._transformVector(vec::i);
  }
  
  vec3 Camera::right() const
  {
      return -left();
  }
  
  vec3 Camera::up() const
  {
      return mRotation._transformVector(vec::j);
  }
  
  vec3 Camera::down() const
  {
      return -up();
  }
  
  vec3 Camera::forward() const
  {
      return mRotation._transformVector(vec::k);
  }
  
  vec3 Camera::backward() const
  {
      return -forward();
  }
  
  const vec3 &amp;Camera::pos() const
  {
      return mPos;
  }
  </code></pre>
  
  <p><strong>Updates Functions:</strong></p>
  
  <pre><code>void App::onMouseMotion(int x, int y, int dx, int dy)
  {
      cam.rotateUp(dy * ROTATE_SCALE); 
      cam.rotateLeft(-dx * ROTATE_SCALE);
  }
  
  
  void App::update()
  {
      cam.moveLeft(((int)Keyboard::isKeyDown('a')) * MOVE_SCALE * mDt);
      cam.moveLeft(((int)Keyboard::isKeyDown('d')) * -MOVE_SCALE * mDt);
      cam.moveForward(((int)Keyboard::isKeyDown('w')) * MOVE_SCALE * mDt);
      cam.moveForward(((int)Keyboard::isKeyDown('s')) * -MOVE_SCALE * mDt);
  
      cam.rollLeft(((int)Keyboard::isKeyDown('q')) * -ROLL_SCALE * mDt);
      cam.rollLeft(((int)Keyboard::isKeyDown('e')) * ROLL_SCALE * mDt);
  }
  </code></pre>
  
  <p>I've read that some issues are due to combining Quaternions on the incorrect side... such as Q<em>R instead of R</em>Q. Switching the X axis as suggested <a href="https://stackoverflow.com/questions/9857398/quaternion-camera-how-do-i-make-it-rotate-correctly" title="here">here</a> definitely doesn't help. </p>
  
  <p>I'd also appreciate any suggestions with my implementation. I've consider switching to matrices for rotations but normalizing and combining them is more expensive.</p>