How to avoid camera flipping on quaternion rotation?

I have a camera that orbits around a fixed point using quaternions. The problem is that as the camera rotates around the x-axis and passes over a pole, that the camera will flip and produce a mirrored image. This makes sense because the camera is facing the opposite way but the up vector of the camera hasn't changed. Clearly, a new up vector needs to be calculated from the look vector and the right vector but I can't seem to get it to work. Note: this uses http://commons.apache.org/math/api-2.2/org/apache/commons/math/geometry/Rotation.html to represent quaternions.

Anyway, I'm using the following basic procedure to rotate the camera.

The rotation quaternion is initialised to the identity [1, 0, 0, 0]:

private Rotation total = Rotation.IDENTITY;

And the up vector of the camera is initialised as:

private Vector3D up = new Vector3D(0, 1, 0);

Rotation is done by storing the current rotation of the camera as a quaternion and then applying any subsequent rotations to this quaternion, the combined quaternion (total) is then used to rotate the position of the camera. The following code describes this procedure:

/**
 * Rotates the camera by combining the current rotation (total) with any new axis/angle representation of a new rotation (newAxis, rotation).
 */
public void rotateCamera() {
    if (rotation != 0) {
        //Construct quaternion from the new rotation:
        Rotation local = new Rotation(Math.cos(rotation/2), Math.sin(rotation/2) * newAxis.getX(), Math.sin(rotation/2) * newAxis.getY(), Math.sin(rotation/2) * newAxis.getZ(), true);

        //Generate new camera rotation quaternion from current rotation quaternion and new rotation quaternion:
        total = total.applyTo(local);

        //Rotate the position of the camera using the camera rotation quaternion:
        cam = rotateVector(local, cam);

        //rotation is complete so set the next rotation to 0
        rotation = 0;
    }
}

/**
 * Rotate a vector around a quaternion rotation.
 * 
 * @param rotation The quaternion rotation.
 * @param vector A vector to be rotated.
 * @return The rotated vector.
 */
public Vector3D rotateVector(Rotation rotation, Vector3D vector) {
    //set world centre to origin, i.e. (width/2, height/2, 0) to (0, 0, 0)
    vector = new Vector3D(vector.getX() - width/2, vector.getY() - height/2, vector.getZ());

    //rotate vector
    vector = rotation.applyTo(vector);

    //set vector in world coordinates, i.e. (0, 0, 0) to (width/2, height/2, 0) 
    return new Vector3D(vector.getX() + width/2, vector.getY() + height/2, vector.getZ());
}

The fields newAxis and rotation which store the axis/angle of any new rotation are generated by key presses as follows:

@Override
public void keyPressed(KeyEvent e) {
    if (e.getKeyCode() == KeyEvent.VK_W) {
        camera.setAxis(new Vector3D(1, 0, 0));
        camera.setRotation(0.1);
    }
    if (e.getKeyCode() == KeyEvent.VK_A) {
        camera.setAxis(new Vector3D(0, 1, 0));
        camera.setRotation(0.1);
    }
    if (e.getKeyCode() == KeyEvent.VK_S) {
        camera.setAxis(new Vector3D(1, 0, 0));
        camera.setRotation(-0.1);
    }
    if (e.getKeyCode() == KeyEvent.VK_D) {
        camera.setAxis(new Vector3D(0, 1, 0));
        camera.setRotation(-0.1);
    }
}

During each render loop the rotateCamera() method is called and then the following code sets the camera:

glu.gluLookAt(camera.getCam().getX(), camera.getCam().getY(), camera.getCam().getZ(), camera.getView().getX(), camera.getView().getY(), camera.getView().getZ(), 0, 1, 0);

You're doing something weird. A unit quaternion represents an entire orientation. You wouldn't normally use an 'up' vector with it. But... it looks like you'd get the effect you want by just using a constant 'up' vector [0,1,0] instead of getting it from the quaternion.

It really sounds like you don't need quaternions. What you want is a constant 'up' vector of [0,1,0]. Then you want an 'at' point that is always the point you're orbiting. Then you want an 'eye' point that can be rotated (with respect to your orbit point) around the y-axis or around the axis defined by the cross-product between your 'up' vector and the vector between your orbit point and the 'eye' point.

链接地址: http://www.djcxy.com/p/81756.html

上一篇: C ++ OpenGl使用四元数问题的相机旋转

下一篇: 如何避免相机翻转四元数旋转?