How to rotate about the center of screen using quaternions in opengl?

3.8k views Asked by At

I am trying implement arcball/trackball rotation but I have a problem with the center of rotation. I want the center to be the center of my screen no matter what.

Let me explain what I have done so far.

I've created a quaterion (rotation axis: vector_start x vector_end, angle: vector_start * vector_end)

From that quaternion I've created a rotation matrix in order to use it with glMultMatrixf(matrix) and get the desired rotation.

The problem is that while my model seems to arcball rotate as it should it always rotates around its local origin. How could I make it rotate around the center of my screen no matter where its local origin is located?

I suppose a solution to that problem could be to translate the whole rotation axis in the center of the screen and then apply the rotation but is this possible? Do I miss something here?

2

There are 2 answers

4
catchmeifyoutry On

You should be able to solve this by applying rotation and translation matrices in the correct order. In your code you could translate back to the origin T(-pos_x, -pos_y, -pos_z), apply your rotation, and translate to the object center again T(pos_x, pos_y, pos_z). This should work in general, independent of how your rotation matrix is constructed.

0
bkritzer On

Here's some code I wrote a while ago for a 3-stage rocket launch viewer. I got most of the information from http://www.euclideanspace.com/maths/geometry/rotations

Note: yaw, pitch and roll may change for you based on how you set up your coordinate system

      // Assuming the angles are in radians.
            double p = curPitch * Math.PI/180.0 / 2.0;
            double y = curYaw * Math.PI/180.0 / 2.0;
            double r = curRoll * Math.PI/180.0 / 2.0;

            double sinp = Math.sin(p);
            double siny = Math.sin(y);
            double sinr = Math.sin(r);
            double cosp = Math.cos(p);
            double cosy = Math.cos(y);
            double cosr = Math.cos(r);

            Vector3 axis = new Vector3();

            //here's the important part: how you get your quaternion vector!
            axis.x = sinr * cosp * cosy - cosr * sinp * siny;
            axis.y = cosr * sinp * cosy + sinr * cosp * siny;
            axis.z = cosr * cosp * siny - sinr * sinp * cosy;

            //now normalize the vector in case we want to use it again later
            axis = Vector3.normalizeVector(axis);

            orientation[1] = axis.x;
            orientation[2] = axis.y;
            orientation[3] = axis.z;

            //w is omega: the angle to rotate about the quaternion
            double w = cosr * cosp * cosy + sinr * sinp * siny;

            w = Math.acos(w) * 2.0;

            orientation[0] = w;

            gl.glPushMatrix();

              //translate object first, then rotate it.
              gl.glTranslated(curDisplacement[0] + saveDisplacement[0], -curDisplacement[1] + saveDisplacement[2], curDisplacement[2] + saveDisplacement[1]);

              //this order might be messed up because I screwed up my coordinate system, but the idea is still there
              gl.glRotated(orientation[0]*180/Math.PI, orientation[2]*180/Math.PI, orientation[3]*180/Math.PI, orientation[1]*180/Math.PI);

             //place your objects
             gl.glPopMatrix();

Hope this helps!