So after a lot of researching about quaternions I almost got the quaternion camera working. Almost, cause it rotates in a proper way only in a vertical axis. Other rotations stretches and deforms the view (like on a picture below).

enter image description here

  • Wobbling horizontal moves makes only Z axis stretched

I don't like to post topics like "Please, debug my brain", but I'm in a dead end right now, and I don't know how to fix it.

My implementation looks like this:

  1. I Convert an axis-angle rotation to a quaternion and normalize it.
  2. Then multiply it with a camera identity quaternion.
  3. And then multiply a position of a camera (which is a 4x4 model-view matrix) by a product of above multiplication converted to matrix.

My free quaternion camera class looks like this (for now):

function QuaternionCamera() {
    // Fake 4x4 Matrix
    this.position = new Matrix4x3();
    this.rotation = new Quaternion();

QuaternionCamera.prototype = {
    verticalRotation: function(angle) {
        this.rotation.multiply(new Quaternion().axisToQuaternion(angle, 0, 1, 0));

    horizontalRotation: function(angle) {
        this.rotation.multiply(new Quaternion().axisToQuaternion(angle, 1, 0, 0));

And on mouse movement, it runs this:

    camera.verticalRotation(degToRad(deltaX / 6));
    camera.horizontalRotation(degToRad(deltaY / 6));

I believe that this is a proper way to do it, so I'll just dump my math library, maybe you could find a typo in there (cause I have checked it a hunderd of times and found nothing): http://pastebin.com/0zYLaR1V

PS How to get rid off an additional little roll when rotating camera around, so it will move in a game fashion way?

PS2 And where did the imaginery numbers gone when implementing quaternion math to programming language?? ^^ This is a true mystery for me.

  • \$\begingroup\$ If you're applying your rotations strictly sequentially like this, separated by axis, and converting to a matrix every time you need to transform a vector, then I'm not sure that you're gaining anything by using a quaternion representation in the first place. I love quaternions, but for the code you've shown above Euler angles would have the same effect and be easier to read/debug. In fact, Euler angles are often useful for camera movement in games, since they give a clear mapping for axis-selective constraints (John Nesky gave a talk on this at this year's GDC). \$\endgroup\$ – DMGregory Apr 2 '14 at 21:33
  • \$\begingroup\$ @DMGregory By saying "separated by axis" you mean that I have got two functions, one for vertical and one for horizontal rotation? If so, is in this case this function appropiate for quaternions? rotateCamera: function(angleX, angleY) { var quatX = new Quaternion(); var quatY = new Quaternion(); quatX = (new Quaternion().axisToQuaternion(angleY, 1, 0, 0)); quatY = (new Quaternion().axisToQuaternion(angleX, 0, 1, 0)); this.rotation.multiply(quatX.multiply(quatY)); this.position.multiply(this.rotation.quaternionToMatrix()); this.rotation.makeIdentity(); }, \$\endgroup\$ – Winged Apr 3 '14 at 8:10
  • \$\begingroup\$ The code above is 'taken' from this post stackoverflow.com/questions/7938373/… and in OP's opinion it should work just fine. And in my case, it still suffers the same problem. And the reason why I want to implement quaternion camera is LERP and SLERP. \$\endgroup\$ – Winged Apr 3 '14 at 9:15
  • 2
    \$\begingroup\$ If your quaternion is always normalized and your quaterion to matrix code is correct, than you can not have any stretching or slanting. I would check where your quaternion starts to get unnormalized. \$\endgroup\$ – rioki Apr 3 '14 at 9:31

Ahahaha, problem solved, I'm such a math genius ^^: my math library had a typo in function that converts quaternion to a matrix : 1 - 2 * (this.y * this.y - this.z * this.z); - minus times minus makes plus, not minus, as in here: http://www.gameprogrammer.net/delphi3dArchive/quaternions_bestanden/quat1.gif

| improve this answer | |
  • \$\begingroup\$ You can mark your answer as accepted by clicking the check-mark below the voting buttons. (This gives you some rep and helps inform other users you've found an answer that works for you.) \$\endgroup\$ – Anko Apr 3 '14 at 12:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.