2012-03-25 17 views
8

Ho una camera 3D con la sua rotazione corrente memorizzata come un quaternione, e ho problemi a ruotarla correttamente. Voglio che la fotocamera ruoti in modo incrementale attorno ai suoi assi locali basandosi sul movimento del mouse per ogni fotogramma (in prima persona, in stile sparatutto), ma la rotazione è errata. Funziona, ma la fotocamera sembra "rotolare" attorno al suo asse in avanti quando non dovrebbe.Fotocamera Quaternion. Come faccio a ruotare correttamente?

aggiorno la rotazione ogni fotogramma con questa funzione:

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

Ecco la mia funzione di quaternion moltiplicazione:

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

sto facendo qualcosa di sbagliato, o si tratta di un qualche tipo di errore di floating-point cosa?

+0

Il metodo di moltiplicazione Q sembra corretto. Potrebbe essere una cosa a virgola mobile, o potrebbe essere argomenti errati per 'Camera :: ruota '. Fai un log di tutte le chiamate a quella funzione, scrivendo sia 'q' che' m_rot' su file, e analizzalo. –

+0

correlati: http://stackoverflow.com/questions/16384571/rotate-a-quaternion – danijar

risposta

7

Capito il problema. Per una fotocamera in prima persona con controllo del mouse come quella che sto cercando, voglio ruotare attorno all'asse x locale per guardare su e giù, ma l'asse y globale per guardare da un lato all'altro.

Quindi questo è corretto per l'asse x:

m_rot = m_rot * q; 

ma ho bisogno di fare questo per l'asse y:

m_rot = d * m_rot; 
0

Perché non riuscivo a trovare alcun esempio di lavoro come impostare una videocamera in prima persona utilizzando DirectXMath e poiché ho trascorso due giorni a lavorare sulla mia soluzione, ho deciso di pubblicare la mia soluzione qui. Forse c'è qualcuno che sta lavorando sullo stesso problema. La mia soluzione non è ottimizzata ma la matematica dietro dovrebbe essere corretta.

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