2013-08-09 15 views
7

Sto utilizzando glm per creare una classe di telecamera e sto riscontrando alcuni problemi con una funzione lookat. Sto usando un quaternion per rappresentare la rotazione, ma voglio usare la funzione di lookat pre-scritta di glm per evitare la duplicazione del codice. Questa è la mia funzione lookat in questo momento:Conversione di glm :: lookat matrix in quaternion e back

void Camera::LookAt(float x, float y, float z) { 
    glm::mat4 lookMat = glm::lookAt(position, glm::vec3(x, y, z), glm::vec3(0, 1, 0)); 
    rotation = glm::toQuat(lookMat); 
} 

Tuttavia quando chiamo LookAt(0.0f,0.0f,0.0f), la mia macchina fotografica non è ruotato a quel punto. Quando chiamo glm::eulerangles(rotation) dopo la chiamata lookat, ottengo un vec3 con i seguenti valori: (180.0f, 0.0f, 180.0f). position è (0.0f, 0.0f, -10.0f), quindi non dovrei avere alcuna rotazione per guardare 0,0,0. Questa è la funzione che costruisce la matrice di vista:

glm::mat4 Camera::GetView() { 
    view = glm::toMat4(rotation) * glm::translate(glm::mat4(), position); 
    return view; 
} 

Perché non ricevo il quaternione corretto, e come posso risolvere il mio codice?

risposta

0

Desidero utilizzare la funzione di lookat pre-scritta di glm per evitare la duplicazione del codice.

Ma è non codice di duplicazione. La matrice che esce da glm::lookat è solo una mat4. Passando attraverso la conversione da un quaternione a 3 vettori, solo in modo che glm::lookat possa riconvertirlo in un orientamento è solo una perdita di tempo. Hai già fatto l'85% del lavoro di lookat; fai il resto

+1

Questa è davvero una risposta non soddisfacente, in quanto potrebbe esserci una ragione per contenere effettivamente un quaternion. Dire "usa solo la matrice" non è una risposta quando qualcuno ti chiede un modo per produrre un quaternion lookat. – opatut

+0

@opatut: non ho detto "usa solo una matrice". Ho detto che non ha senso trasformare un quaternione in 3 vettori di osservazione al solo scopo di produrre una matrice, quando puoi semplicemente usare direttamente il quaternario. –

1

Mi sono imbattuto in qualcosa di simile, la risposta breve è il tuo look Potrebbe dover essere invertito/trasposto, perché è una rotazione della fotocamera (almeno nel mio caso), al contrario di una rotazione del mondo. Ruotare il mondo sarebbe un inverso di una rotazione della telecamera.

Ho un m_current_quat che è un quaternione che memorizza la rotazione della telecamera corrente. Ho eseguito il debug del problema stampando la matrice prodotta da glm :: lookAt e confrontandola con la matrice risultante ottenuta applicando m_current_quat e una traduzione di m_camera_position. Ecco il codice rilevante per il mio test.

void PrintMatrix(const GLfloat m[16], const string &str) 
{ 
    printf("%s:\n", str.c_str()); 

    for (int i=0; i<4; i++) 
    { 
     printf("["); 
     //for (int j=i*4+0; j<i*4+4; j++) // row major, 0, 1, 2, 3 
     for (int j=i+0; j<16; j+=4) // OpenGL is column major by default, 0, 4, 8, 12 
     { 
      //printf("%d, ", j);   // print matrix index 
      printf("%.2f, ", m[j]); 

     } 
     printf("]\n"); 
    } 
    printf("\n"); 
} 

void CameraQuaternion::SetLookAt(glm::vec3 look_at) 
{ 
    m_camera_look_at = look_at; 

    // update the initial camera direction and up 
    //m_initial_camera_direction = glm::normalize(m_camera_look_at - m_camera_position); 
    //glm::vec3 initial_right_vector = glm::cross(m_initial_camera_direction, glm::vec3(0, 1, 0)); 
    //m_initial_camera_up = glm::cross(initial_right_vector, m_initial_camera_direction); 

    m_camera_direction = glm::normalize(m_camera_look_at - m_camera_position); 
    glm::vec3 right_vector = glm::cross(m_camera_direction, glm::vec3(0, 1, 0)); 
    m_camera_up = glm::cross(right_vector, m_camera_direction); 


    glm::mat4 lookat_matrix = glm::lookAt(m_camera_position, m_camera_look_at, m_camera_up); 

    // Note: m_current_quat quat stores the camera rotation with respect to the camera space 
    // The lookat_matrix produces a transformation for world space, where we rotate the world 
    // with the camera at the origin 
    // Our m_current_quat need to be an inverse, which is accompolished by transposing the lookat_matrix 
    // since the rotation matrix is orthonormal. 
    m_current_quat = glm::toQuat(glm::transpose(lookat_matrix));  

    // Testing: Make sure our model view matrix after gluLookAt, glmLookAt, and m_current_quat agrees 
    GLfloat current_model_view_matrix[16];    

    //Test 1: gluLookAt 
    gluLookAt(m_camera_position.x, m_camera_position.y, m_camera_position.z, 
       m_camera_look_at.x, m_camera_look_at.y, m_camera_look_at.z, 
       m_camera_up.x, m_camera_up.y, m_camera_up.z);  
    glGetFloatv(GL_MODELVIEW_MATRIX, current_model_view_matrix);       
    PrintMatrix(current_model_view_matrix, "Model view after gluLookAt"); 

    //Test 2: glm::lookAt 
    lookat_matrix = glm::lookAt(m_camera_position, m_camera_look_at, m_camera_up); 
    PrintMatrix(glm::value_ptr(lookat_matrix), "Model view after glm::lookAt"); 

    //Test 3: m_current_quat 
    glLoadIdentity(); 
    glMultMatrixf(glm::value_ptr(glm::transpose(glm::mat4_cast(m_current_quat)))); 
    glTranslatef(-m_camera_position.x, -m_camera_position.y, -m_camera_position.z); 
    glGetFloatv(GL_MODELVIEW_MATRIX, current_model_view_matrix);       
    PrintMatrix(current_model_view_matrix, "Model view after quaternion transform");  

    return; 
} 

Spero che questo aiuti.

0

Si sono ottenere il (o meglio: a) rotazione corretta.

Quando chiamo glm::eulerangles(rotation) dopo la chiamata lookat, ottengo un vec3 con i seguenti valori: (180.0f, 0.0f, 180.0f). position è (0,0f, 0,0f, -10,0f), quindi non dovrei avere alcuna rotazione per guardare a 0,0,0.

glm sta seguendo le convenzioni della vecchia funzione fissa GL. E lì, lo spazio degli occhi è stato definito come la fotocamera posizionata all'origine, con puntamento a destra, e guardando in direzione -z. Dal momento che si desidera guardare in direzione positiva z, la telecamera deve girare. Ora, come umano, l'avrei descritto come una rotazione di 180 gradi intorno a , ma una rotazione di 180 gradi attorno a x in combinazione con un'altra rotazione di 180 gradi attorno allo z avrà lo stesso effetto.

4

per correggere l'errore, è sufficiente invertire la rotazione del quaternione si ottiene coniugando in questo modo:

using namespace glm; 

quat orientation = conjugate(toQuat(lookAt(vecA, vecB, up))); 

La mia ipotesi migliore per la causa sarebbe, che glm rende una rotazione del fotocamera deve ruotare il mondo con, che è l'opposto della rotazione degli spettatori.

+0

upvote, mi ha solo aiutato a convertire un vettore di direzione temuto in un quaternario appropriato – Avithohol