2013-06-01 5 views
1

Когда я вращаю мышь CW, объекты на экране вращают CCW и наоборот. Это не огромная ошибка, но это кажется неправильным.Маленькая ошибка камеры Quaternion? (слегка вращается по оси Z)

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

камеры:

#include <Eigen/Dense> 
#include <cstring> 
#include <math.h> 

typedef Eigen::Vector3f vec3; 
typedef Eigen::Quaternionf Quaternion; 

namespace vec 
{ 
    // 
    // Constants 
    // 
    const vec3 i(1, 0, 0); 
    const vec3 j(0, 1, 0); 
    const vec3 k(0, 0, 1); 
    const vec3 zero(0, 0, 0); 
    const vec3 ones(1, 1, 1); 
} 

class Camera 
{ 
void init(); 

void moveX(float dist); 
void moveY(float dist); 
void moveZ(float dist); 

void rotateX(float radians); //yaw 
void rotateY(float radians); //pitch 
void rotateZ(float radians); //roll 

void moveLeft(float dist); 
void moveForward(float dist); 
void moveUp(float dist); 

void rotateLeft(float radians); //yaw 
void rotateUp(float radians); //pitch 
void rollLeft(float radians); //roll 

void setPosition(const vec3 &pos); 
void setDirection(const vec3 &dir); 
void lookAt(const vec3 &pos); //changes direction 

// Camera Vectors 
vec3 left() const; 
vec3 right() const; 
vec3 up() const; 
vec3 down() const; 
vec3 forward() const; 
vec3 backward() const; 
const vec3 &pos() const; 

protected: 
    Quaternion mRotation; 
    vec3 mPos; 

    void rotateL(float radians, const vec3 &axis); 
    void rotateR(float radians, const vec3 &axis); 
}; 

Реализация:

void Camera::init() 
{ 
    mPos.setZero(); 
    mRotation.setIdentity(); 
} 

inline void Camera::rotateL(float radians, const vec3 &axis) 
{ 
    Quaternion q(Eigen::AngleAxis<float>(radians, axis)); 
    mRotation = (q * mRotation).normalized(); 
} 

inline void Camera::rotateR(float radians, const vec3 &axis) 
{ 
    Quaternion q(Eigen::AngleAxis<float>(radians, axis)); 
    mRotation = (mRotation * q).normalized(); 
} 

void Camera::moveX(float dist) 
{ 
    mPos.x() += dist; 
} 

void Camera::moveY(float dist) 
{ 
    mPos.y() += dist; 
} 

void Camera::moveZ(float dist) 
{ 
    mPos.z() += dist; 
} 

void Camera::rotateX(float radians) 
{ 
    rotateL(radians, vec::i); 
} 

void Camera::rotateY(float radians) 
{ 
    rotateL(radians, vec::j); 
} 

void Camera::rotateZ(float radians) 
{ 
    rotateL(radians, vec::k); 
} 

void Camera::moveLeft(float dist) 
{ 
    mPos += dist * left(); 
} 

void Camera::moveUp(float dist) 
{ 
    mPos += dist * up(); 
} 

void Camera::moveForward(float dist) 
{ 
    mPos += dist * forward(); 
} 

void Camera::rotateLeft(float radians) 
{ 
    rotateL(radians, up()); 
} 

void Camera::rotateUp(float radians) 
{ 
    rotateL(radians, left()); 
} 

void Camera::rollLeft(float radians) 
{ 
    rotateL(radians, forward()); 
} 

void Camera::setPosition(const vec3 &pos) 
{ 
    mPos = pos; 
} 

void Camera::setDirection(const vec3 &dir) 
{ 
    mRotation.setFromTwoVectors(vec::k, dir); 
    mRotation.normalize(); 
} 

void Camera::lookAt(const vec3 &pos) 
{ 
    setDirection(mPos - pos); 
} 

// Camera Vectors 
vec3 Camera::left() const 
{ 
    return mRotation._transformVector(vec::i); 
} 

vec3 Camera::right() const 
{ 
    return -left(); 
} 

vec3 Camera::up() const 
{ 
    return mRotation._transformVector(vec::j); 
} 

vec3 Camera::down() const 
{ 
    return -up(); 
} 

vec3 Camera::forward() const 
{ 
    return mRotation._transformVector(vec::k); 
} 

vec3 Camera::backward() const 
{ 
    return -forward(); 
} 

const vec3 &Camera::pos() const 
{ 
    return mPos; 
} 

Обновления Функции:

void App::onMouseMotion(int x, int y, int dx, int dy) 
{ 
    cam.rotateUp(dy * ROTATE_SCALE); 
    cam.rotateLeft(-dx * ROTATE_SCALE); 
} 


void App::update() 
{ 
    cam.moveLeft(((int)Keyboard::isKeyDown('a')) * MOVE_SCALE * mDt); 
    cam.moveLeft(((int)Keyboard::isKeyDown('d')) * -MOVE_SCALE * mDt); 
    cam.moveForward(((int)Keyboard::isKeyDown('w')) * MOVE_SCALE * mDt); 
    cam.moveForward(((int)Keyboard::isKeyDown('s')) * -MOVE_SCALE * mDt); 

    cam.rollLeft(((int)Keyboard::isKeyDown('q')) * -ROLL_SCALE * mDt); 
    cam.rollLeft(((int)Keyboard::isKeyDown('e')) * ROLL_SCALE * mDt); 
} 

I'v читайте, что некоторые проблемы связаны с объединением кватернионов с неправильной стороны ... например, Q R вместо R Q. Переключение оси X, как было предложено here, определенно не помогает.

Я также ценю любые предложения с моей реализацией. Я рассматриваю переход на матрицы для вращения, но нормализация и комбинирование их дороже.

ответ

2

Это нормальное поведение при повторном применении поворотов. Вы можете видеть это в некоторых приложениях или играх, которые позволяют свободно вращаться.

  1. Держите руку перед собой. «Вперед» - это ваши пальцы. «Вверх» - это тыльная сторона руки.
  2. Наклоните его вверх примерно на 30 °.
  3. От новой ориентации, наклоните его налево около 30 °.
  4. От новой ориентации, наклоните его около 30 °.
  5. От новой ориентации, наклоните его прямо около 30 °.

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

Это может показаться странным для людей, поскольку мы привыкли к фиксированному направлению вверх.

+0

Я полагаю, что у меня нет большого опыта в играх, где доступно свободное вращение. Было бы невозможно сказать, было ли это проблемой в летных симах, так как вы всегда будете двигаться. Я предполагаю, что я думал, что это осталось/равно как equiv для X/Y ... но они относительны в моем случае. – ffhighwind

+0

Даже после замены его на rotateX и rotateY у него все еще есть проблема ... так что я думаю, что это что-то еще. Попробует один флоат-рывок/шаг/рулон или просто используйте Эйлеров с минимальным/максимальным шагом. – ffhighwind

Смежные вопросы