5

我刚刚开始使用四元数,但是让一个简单的 FPS 相机使用四元数正常工作时遇到了一些烦人的困难。

基本上,每当我尝试移动鼠标时,我在屏幕上绘制的三角形就会变得疯狂,并且在屏幕上的移动速度比我看到的要快。移动键(wsad)按预期工作,直到我移动鼠标,然后一切都搞砸了。我认为问题出在轮换上,但过去几天我一直在倾注这个问题,但无济于事。

这是正在发生的事情的视频:四元数测试视频

  • 要查看鼠标输入,请从头开始观看。
  • 要查看键盘输入(前进、后退等),请跳至 0:51 秒。

仅供参考,以下是我使用的 3 个主要类:
Quaternion.h
CameraSceneNode.h
CameraSceneNode.cpp

最相关的部分是tick()(我更新旋转四元数的地方)和render()(我渲染“相机”的地方,其中包括旋转和平移场景)。

这是tick()方法:

void CameraSceneNode::tick(float32 time) {
    // movement direction
    if (movement_[MOVE_DIR_FORWARD] == 1)
        pos_ += rotation_ * vmath::Vector3f(0, 0, -moveSpeed_ * time);

    if (movement_[MOVE_DIR_BACKWARD] == 1)
        pos_ += rotation_ * vmath::Vector3f(0, 0, moveSpeed_ * time);

    if (movement_[MOVE_DIR_LEFT] == 1)
        pos_ += rotation_ * vmath::Vector3f(-moveSpeed_ * time, 0, 0);

    if (movement_[MOVE_DIR_RIGHT] == 1)
        pos_ += rotation_ * vmath::Vector3f(moveSpeed_ * time, 0, 0);

    // rotation
    if (xRot_ != 0) {
        Quaternion quatRotation = Quaternion();
        quatRotation.buildFromAxisAngle(1, 0, 0, (xRot_ * time * rotSpeed_) *         math::DEGTORAD);
        //quatRotation.normalize();
        rotation_ = rotation_ * quatRotation;
        xRot_ = 0;
        rotation_.normalize();
    }
    if (yRot_ != 0) {
        Quaternion quatRotation = Quaternion();
        quatRotation.buildFromAxisAngle(0, 1, 0, (yRot_ * time * rotSpeed_) *         math::DEGTORAD);
        //quatRotation.normalize();
        rotation_ = quatRotation * rotation_;
        yRot_ = 0;
        rotation_.normalize();
    }
}

这是render()方法:

void CameraSceneNode::render() {
    if (isActive()) {
        float32 matrix[16];
        rotation_.fillMatrix(matrix);

        glMultMatrixf(&matrix[0]);

        //glRotatef(rotYTest, 0, 1, 0);
        //glRotatef(rotXTest, 1, 0, 0);

        glTranslatef(-pos_.x, -pos_.y, -pos_.z);
    }
}

另外,在我调用render()相机之前,我运行了这段代码:

glMatrixMode(GL_MODELVIEW);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();

两者tick(..)render()在我的主游戏循环中的每一帧都被调用。类中有一些函数CameraSceneNode接受运动方向和摄像机旋转的变化(即改变movement_缓冲区或xRot_yRot_)。

如果这不是足够的信息,我很抱歉。一些函数(如fillMatrix(..))是在我上面引用的 3 个 .h/.cpp 文件中定义的。我已经检查过 Quaternion 类几次,在我看来它是正确的。但是话又说回来,我使用的所有代码对我来说都是正确的,所以谁知道:S

我对此完全束手无策。如果有人能解释为什么这不起作用,我将不胜感激!

干杯

贾勒特

4

1 回答 1

6

从它的外观来看,您正在逐步累积每个刻度的旋转(rotation_ = quatRotation * rotation_;),这首先是有道理的,因为您所做的只是稍微调整旋转,因此应该安全地添加另一个旋转到已经存在的一两个度数,对吗?

但是,每次旋转(通过您正在做的事情)时,实际上每次都会稍微改变旋转轴,这就是为什么您会看到这种不稳定行为的原因。

我的建议是跟踪整体 X/Y 旋转,随着鼠标移动而增加或减少,然后每次直接计算旋转而不是累积旋转。因此,如果您在 X 中旋转 1 度 15 次,您当前的代码基本上是“在 X 中旋转 1 度,在 X 中添加旋转 1 度,等等”。我的建议是跟踪单个旋转因子 X,并随着它的变化直接设置旋转“旋转 13 度、旋转 14 度、旋转 15 度等”。

从您的视频来看,旋转看起来也太大了,因此您可能希望将使用的最终旋转缩放 10 或 50 倍(或其他)。

我可能会走得很远,但我在 3D 编码冒险中遇到过类似的事情,这是我最好的建议。如果这不是问题,因为您正在处理相机旋转,您可能需要使用矩阵逆。更糟糕的是,查看模型视图矩阵的某些旋转,看看它是否符合您的预期(很痛苦,但也是一个有价值的调试练习)。

于 2011-06-15T23:36:09.093 回答