首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用四元数问题的C++ OpenGl相机旋转

使用四元数问题的C++ OpenGl相机旋转
EN

Stack Overflow用户
提问于 2012-08-18 12:43:29
回答 2查看 3.2K关注 0票数 0

我在为我的相机实现四元数时遇到了问题。我正在用OpenGL创建一个3D空间射击游戏,我需要避免万向节锁定。如果我只在一个轴上旋转,这很好,但一旦我同时应用俯仰和偏航,它们就会有奇怪的行为。我的旋转角度是使用我的鼠标输入。

在这里,我计算了我的ViewMatrix,并且每帧更新一次

代码语言:javascript
复制
Matrix4x4 camera::GetViewMat()
{
    m_rotation.AddX((oInput.MousePosition.GetY() - oInput.PrevMousePosition.GetY()) * m_sensitivity * dt);
    m_rotation.AddY((oInput.MousePosition.GetX() - oInput.PrevMousePosition.GetX()) * -m_sensitivity * dt);

    Matrix4x4 oTranslateOrigin, oRotate, oView;
    oView.SetIdentity();

    //constructor creates a quaternion from an AxisAngle, the constructor will be shown below
    Quaternions pitch = Quaternions(m_rotation.GetX() * Utility::DegToRad(), Vector3(1, 0, 0));
    Quaternions yaw = Quaternions(m_rotation.GetY() * Utility::DegToRad(), Vector3(0, 1, 0));

    //update orientation with the new quaternion times its current orientation
    ori = ori * yaw * pitch;

    //convert quaternion to matrix, also shown below
    oRotate = ori.ToMatrix();
    oTranslateOrigin.BuildTranslate(-m_camPosition.GetX(), -m_camPosition.GetY(), -m_camPosition.GetZ());

    oView = oRotate * oTranslateOrigin;

    return oView;
}

初始化ProjectionMatrix

代码语言:javascript
复制
Matrix4x4 camera::GetProjMat(float fFieldOfViewY, float fAspectRatio, float fNearZ, float fFarZ)
{
    // Transposed version of D3DXMatrixPerspectiveFovRH
    float fYScale = 1 / tanf( fFieldOfViewY / 2.0f );
    float fXScale = fYScale / fAspectRatio;
    memset( &m_projMat, 0, sizeof( Matrix4x4 ) );
    m_projMat.Set(0, 0, fXScale);
    m_projMat.Set(1, 1, fYScale);
    m_projMat.Set(2, 2, fFarZ / ( fNearZ - fFarZ ));
    m_projMat.Set(2, 3, ( fNearZ * fFarZ ) / ( fNearZ - fFarZ ));
    m_projMat.Set(3, 2, -1.0f);
    return m_projMat;
   }

这是为AxisAngle创建一个四元数的构造器之一

代码语言:javascript
复制
Quaternions::Quaternions(float angle, Vector3& axis)
{
    FromAxisAngle(angle, axis);
}

void Quaternions::FromAxisAngle(float angle, Vector3& axis)
{
    float halfAngle = angle * ((float)PI/360.0f);
    float sin = sinf(halfAngle);

    this->w = cosf(halfAngle);
    this->x = axis.GetX() * sin;
    this->y = axis.GetY() * sin;
    this->z = axis.GetZ() * sin;
}

Matrix4x4 Quaternions::ToMatrix()
{
    Normalize();
    Matrix4x4 mat;
    mat.SetIdentity();

    mat.Set(0, 0, 1.0f - 2*(this->y * this->y) - 2*(this->z * this->z));
    mat.Set(0, 1, 2*(this->x*this->y) - 2*(this->w*this->z));
    mat.Set(0, 2, 2*(this->x * this->z) + 2*(this->w * this->y));

    mat.Set(1, 0, 2*(this->x * this->y) + 2*(this->w * this->z));
    mat.Set(1, 1, 1.0f - 2*(this->x * this->x) - 2*(this->z * this->z));
    mat.Set(1, 2, 2*(this->y * this->z) - 2*(this->w * this->x));

    mat.Set(2, 0, 2*(this->x * this->z) - 2*(this->w * this->y));
    mat.Set(2, 1, 2*(this->y * this->z) + 2*(this->w * this->x));
    mat.Set(2, 2, 1.0f - 2*(this->x * this->x) - 2*(this->y * this->y));

    return mat;
}

这就是我正在做的事情。

你们能把我引向正确的方向吗?

EN

回答 2

Stack Overflow用户

发布于 2012-08-18 12:45:35

是不是因为这行:

代码语言:javascript
复制
ori = ori * yaw * pitch;

是顺序错了吗?

您始终可以使用openGL函数旋转相机矩阵。只要确保你的相机矩阵在堆栈上。

代码语言:javascript
复制
glRotate(angle, 1, 0, 0);
glRotate(angle, 0, 1, 0);

您可以使用此函数查看某个点:

代码语言:javascript
复制
void gluLookAt( GLdouble eyeX , GLdouble eyeY , GLdouble eyeZ , 
                GLdouble centerX , GLdouble centerY , GLdouble centerZ , 
                GLdouble upX , GLdouble upY , GLdouble upZ );

需要眼睛位置、目标(中心)位置和相机的上方向向量的位置。

票数 0
EN

Stack Overflow用户

发布于 2012-08-18 19:02:03

好的,这就是你想要做的,以避免四元数的万向锁定。另外,我还包含了一些Opengl特定的代码,希望能指引你朝着正确的方向前进。首先,我要把键映射到旋转。

代码语言:javascript
复制
W - Pitch up(x rot)
S - Pitch down(x rot)
A - Yaw left(y rot)
D - Yaw Right(y rot)
Q - Roll left(z rot)
E - Roll right(z rot)

所有你想要的就是当这些被按下的时候调用正确的旋转。例如,用户按下W,我们所要做的就是创建一个四元数,它围绕x旋转1度。使用你的四元数类来实现:

代码语言:javascript
复制
a = EulerToQuat(angle,0,0);
cameraOri = cameraOri * a;

显然,对其他控件也是如此!你需要做的最后一步是使用Opengl中的旋转命令来正确地旋转世界。我们把四元数转换成角度和轴的方式很好,也很容易读懂。(希望你的四元数类能做到这一点!)然后使用这个继续做一个glRotate!

代码语言:javascript
复制
m_frustumCamera->getQuat().GetAxisAngle(axis,angle);
angle = (float)(angle * radToDeg);  
glRotatef(angle,axis.x,axis.y,axis.z);  
glTranslatef(-1*m_frustumCamera->getPos().x,-1*m_frustumCamera->getPos().y,-1*m_frustumCamera->getPos().z);

如果你没有一个可以工作的四元数类,我推荐:http://www.wolframalpha.com/来确保你所有的函数都能给出正确的响应!

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/12015920

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档