4

I've got a question about quaternions in my WebGL application.

How can I rotate an object only around two axes? For example, how can I exclude/nullify rotation about the Y axis?

The problem is that when I rotate something around X axis, and then around Y axis, it rotates around Z axis slightly as well. I have read whole piles of posts about it (for example) but none of them really helped me. Reversal order of multiplication operations doesn't work for me. My actual code below:

// Main rotation function:

rotateCamera: function(angleX, angleY) {
    if (angleY !== 0) {
        this.yawRotation.axisToQuaternion(angleY, this.tempVec.make(1, 0, 0)));
        this.rotation.multiply(this.yawRotation);
    }
    if (angleX !== 0) {
        this.pitchRotation.axisToQuaternion(angleX, this.tempVec.make(0, 1, 0)));
        this.rotation.multiply(this.pitchRotation);
    }
    this.rotation.normalize();

    MVMatrix.setRotation(this.rotation.quaternionToMatrix());

// Matrix setRotation function:

setRotation: function(m) {
    this.element[0] = m.element[0];
    (... some code omitted ...)
    this.element[10] = m.element[10];
},

And the ought-to-be-working code based on other posts (which is not working):

rotateCamera: function(angleX, angleY) {
    if (angleY !== 0) {
        this.yawRotation.axisToQuaternion(angleY, this.tempVec.make(1, 0, 0));
    }
    if (angleX !== 0) {
        this.pitchRotation.axisToQuaternion(angleX, this.tempVec.make(0, 1, 0));
    }
    this.yawRotation.multiply(this.rotation);
    this.rotation.copy(this.yawRotation);
    this.rotation.multiply(this.pitchRotation);
    this.rotation.normalize();

    MVMatrix.setRotation(this.rotation.quaternionToMatrix());
},

EDIT: I have added more info about the actual code.

EDIT2: Okeeeey, I almost found a working answer for my problem (adapted it from Rick Hoskinson's post). My updated code below:

rotateCamera: function(radX, radY) {
    // Pitch (vertical rotation)
    if (radY !== 0) {
        this.pitch += radY;
        // Prevent camera from flipping upside-down (constrained by vertical "plane")
        this.pitch = Math.clamp(this.pitch, -Math.PI/2, Math.PI/2);

        this.rotation.axisToQuaternion(this.yaw, this.tempVec.make(0, 1, 0));
        this.rotation.multiply(this.tempQuat.axisToQuaternion(this.pitch, this.tempVec.make(1, 0, 0)));
    }
    // Yaw (horizontal rotation)
    if (radX !== 0) {
        this.yaw += radX;

        this.rotation.axisToQuaternion(this.yaw, this.tempVec.make(0, 1, 0));
        this.rotation.multiply(this.tempQuat.axisToQuaternion(this.pitch, this.tempVec.make(1, 0, 0)));
    }

    MVMatrix.setRotation(this.rotation.quaternionToMatrix());
}

Camera's roll has been eliminated using this method, but strange camera motion appears when rotating from one of the sides and then looking below (or I should say trying to look below, cause it curves away from this direction).

Winged
  • 340
  • 2
  • 15
  • Please only ask a single question per post. I've edited your question to remove everything but the last unanswered question. I've also revoked the community wiki status you imparted via excessive edits. See the [help] for more details. –  Apr 08 '14 at 16:55
  • Good Question, useful edits and helpful information. Shame admin dick removed additional information, could have been interesting to read. But most stack exchange mods are dicks. – Darcey Oct 02 '17 at 17:52

1 Answers1

2

Finally, I have found an ultimate answer for my question. All I had to do it to use rotation from Euler angles instead of rotating around an axis. Working code below:

Inside camera class:

rotateCamera: function(radX, radY) {
    this.pitch += radY;
    // Prevent camera from flipping upside-down (constrained by vertical "plane")
    this.pitch = Math.clamp(this.pitch, -Math.PI/2, Math.PI/2);

    this.yaw += radX;
    // Cancel unnecessary looping rotation degree
    if (this.yaw <= -2 * Math.PI)
        this.yaw = 0;
    else if (this.yaw >= 2 * Math.PI)
        this.yaw = 0;

    this.rotation.yawPitchRollToQuaternion(this.yaw, this.pitch, 0);

    MVMatrix.setRotation(this.rotation.quaternionToMatrix());
},

yawPitchRollToQuaternion function taken from here: reference

Winged
  • 340
  • 2
  • 15