Вращение кватерниона не работает - PullRequest
5 голосов
/ 16 июня 2011

Я только начинаю работать с кватернионами, но у меня возникают некоторые досадные трудности с настройкой простой камеры FPS для правильной работы с использованием кватернионов.

По сути, всякий раз, когда я пытаюсь двигать мышь, треугольник, который я рисую на экране, сходит с ума и уходит на экран быстрее, чем я могу видеть. Клавиши перемещения (wsad) работают, как и ожидалось, ДО того, как я переместил мышь, а затем все испортилось. Я думаю проблема в ротации, но я пролил этот вопрос на последние пару дней, но безрезультатно.

Вот видео о том, что происходит: Quaternion Test Video

  • Чтобы увидеть ввод мыши, смотрите с начала.
  • Чтобы увидеть ввод с клавиатуры (вперед, назад и т. Д.), Перейдите к 0:51 секундам.

Просто для справки, вот 3 основных класса, которые я использую:
Quaternion.h
CameraSceneNode.h
CameraSceneNode.cpp

Наиболее релевантными разделами являются tick() (где я обновляю Quaternion вращения) и 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

Я полностью в своем уме. Если кто-то может пролить свет на то, почему это не работает, я был бы очень признателен !!

Приветствия

Джарретт

1 Ответ

6 голосов
/ 16 июня 2011

Судя по всему, вы постепенно накапливаете свое вращение каждый тик (вращение_ = quatRotation * вращение_;), что поначалу имеет смысл, потому что все, что вы делаете, это слегка настраивает вращение и поэтому оно должно быть безопасно придерживайтесь другой степени или двух степеней вращения, что уже есть, верно?

Тем не менее, каждый раз, когда вы вращаетесь (в зависимости от того, что вы делаете), вы фактически каждый раз слегка меняете ось вращения, и именно поэтому вы видите это странное поведение.

Что я хотел бы предложить, так это отслеживать общие повороты X / Y, увеличивая или уменьшая при перемещении мыши, а затем вычисляя вращение непосредственно каждый раз вместо накопления вращений. Поэтому, если вы повернули в X на 1 градус 15 раз, ваш текущий код, по сути, говорит: «Поверните на 1 градус в X, добавьте вращение на 1 градус в X и т. Д., И т. Д.». То, что я предлагаю, это следить за одним фактором поворота X, и, когда он меняется, установить вращение напрямую: «повернуть на 13 градусов, повернуть на 14 градусов, повернуть на 15 градусов и т. Д.».

Из вашего видео также видно, что повороты слишком велики, поэтому вы можете захотеть масштабировать конечные повороты, используемые в 10 или 50 раз (или как угодно).

Я могу быть далеко, но я сталкивался с подобными вещами в моих приключениях по 3D-кодированию, и это мое лучшее предложение. Если это не проблема, поскольку вы имеете дело с вращением камеры, вам может понадобиться использовать матрицу, обратную. Что еще хуже, посмотрите на матрицу вида модели для определенных поворотов и посмотрите, соответствует ли она вашим ожиданиям (боль, но также и ценное упражнение по отладке).

...