【问题标题】:How to avoid camera flipping on quaternion rotation?如何避免相机在四元数旋转时翻转?
【发布时间】:2012-05-08 09:41:49
【问题描述】:

我有一台使用四元数围绕固定点运行的相机。问题在于,当相机绕 x 轴旋转并越过极点时,相机会翻转并产生镜像图像。这是有道理的,因为相机朝向相反的方向,但相机的向上矢量没有改变。显然,需要从外观向量和右向量计算一个新的向上向量,但我似乎无法让它工作。注意:这里使用http://commons.apache.org/math/api-2.2/org/apache/commons/math/geometry/Rotation.html 来表示四元数。

无论如何,我正在使用以下基本过程来旋转相机。

旋转四元数被初始化为恒等式[1, 0, 0, 0]:

private Rotation total = Rotation.IDENTITY;

并且相机的向上向量初始化为:

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

旋转是通过将相机的当前旋转存储为四元数,然后对该四元数应用任何后续旋转来完成的,然后使用组合的四元数(总)来旋转相机的位置。下面的代码描述了这个过程:

/**
 * 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());
}

存储任何新旋转的轴/角度的字段newAxis和rotation由按键生成,如下所示:

@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);
    }
}

在每个渲染循环期间,都会调用 rotateCamera() 方法,然后以下代码设置相机:

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

【问题讨论】:

  • 我不明白你为什么使用 gluLookAt,它计算给定相机位置和你想看到的东西的旋转。如果你已经自己计算了旋转,为什么不直接设置视图矩阵呢?

标签: java opengl rotation jogl quaternions


【解决方案1】:

你在做一些奇怪的事情。一个单位四元数代表一个完整的方向。您通常不会使用“向上”向量。但是......看起来你只需使用一个恒定的“向上”向量 [0,1,0] 而不是从四元数中获取它,就可以获得你想要的效果。

听起来你真的不需要四元数。您想要的是 [0,1,0] 的恒定“向上”向量。然后你想要一个“at”点,它始终是你正在绕行的点。然后,您需要一个可以围绕 y 轴或围绕由您的“向上”向量与您的轨道点和'眼'点。

【讨论】:

  • 感谢您的回答。我这样做的原始方法是调用:glu.gluLookAt(camera.getCam().getX(), camera.getCam().getY(), camera.getCam().getZ(), camera.getView() .getX(), camera.getView().getY(), camera.getView().getZ(), 0, 1, 0);但这会导致相机翻转。我认为四元数是做到这一点的正确方法。我是否应该将 glTranslatef() 和 glMultMatrixf 与四元数的矩阵一起使用,因为我理解 Ishtar 的建议?
  • @noise 在什么情况下会导致相机翻转?以什么方式翻转?
猜你喜欢
  • 2016-02-24
  • 1970-01-01
  • 2012-02-01
  • 2012-07-24
  • 1970-01-01
  • 2023-03-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多