Камера кватерниона.Как мне заставить его вращаться правильно? - PullRequest
8 голосов
/ 25 марта 2012

У меня есть 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);
}

Я что-то не так делаю, или это какая-то ошибка с плавающей точкой?

Ответы [ 2 ]

7 голосов
/ 25 марта 2012

Разобрался с проблемой.Для камеры от первого лица, управляемой мышью, такой как та, для которой я собираюсь, я хочу вращаться вокруг локальной оси x, чтобы смотреть вверх и вниз, но глобальной оси y для просмотра из стороны в сторону.

Так что это правильно для оси X:

m_rot = m_rot * q;

Но мне нужно сделать это для оси Y:

m_rot = d * m_rot;
0 голосов
/ 06 сентября 2014

Поскольку я не смог найти ни одного рабочего примера настройки камеры от первого лица с помощью 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;
}
...