I can't get it to work for the life of me. Its rotating the camera in the global coordinate system, or some other random coordinate system, not the camera local coordinate system. WASDEC work perfectly, right until I start rotating. Here's the annotated code:

  //eye.r is the quat camera rotation
  //eye.p is the vec3 camera position

  // Get the local axes we're going to do transformations with
  var axes = {
    x: quat4.multiplyVec3(eye.r, [1, 0, 0]),
    y: quat4.multiplyVec3(eye.r, [0, 1, 0]),
    z: quat4.multiplyVec3(eye.r, [0, 0, 1])

  // If a movement key is down, add the appropriately scaled local axis
  // to our position
  if(keystate[W]) vec3.add(eye.p, vec3.scale(axes.z,  10, []));
  if(keystate[S]) vec3.add(eye.p, vec3.scale(axes.z, -10, []));
  if(keystate[A]) vec3.add(eye.p, vec3.scale(axes.x,  10, []));
  if(keystate[D]) vec3.add(eye.p, vec3.scale(axes.x, -10, []));
  if(keystate[E]) vec3.add(eye.p, vec3.scale(axes.y, -10, []));
  if(keystate[C]) vec3.add(eye.p, vec3.scale(axes.y,  10, []));

  // If a rotation key is down, create a scaled rotation about the appropriate
  // local axis, and multiply it into the current rotation
  if(keystate[UP])    quat4.multiply(quat4.rotation(-0.05, axes.x), eye.r, eye.r);
  if(keystate[DOWN])  quat4.multiply(quat4.rotation( 0.05, axes.x), eye.r, eye.r);
  if(keystate[LEFT])  quat4.multiply(quat4.rotation(-0.05, axes.y), eye.r, eye.r);
  if(keystate[RIGHT]) quat4.multiply(quat4.rotation( 0.05, axes.y), eye.r, eye.r);

Thanks for your help!

Edit: Since it might not be clear what the functions do. This is javascript and the glmatrix linear algebra/quat library.

quat4.multiplyVec3(quat, vec) // vec = quat * vec

vec3.add(vec, vec2) // vec = vec + vec2

vec3.scale(vec, scalar, dest) // dest = vec * scalar

quat4.rotation(angle, axis) // creates a quaternion rotation about the given axis, by the given angle

quat4.multiply(quat, quat2, dest) // dest = quat * quat2

2 Answers 2


So, my friend on facebook sorted me out. Here's his answer:

Hmm.. I suspect part of the problem might be that quaternion rotation transformations use a sandwiching product form.

If: v = vector to be rotated q = quaternion representing the intended rotation v' = v after rotation

The rotation should be described by:

v' = qvq^-1

where q^-1 is the the inverse or the conjugate of q.

See: http://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation#From_the_rotations_to_the_quaternions

specifically the second section "Describing rotations with quaternions"

So as a result, my local axis vectors are completely half-baked, and can't be used as such. Fortunately, all they need is another inverse quat multiplication.

EDIT: Or not. On close inspection it looks like the multiply function actually does the two multiplies, one with the quat and one with it's conjugate. The mystery continues...


Might be a pre-multiply/post-multiply issue. Sometimes the order in which you need to apply transformations can be a little counterintuitive.

I would try changing this:

quat4.multiply(quat4.rotation(-0.05, axes.x), eye.r, eye.r)

to one of two possible things:

quat4.multiply(eye.r, quat4.rotation(-0.05, axes.x), eye.r)

or maybe

quat4.multiply(quat4.rotation(-0.05,[1, 0, 0]), eye.r, eye.r)

(and obviously make similar changes for the other rotations).


You must log in to answer this question.

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