title: Making a Quaternion camera
body: <p>I'd like to be able to create a camera which is first-person, and can be in one of two modes. Either it is fixed looking at a specific location (and standard "wasd" movement moves around that point), or it has free-look, where movement is not constrained to circling around a point and the mouse can be used to look anywhere. (clamped to only be able to look straight up/down though, as I don't want a six degrees of freedom camera a la Descent) This means that I currently do not want to have roll.</p>
  
  <p>Can someone walk me through the basics necessary to implement this kind of thing? I'm currently using LWJGL, so I have access to the Vector* and Matrix* classes they provide, as well as my own Quaternion class which does some stuff that LWJGL doesn't. Also assume that I have a method, lookAt, which is given coordinates exactly like OpenGL's gluLookAt (eyex, eyey, ..., upy, upz), and this is where I wanted to build the matrix/matrices. Also assume the resultant matrix/matrices are going to be used in a version 330 shader where</p>
  
  <pre><code>layout(location = 0) in vec4 position;
  uniform mat4 camera;
  uniform mat4 projection;
  uniform mat4 model;
  // ...
  gl_Position = projection * camera * model * (position);
  </code></pre>
  
  <p>is some of the code. Do I keep the current order of operations, or do I need to change it in  any way to get the correct gl_Position?</p>
  
  <p>Quaternion code:</p>
  
  <pre><code>public class Quaternion {
      public float x, y, z, w;
  
      public Quaternion() {
          this.x = 0.0f;
          this.y = 0.0f;
          this.z = 0.0f;
          this.w = 1.0f;
      }
  
      public Quaternion(Vector3f v, float w) {
          this.x = v.x;
          this.y = v.y;
          this.z = v.z;
          this.w = w;
      }
  
      public Quaternion(float x, float y, float z, float w) {
          this.x = x;
          this.y = y;
          this.z = z;
          this.w = w;
      }
  
      public Quaternion(Quaternion other) {
          this.x = other.x;
          this.y = other.y;
          this.z = other.z;
          this.w = other.w;
      }
  
      public float length() {
          return (float)Math.sqrt(x * x + y * y + z * z + w * w);
      }
  
      public Quaternion normalize() {
          return Quaternion.normalize(new Quaternion(this));
      }
  
      public Quaternion conjugate() {
          return Quaternion.conjugate(new Quaternion(this));
      }
  
      public Quaternion mult(Quaternion other) {
          return Quaternion.mult(this, other, new Quaternion());
      }
  
      public static Quaternion fromAxisAngle(Quaternion q, Vector3f axis, float angle) {
          float sinAngle2 = (float)Math.sin(angle / 2.0);
          q.x = axis.x * sinAngle2;
          q.y = axis.y * sinAngle2;
          q.y = axis.y * sinAngle2;
          q.w = (float)Math.cos(angle / 2.0);
          return q;
      }
  
      public static Matrix4f toMatrixUnit(Quaternion q) {
          Matrix4f ret = new Matrix4f();
  
          ret.m00 = 1 - 2 * q.y * q.y - 2 * q.z * q.z;
          ret.m01 = 2 * q.x * q.y - 2 * q.w * q.z;
          ret.m02 = 2 * q.x * q.z + 2 * q.w + q.y;
          ret.m03 = 0;
  
          ret.m10 = 2 * q.x * q.y + 2 * q.w * q.z;
          ret.m11 = 1 - 2 * q.x * q.x - 2 * q.z * q.z;
          ret.m12 = 2 * q.y * q.z + 2 * q.w * q.x;
          ret.m13 = 0;
  
          ret.m20 = 2 * q.x * q.z - 2 * q.w * q.z;
          ret.m21 = 2 * q.y * q.z - 2 * q.w * q.x;
          ret.m22 = 1 - 2 * q.x * q.x - 2 * q.y * q.y;
          ret.m23 = 0;
  
          ret.m30 = 0;
          ret.m31 = 0;
          ret.m32 = 0;
          ret.m33 = 1;
  
          return ret;
      }
  
      public static Matrix4f toMatrix(Quaternion q) {
          throw new UnsupportedOperationException("Use toMatrixUnit");
  //        Matrix4f ret = new Matrix4f();
  //        return ret;
      }
  
      public static Quaternion mult(Quaternion A, Quaternion B, Quaternion C) {
          C.x = A.w*B.x + A.x*B.w + A.y*B.z - A.z*B.y;
          C.y = A.w*B.y - A.x*B.z + A.y*B.w + A.z*B.x;
          C.z = A.w*B.z + A.x*B.y - A.y*B.x + A.z*B.w;
          C.w = A.w*B.w - A.x*B.x - A.y*B.y - A.z*B.z;
          return C;
      }
  
      public static Quaternion normalize(Quaternion q) {
          float len = q.length();
          q.x = q.x / len;
          q.y = q.y / len;
          q.z = q.y / len;
          q.w = q.w / len;
          return q;
      }
  
      public static Quaternion conjugate(Quaternion q) {
          q.x = -q.x;
          q.y = -q.y;
          q.z = -q.z;
          return q;
      }
  </code></pre>