【问题标题】:Quaternion camera. How do I make it rotate correctly?四元数相机。如何让它正确旋转?
【发布时间】:2012-03-25 02:16:10
【问题描述】:

我有一个 3D 相机,它的当前旋转存储为四元数,但我无法正确旋转它。我希望相机根据每帧的鼠标移动(第一人称射击风格)围绕其局部轴增量旋转,但旋转是错误的。它有点工作,但相机似乎在不应该的时候绕着它的前轴“滚动”。

我用这个函数更新每一帧的旋转:

void Camera::rotate(const Quat& q)
{
    // m_rot is the current rotation
    m_rot = m_rot * q;
}

这是我的四元数乘法函数:

Quat Quat::operator*(const Quat &rhs) const
{
    // quaternion elements in w,x,y,z order
    Vector4d res;

    res[0] = m_q[0]*rhs.m_q[0] - m_q[1]*rhs.m_q[1] -
             m_q[2]*rhs.m_q[2] - m_q[3]*rhs.m_q[3];
    res[1] = m_q[0]*rhs.m_q[1] + m_q[1]*rhs.m_q[0] +
             m_q[2]*rhs.m_q[3] - m_q[3]*rhs.m_q[2];
    res[2] = m_q[0]*rhs.m_q[2] - m_q[1]*rhs.m_q[3] +
             m_q[2]*rhs.m_q[0] + m_q[3]*rhs.m_q[1];
    res[3] = m_q[0]*rhs.m_q[3] + m_q[1]*rhs.m_q[2] -
             m_q[2]*rhs.m_q[1] + m_q[3]*rhs.m_q[0];

    return Quat(res);
}

是我做错了什么,还是这是某种浮点错误?

【问题讨论】:

标签: c++ math 3d rotation


【解决方案1】:

找出问题所在。对于像我要使用的鼠标控制的第一人称相机,我想绕局部 x 轴旋转以向上和向下看,但要绕全局 y 轴旋转以左右看。

所以这对于 x 轴是正确的:

m_rot = m_rot * q;

但我需要为 y 轴执行此操作:

m_rot = d * m_rot;

【讨论】:

    【解决方案2】:

    因为我找不到任何如何使用 DirectXMath 设置第一人称相机的工作示例,并且因为我花了两天时间研究我的解决方案,所以我决定在这里发布我的解决方案。也许有人正在解决同样的问题。我的解决方案没有那么优化,但它背后的数学应该是正确的。

    inline DX11FRAMEWORK_API DirectX::XMFLOAT4X4 MatrixCameraFirstPersonQuaternion(DirectX::XMFLOAT3 &Pos, DirectX::XMFLOAT3 &DeltaPos, DirectX::XMFLOAT3 &DeltaAngles,
            DirectX::XMVECTOR &RotationQuaternion, DirectX::XMFLOAT3 *At = nullptr, DirectX::XMFLOAT3 *Up = nullptr)
    {
        using namespace DirectX;
    
        static const XMFLOAT3 OriginalAt = { 1.f, 0.f, 0.f };
        static const XMFLOAT3 OriginalUp = { 0.f, 1.f, 0.f };
        static const XMFLOAT3 OriginalRight = { 0.f, 0.f, 1.f };
    
        // performing rotation of x-axis (here roll) und z-axis (here pitch) round camera axis using quaternion
        RotationQuaternion = XMQuaternionMultiply(RotationQuaternion, XMQuaternionRotationRollPitchYaw(DeltaAngles.z, 0.f, -DeltaAngles.x));
    
        // performing rotation of y-axis (yaw) round world axis
        XMMATRIX MRotation = XMMatrixMultiply(XMMatrixRotationQuaternion(RotationQuaternion), XMMatrixRotationRollPitchYaw(0.f, -DeltaAngles.y, 0.f));
    
        // keep track of rotation round y-axis because it is rotated round world axis
        DeltaAngles = { 0.f, DeltaAngles.y, 0.f };
    
        // generating camera axis
        XMFLOAT3 CameraAt, CameraRight, CameraUp;
        XMStoreFloat3(&CameraAt, XMVector3TransformCoord(XMLoadFloat3(&OriginalAt), MRotation));
        XMStoreFloat3(&CameraRight, XMVector3TransformCoord(XMLoadFloat3(&OriginalRight), MRotation));
        XMStoreFloat3(&CameraUp, XMVector3TransformCoord(XMLoadFloat3(&OriginalUp), MRotation));
    
        // performing translation
        Pos += CameraAt * DeltaPos.x;
        Pos += CameraUp * DeltaPos.y;
        Pos += CameraRight * DeltaPos.z;
        DeltaPos = { 0.f, 0.f, 0.f };
    
        CameraAt += Pos;
    
        if (At)
            *At = CameraAt;
        if (Up)
            *Up = CameraUp;
    
        // finally generate view matrix
        DirectX::XMFLOAT4X4 Camera;
        DirectX::XMStoreFloat4x4(&Camera, DirectX::XMMatrixLookAtLH(DirectX::XMLoadFloat3(&Pos), DirectX::XMLoadFloat3(&CameraAt), DirectX::XMLoadFloat3(&CameraUp)));
        return Camera;
    }
    

    【讨论】:

      猜你喜欢
      • 2016-02-24
      • 1970-01-01
      • 2012-07-24
      • 2012-05-08
      • 2019-04-06
      • 2023-04-01
      • 1970-01-01
      • 2012-02-01
      • 2018-11-17
      相关资源
      最近更新 更多