4
\$\begingroup\$

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).

\$\endgroup\$
2
  • \$\begingroup\$ 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 center for more details. \$\endgroup\$
    – user1430
    Apr 8, 2014 at 16:55
  • \$\begingroup\$ 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. \$\endgroup\$
    – Darcey
    Oct 2, 2017 at 17:52

1 Answer 1

2
\$\begingroup\$

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

\$\endgroup\$

You must log in to answer this question.

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