title: Using Quaternions for OpenGL Rotations
body: <p>So I'm writing a program where objects move around spacesim-style, in order to learn how to move things smoothly through 3D space.  After messing around with Euler angles a bit, it seems they aren't really appropriate for free-form 3D movement in arbitrary directions, so I decided to move on to what seems to be best for the job - quaternions.  I intend for the object to rotate around its local X-Y-Z axes at all times, never around the global X-Y-Z axes.</p>
  
  <p>I've tried to implement a system of rotation using quaternions, but something isn't working.  When rotating the object along a single axis, if no previous rotations were undertaken, the thing rotates fine along a given axis.  However, when applying one rotation after another has been performed, the second rotation is not always along the local axis it's supposed to be rotating along - for instance, after a rotation of about 90° around the Z axis, a rotation around the Y axis still takes place around the global Y axis, rather than the new local Y axis which is aligned with the global X axis.</p>
  
  <p>Huh.  So let's go through this step by step.  The mistake must be in here somewhere.</p>
  
  <p><strong>STEP 1 - Capture Input</strong></p>
  
  <p>I figured it would be best to use Euler angles (or a Pitch-Yaw-Roll scheme) for capturing player input.  At the moment, arrow keys control Pitch and Yaw, whereas Q and E control Roll.  I capture player input thus (I am using SFML 1.6):</p>
  
  <pre><code>    ///SPEEDS
      float ForwardSpeed = 0.05;
      float TurnSpeed = 0.5;
  
      //Rotation
      sf::Vector3&lt;float&gt; Rotation;
      Rotation.x = 0;
      Rotation.y = 0;
      Rotation.z = 0;
      //PITCH
      if (m_pApp-&gt;GetInput().IsKeyDown(sf::Key::Up) == true)
      {
          Rotation.x -= TurnSpeed;
      }
      if (m_pApp-&gt;GetInput().IsKeyDown(sf::Key::Down) == true)
      {
          Rotation.x += TurnSpeed;
      }
      //YAW
      if (m_pApp-&gt;GetInput().IsKeyDown(sf::Key::Left) == true)
      {
          Rotation.y -= TurnSpeed;
      }
      if (m_pApp-&gt;GetInput().IsKeyDown(sf::Key::Right) == true)
      {
          Rotation.y += TurnSpeed;
      }
      //ROLL
      if (m_pApp-&gt;GetInput().IsKeyDown(sf::Key::Q) == true)
      {
          Rotation.z -= TurnSpeed;
      }
      if (m_pApp-&gt;GetInput().IsKeyDown(sf::Key::E) == true)
      {
          Rotation.z += TurnSpeed;
      }
  
      //Translation
      sf::Vector3&lt;float&gt; Translation;
      Translation.x = 0;
      Translation.y = 0;
      Translation.z = 0;
  
      //Move the entity
      if (Rotation.x != 0 ||
          Rotation.y != 0 ||
          Rotation.z != 0)
      {
          m_Entity-&gt;ApplyForce(Translation, Rotation);
      }
  </code></pre>
  
  <p>m_Entity is the thing I'm trying to rotate.  It also contains the quaternion and rotation matrices representing the object's rotation.</p>
  
  <p><strong>STEP 2 - Update quaternion</strong></p>
  
  <p>I'm not 100% sure this is the way it's supposed to be done, but this is what I tried doing in Entity::ApplyForce():</p>
  
  <pre><code>//Rotation
  m_Rotation.x += Rotation.x;
  m_Rotation.y += Rotation.y;
  m_Rotation.z += Rotation.z;
  
  //Multiply the new Quaternion by the current one.
  m_qRotation = Quaternion(m_Rotation.x, m_Rotation.y, m_Rotation.z);// * m_qRotation;
  
  m_qRotation.RotationMatrix(m_RotationMatrix);
  </code></pre>
  
  <p>As you can see, I'm not sure whether it's best to just build a new quaternion from updated Euler angles, or whether I'm supposed to multiply the quaternion representing the change with the quaternion representing the overall current rotation, which is the impression I got when reading <a href="http://www.cprogramming.com/tutorial/3d/quaternions.html" rel="noreferrer">this guide</a>.  If the latter, my code would look like this:</p>
  
  <pre><code>//Multiply the new Quaternion by the current one.
  m_qRotation = Quaternion(Rotation.x, Rotation.y, Rotation.z) * m_qRotation;
  </code></pre>
  
  <p>m_Rotation is the object's current rotation stored in PYR format; Rotation is the change demanded by player input.  Either way, though, the problem might be in my implementation of my Quaternion class.  Here is the whole thing:</p>
  
  <pre><code>Quaternion::Quaternion(float Pitch, float Yaw, float Roll)
  {
      float Pi = 4 * atan(1);
  
      //Set the values, which came in degrees, to radians for C++ trig functions
      float rYaw = Yaw * Pi / 180;
      float rPitch = Pitch * Pi / 180;
      float rRoll = Roll * Pi / 180;
  
      //Components
      float C1 = cos(rYaw / 2);
      float C2 = cos(rPitch / 2);
      float C3 = cos(rRoll / 2);
      float S1 = sin(rYaw / 2);
      float S2 = sin(rPitch / 2);
      float S3 = sin(rRoll / 2);
  
      //Create the final values
      a = ((C1 * C2 * C3) - (S1 * S2 * S3));
      x = (S1 * S2 * C3) + (C1 * C2 * S3);
      y = (S1 * C2 * C3) + (C1 * S2 * S3);
      z = (C1 * S2 * C3) - (S1 * C2 * S3);
  }
  
  //Overload the multiplier operator
  Quaternion Quaternion::operator* (Quaternion OtherQuat)
  {
      float A = (OtherQuat.a * a) - (OtherQuat.x * x) - (OtherQuat.y * y) - (OtherQuat.z * z);
      float X = (OtherQuat.a * x) + (OtherQuat.x * a) + (OtherQuat.y * z) - (OtherQuat.z * y);
      float Y = (OtherQuat.a * y) - (OtherQuat.x * z) - (OtherQuat.y * a) - (OtherQuat.z * x);
      float Z = (OtherQuat.a * z) - (OtherQuat.x * y) - (OtherQuat.y * x) - (OtherQuat.z * a);
      Quaternion NewQuat = Quaternion(0, 0, 0);
      NewQuat.a = A;
      NewQuat.x = X;
      NewQuat.y = Y;
      NewQuat.z = Z;
      return NewQuat;
  }
  
  //Calculates a rotation matrix and fills Matrix with it
  void Quaternion::RotationMatrix(GLfloat* Matrix)
  {
      //Column 1
      Matrix[0] = (a*a) + (x*x) - (y*y) - (z*z);
      Matrix[1] = (2*x*y) + (2*a*z);
      Matrix[2] = (2*x*z) - (2*a*y);
      Matrix[3] = 0;
      //Column 2
      Matrix[4] = (2*x*y) - (2*a*z);
      Matrix[5] = (a*a) - (x*x) + (y*y) - (z*z);
      Matrix[6] = (2*y*z) + (2*a*x);
      Matrix[7] = 0;
      //Column 3
      Matrix[8] = (2*x*z) + (2*a*y);
      Matrix[9] = (2*y*z) - (2*a*x);
      Matrix[10] = (a*a) - (x*x) - (y*y) + (z*z);
      Matrix[11] = 0;
      //Column 4
      Matrix[12] = 0;
      Matrix[13] = 0;
      Matrix[14] = 0;
      Matrix[15] = 1;
  }
  </code></pre>
  
  <p>There's probably something in there to make somebody wiser than me cringe, but I can't see it.  For converting from Euler angles to a quaternion, I used the "first method" according to <a href="http://www.euclideanspace.com/maths/geometry/rotations/conversions/eulerToQuaternion/index.htm" rel="noreferrer">this source</a>, which also seems to suggest that the equation automatically creates a unit quaternion ("clearly normalized").  For multiplying quaternions, I again drew on <a href="http://www.cprogramming.com/tutorial/3d/quaternions.html" rel="noreferrer">this C++ guide</a>.</p>
  
  <p><strong>STEP 3 - Deriving a rotation matrix from the quaternion</strong></p>
  
  <p>Once that is done, as per R. Martinho Fernandes' answer to <a href="https://stackoverflow.com/questions/7938373/from-quaternions-to-opengl-rotations">this question</a>, I try to build a rotation matrix from the quaternion and use that to update my object's rotation, using the above Quaternion::RotationMatrix() code in the following line:</p>
  
  <pre><code>m_qRotation.RotationMatrix(m_RotationMatrix);
  </code></pre>
  
  <p>I should note that m_RotationMatrix is <code>GLfloat m_RotationMatrix[16]</code>, as per <a href="http://www.opengl.org/sdk/docs/man/xhtml/glMultMatrix.xml" rel="noreferrer">the required parameters of glMultMatrix</a>, which I believe I am supposed to use later on when displaying the object.  It is initialized as:</p>
  
  <pre><code>m_RotationMatrix = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1};
  </code></pre>
  
  <p>Which I believe is the "neutral" OpenGL rotation matrix (every 4 values together represent a column, correct?  Again, I get this from <a href="http://www.opengl.org/sdk/docs/man/xhtml/glMultMatrix.xml" rel="noreferrer">the glMultMatrix page</a>).</p>
  
  <p><strong>STEP 4 - Display!</strong></p>
  
  <p>Finally, we get to the function run each cycle for the object that is supposed to display it.</p>
  
  <pre><code>glPushMatrix();
  
  glTranslatef(m_Position.x, m_Position.y, m_Position.z);
  glMultMatrixf(m_RotationMatrix);
  
  //glRotatef(m_Rotation.y, 0.0, 1.0, 0.0);
  //glRotatef(m_Rotation.z, 0.0, 0.0, 1.0);
  //glRotatef(m_Rotation.x, 1.0, 0.0, 0.0);
  
  //glRotatef(m_qRotation.a, m_qRotation.x, m_qRotation.y, m_qRotation.z);
  
  //[...] various code displaying the object's VBO
  
  glPopMatrix();
  </code></pre>
  
  <p>I have left my previous failed attempts there, commented out.</p>
  
  <p><strong>Conclusion - Sad panda</strong></p>
  
  <p>That is the conclusion of the life cycle of player input, from cradle to OpenGL-managed grave.</p>
  
  <p>I've obviously not understood something, since the behavior I get isn't the behavior I want or expect.  But I'm not particularly experienced with matrix math or quaternions, so I don't have the insight required to see the error in my ways.</p>
  
  <p>Can somebody help me out here?</p>