Graphics 如何使用单个四元数表示来控制3D摄影机的方向?

Graphics 如何使用单个四元数表示来控制3D摄影机的方向?,graphics,3d,quaternions,3dcamera,Graphics,3d,Quaternions,3dcamera,我正在为我的游戏引擎创建一个3D相机,我想用一个四元数来表示相机的方向。通过将此四元数转换为旋转矩阵来生成局部上、前和侧摄影机轴。这个矩阵的第一行给我相机的X轴(侧向量),第二行给我上向量,第三行给我前向量。要移动相机,我的函数将沿移动方向移动,数量和位置将更新,视图矩阵()也将更新。要旋转相机,我的函数获取要旋转的轴和角度。将从此轴和角度创建临时四元数,并将其应用于相机的当前方向。我围绕世界Y轴旋转以进行偏航,并围绕摄影机的侧向量旋转以进行俯仰。当我相机的轴与世界轴不对齐时,此俯仰无法正常工作

我正在为我的游戏引擎创建一个3D相机,我想用一个四元数来表示相机的方向。通过将此四元数转换为旋转矩阵来生成局部上、前和侧摄影机轴。这个矩阵的第一行给我相机的X轴(侧向量),第二行给我上向量,第三行给我前向量。要移动相机,我的函数将沿移动方向移动,数量和位置将更新,视图矩阵()也将更新。要旋转相机,我的函数获取要旋转的轴和角度。将从此轴和角度创建临时四元数,并将其应用于相机的当前方向。我围绕世界Y轴旋转以进行偏航,并围绕摄影机的侧向量旋转以进行俯仰。当我相机的轴与世界轴不对齐时,此俯仰无法正常工作。如果我改为围绕全局X轴俯仰,那么效果很好,但我知道这不是我想要的。此外,当我的相机的轴与世界轴不对齐时,运动也会出错。我使用的是基本的“wasd”运动。我的移动和俯仰函数使用局部轴,因此我有一种预感,即我从四元数中提取局部轴的方法是不正确的,但我无法找出哪里出了问题

摄像机等级:

#include "stdafx.h"

Camera * Camera::m_currentCamera = NULL;
    Camera::Camera(vec3 position , double distToNear , double distToFar , double fovy)
{
    m_position = position;
    m_distToNear = distToNear;
    m_distToFar = distToFar;
    m_fovy = fovy;
    // generate the view and projection matrices
    updateViewMatrix();
    projection = glm::perspective(m_fovy, 4.0/3.0, m_distToNear, m_distToFar);
    // in radians
    m_deltaAngle = 10.0 * PIOVER180;

    if(m_currentCamera != NULL)
    {
        delete m_currentCamera;
    }

    m_currentCamera = this;
}

Camera::Camera()
{

}

Camera::~Camera()
{
    // empty for now
}

Camera* Camera::getCurrentCamera()
{
    return m_currentCamera;
}

/** set and get camera position */
vec3 Camera::getPosition()
{
    return m_position;
}

void Camera::setPosition(vec3 pos)
{
    m_position = pos;
}


/** set and get near plane distance */
double Camera::getNearPlaneDist()
{
    return m_distToNear;
}

void Camera::setNearPlaneDist(double dist)
{
    m_distToNear = dist;
}

/** set and get far plane distance */
double Camera::getFarPlaneDist()
{
    return m_distToFar;
}

void Camera::setFarPlaneDist(double dist)
{
    m_distToFar = dist;
}

/** set and get camera field of view */
double Camera::getFovy()
{
    return m_fovy;
}

void Camera::setFovy(double angle)
{
    m_fovy = angle;
}

mat4 Camera::getViewMatrix()
{
    return view;
}

mat4 Camera::getProjectionMatrix()
{
    return projection;
}

Quaternion Camera::getOrientation()
{
    return m_rotation;
}

void Camera::setOrientation(Quaternion *q)
{
    m_rotation.setQuaternion(q);
}

/** this function will be called whenever the camera's position, up vector or lookat vector changes */
void Camera::updateViewMatrix()
{
    mat4 orientation = m_rotation.toMatrix();
    mat4 translation = translate(mat4(1.0f),vec3(-m_position.x,-m_position.y,-m_position.z));
    view = orientation * translation;
}

/** Control Functions */

void Camera::rollCamera(float theta)
{
    Quaternion tempRotation;
    tempRotation.quaternionFromAxis(getFront(), theta);
    tempRotation.normalise();
    m_rotation = m_rotation * &tempRotation;
    m_rotation.normalise();
    updateViewMatrix();
}

void Camera::pitchCamera(float theta)
{
    Quaternion tempRotation;
    // INSTEAD OF LOCAL AXIS IF (1.0,0.0,0.0) GLOBAL X AXIS IS USED THIS WORKS FINE!!!   
    tempRotation.quaternionFromAxis(getSide(), theta);
    tempRotation.normalise();
    m_rotation = m_rotation * &tempRotation;
    m_rotation.normalise();
    updateViewMatrix();
}

void Camera::yawCamera(float theta)
{
    Quaternion tempRotation;
    tempRotation.quaternionFromAxis(vec3(0.0,1.0,0.0), theta);
    tempRotation.normalise();
    m_rotation = m_rotation * &tempRotation;
    m_rotation.normalise();
    updateViewMatrix();
}

void Camera::moveCamera(vec3 dir, float amt)
{
    normalize(dir);
    m_position += dir * amt;
    updateViewMatrix();
}

vec3 Camera::getFront()
{
    m_rotation.normalise();
    mat4 orientation = m_rotation.toMatrix();
    vec3 front(orientation[2][0], orientation[2][1], orientation[2][2]);
    normalize(front);
    cout << "FRONT " << front.x << " " << front.y << " " << front.z << endl;
    return front;
}

vec3 Camera::getSide()
{
    m_rotation.normalise();
    mat4 orientation = m_rotation.toMatrix();
    vec3 side(orientation[0][0], orientation[0][1], orientation[0][2]);
    normalize(side);
    cout << "SIDE " << side.x << " " << side.y << " " << side.z << endl;
    return side;
}

vec3 Camera::getUp()
{
    m_rotation.normalise();
    mat4 orientation = m_rotation.toMatrix();
    vec3 up(orientation[1][0], orientation[1][1], orientation[1][2]);
    normalize(up);
    cout << "UP " << up.x << " " << up.y << " " << up.z << endl;
    return up;
}

这是我关于堆栈溢出的第一篇文章,如果需要更多信息,请告诉我。如果您在我的代码和方法中发现任何错误,请提供帮助。谢谢

这是一个将四元数转换为旋转矩阵的函数。[本页]上的常见问题解答解答了许多与四元数-矩阵转换相关的问题。此外,从您的代码来看,您的所有相机操作似乎都在世界空间中-例如
tempRotation.quaternionFromAxis(vec3(0.0,1.0,0.0),theta),而不是相机空间,因为这更像是你想要的。@Arun R:我已经有了将四元数转换为矩阵的代码。当摄像机已经以一定角度旋转时,从旋转矩阵中提取前、上和侧摄像机向量时,我遇到错误行为。当摄像机处于向下看Z轴的初始位置时,从矩阵中提取向量的工作正常。另外,为了向左和向右看,我需要始终围绕全局Y轴旋转,因此我执行以下操作:tempRotation.quaternionFromAxis(vec3(0.0,1.0,0.0),theta);然后将当前相机方向与此四元数相乘。使用全局四元数
(0,1,0,角度)
并与相机变换相乘:
CT=CT*Q
,在世界空间中进行旋转并将其变换到相机空间,因此,最终这应该看起来像是相机在其局部空间中旋转。另一个选项是仅在世界空间中旋转。这意味着您正在对相机应用世界空间变换。因此,你的相机变换应该与这个旋转相乘,也就是说,你可能需要对Q进行转置,才能使它工作。因此,您将您的相机设置为
世界
,并旋转世界。
void specialKeyboard(int key, int x, int y)
{
    switch(key)
    {
    case GLUT_KEY_LEFT: 
        Camera::getCurrentCamera()->yawCamera(1.0 * PIOVER180);
        break;

    case GLUT_KEY_RIGHT:
        Camera::getCurrentCamera()->yawCamera(-1.0 * PIOVER180);
        break;

    case GLUT_KEY_UP:
        Camera::getCurrentCamera()->pitchCamera(1.0 * PIOVER180);
        break;
    case GLUT_KEY_DOWN:
        Camera::getCurrentCamera()->pitchCamera(-1.0 * PIOVER180);
        break;
    }

    glutPostRedisplay();
}

void keyboard(unsigned char key, int x, int y)
{
    switch(key)
    {
    case 'w':
        Camera::getCurrentCamera()->moveCamera(Camera::getCurrentCamera()->getFront(), -0.1f);
        break;
    case 's':
        Camera::getCurrentCamera()->moveCamera(Camera::getCurrentCamera()->getFront(), 0.1f);
        break;
    case 'a':
        Camera::getCurrentCamera()->moveCamera(Camera::getCurrentCamera()->getSide(), -0.1f);
        break;
    case 'd':
        Camera::getCurrentCamera()->moveCamera(Camera::getCurrentCamera()->getSide(), 0.1f);
        break;
    }
    glutPostRedisplay();
}