2012-03-25 17 views
8

Mam kamerę 3D z bieżącym obrotem zapisanym jako kwaternion i mam problem z jej prawidłowym obracaniem. Chcę, aby kamera obracała się stopniowo wokół swoich lokalnych osi w oparciu o ruch myszy każdą ramką (styl pierwszoosobowy), ale obrót jest nieprawidłowy. To działa, ale kamera wydaje się "toczyć" wokół swojej osi przedniej, kiedy nie powinna.Aparat kwaternionowy. Jak sprawić, aby obracał się prawidłowo?

zaktualizować rotację każdą klatkę z tej funkcji:

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

oto moja funkcja quaternion mnożenie:

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

Czy robię coś źle, czy też jest to jakiś rodzaj zmiennoprzecinkowej-błędu rzecz?

+0

Twoja metoda mnożenia Q wydaje się być poprawna. Może to być rzecz zmiennoprzecinkowa, lub może to być niewłaściwe argumenty do 'Camera :: rotate'. Zrób rejestr wszystkich wywołań tej funkcji, zapisując zarówno 'q' jak i' m_rot' do pliku i przeanalizuj go. –

+0

powiązane: http://stackoverflow.com/questions/16384571/rotate-a-quaternion – danijar

Odpowiedz

7

Wyliczyłem problem. W przypadku sterowanej myszą kamery pierwszej osoby, takiej jak ta, którą zamierzam, chcę obrócić wokół lokalnej osi X, aby spojrzeć w górę iw dół, ale globalna oś Y do szukania obok siebie.

Więc ta jest poprawna dla osi x:

m_rot = m_rot * q; 

Ale muszę to zrobić dla osi y:

m_rot = d * m_rot; 
0

Ponieważ nie mogłem znaleźć żadnej pracy przykład jak skonfigurować kamerę pierwszej osoby za pomocą DirectXMath i ponieważ spędziłem dwa dni pracując nad moim rozwiązaniem, postanowiłem opublikować tutaj moje rozwiązanie. Być może jest ktoś, kto pracuje nad tym samym problemem. Moje rozwiązanie nie jest zoptymalizowane, ale matematyka za nim powinna być poprawna.

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; 
} 
Powiązane problemy