0

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

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

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;
}

初始化投影矩阵

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 创建四元数的构造函数之一

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;
}

这就是我正在做的事情。

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

4

2 回答 2

0

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

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 我们需要做的就是创建一个四元数 for 并围绕 x 旋转 1 度。使用你的四元数类做到这一点:

a = EulerToQuat(angle,0,0);
cameraOri = cameraOri * a;

显然对其他控件做同样的事情!好的,您需要做的最后一步是使用 Opengl 中的旋转命令正确旋转世界。我们这样做的方式既好又易于阅读,我们将四元数转换为角度和轴。(希望您的四元数类可以这样做!)然后继续使用它进行 glRotate!

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/ 以确保您的所有函数都给出正确的响应!

于 2012-08-18T11:02:02.990 回答
0

是不是因为这一行:

ori = ori * yaw * pitch;

是不是顺序不对?

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

glRotate(angle, 1, 0, 0);
glRotate(angle, 0, 1, 0);

你可以用这个函数看一个点:

void gluLookAt( GLdouble eyeX , GLdouble eyeY , GLdouble eyeZ , 
                GLdouble centerX , GLdouble centerY , GLdouble centerZ , 
                GLdouble upX , GLdouble upY , GLdouble upZ );

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

于 2012-08-18T04:45:34.553 回答