2011-10-11 11 views
5

Sto facendo un rollercoaster all'interno di uno skybox in OpenGL e senza molto background sulle sue funzioni o la grafica del computer si sta dimostrando molto difficile. Ho disegnato un rollercoaster utilizzando l'interpolazione di Catmull-Rom spline e ho disegnato ogni punto con glVertex3f. Ora voglio chiamare una funzione update() ogni 50ms per spostare la telecamera attorno alla traccia. gluLookAt() sta producendo risultati strani, sia rimuovendo la traccia dallo schermo, producendo uno schermo nero, ecc. Penso di aver bisogno di spostare alcune delle funzioni della matrice, ma non sono sicuro di dove metterle. Ecco il mio codice finora:OpenGL gluLookAt() non funziona come previsto

int main(int argc, char** argc) 
{ 
    // ... load track, etc ... 

    // Init currpos, nextpos, iter, up 
    currpos = Vec3f(0, 0, 0); 
    nextpos = currpos; 
    iter = 0; 
    up = Vec3f(0, 1, 0); 

    deque<Vec3f> points; 
    Vec3f newpt; 

    // Loop through the points and interpolate 
    for (pointVectorIter pv = g_Track.points().begin(); pv != g_Track.points().end(); pv++) 
    { 
     Vec3f curr(*pv);   // Initialize the current point and a new point (to be drawn) 
     points.push_back(curr);  // Push the current point onto the stack 
     allpoints.push_back(curr); // Add current point to the total stack 

     if (points.size() == 4) // Check if there are 4 points in the stack, if so interpolate 
     { 
      for (float u = 0.0f; u < 1.0f; u += 0.01f) 
      { 
       newpt = interpolate(points[0], points[1], points[2], points[3], u); 
       glColor3f(1, 1, 1); 
       glVertex3f(newpt.x(), newpt.y(), newpt.z()); 

       allpoints.push_back(newpt); 
      } 

      points.pop_front(); 
     } 
    } 

    // glutInit, InitGL(), etc... 
} 

void InitGL(GLvoid) 
{ 
    glEnable(GL_DEPTH_TEST); 
    glDepthFunc(GL_LEQUAL); 
    glMatrixMode(GL_PROJECTION); 
    glLoadIdentity(); 
    gluPerspective(100.0, (GLfloat)WINDOW_WIDTH/(GLfloat)WINDOW_HEIGHT, .0001, 999999); 
    glMatrixMode(GL_MODELVIEW); 
    glClearColor(0.0f, 0.0f, 0.0f, 0.5f); 
} 

void display (void) 
{ 
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 
    glMatrixMode(GL_MODELVIEW); 
    glLoadIdentity(); 
    gluLookAt(currpos.x(), currpos.y(), currpos.z(), nextpos.x(), nextpos.y(), nextpos.z(), up.x(), up.y(), up.z()); 

    glPushMatrix(); 
    glEnable(GL_TEXTURE_2D); // Enable texturing from now on 

    /* draw skybox, this was from previous assignment and renders correctly */ 

    glPopMatrix(); 

    // now draw rollercoaster ... 

    glPushMatrix(); 
    glBegin(GL_LINE_STRIP); 

    deque<Vec3f> points; 
    Vec3f newpt; 

    for each (Vec3f pt in allpoints) 
    { 
     glColor3f(1, 1, 1); 
     glVertex3f(pt.x(), pt.y(), pt.z()); 
    } 

    glutTimerFunc(50, update, 1); 
    glEnd(); 
    glPopMatrix(); 

    // Swap buffers, so one we just drew is displayed 
    glutSwapBuffers(); 
} 

void update(int a) 
{ 
    if (iter < allpoints.size()) 
    { 
     currpos = allpoints[iter]; 
     nextpos = allpoints[iter + 1]; 

     gaze = nextpos - currpos; 
     gaze.Normalize(); 

     Vec3f::Cross3(binorm, gaze, up); 
     binorm.Normalize(); 

     Vec3f::Cross3(up, binorm, gaze); 
     up.Normalize(); 

     glutPostRedisplay(); 
    } 

    iter++; 
} 

L'idea è che sto mantenendo un deque globale allpoints che include i punti di controllo della spline ei punti interpolati. Una volta completato, chiamo update() ogni 50 ms e spostiamo la fotocamera lungo ciascun punto in allpoints. In una versione precedente del progetto, ho potuto vedere che le montagne russe venivano disegnate correttamente. È gluLookAt() che non sembra funzionare come voglio. Con il codice sopra, il programma inizia con la telecamera guardando un lato dello skybox con una parte delle montagne russe, e quindi quando viene chiamato lo update(), le montagne russe scompaiono ma la telecamera non si muove. Ho lavorato con le funzioni della matrice OpenGL e, a seconda di dove sono a volte, update() causerà anche uno schermo vuoto.

risposta

5

Oltre l'assenza di glPopMatrix (che user971377 già macchiato), vi invito glLoadIdentity nella vostra routine disegno, che ovviamente sovrascrive tutti i cambiamenti che hai fatto sulla matrice modelview nel metodo update (utilizzando gluLookAt).

tenere sempre presente: gluLookAt, glOrtho, gluPerspective, glTranslate, glRotate, e tutte le altre funzioni della matrice e di trasformazione lavorano sempre sull'elemento superiore (modificato da glPush/PopMatrix) della pila matrice selezionata (modificato da glMatrixMode). E moltiplicano sempre la matrice attuale, lo sostituiscono. Quindi, come per gluPerspective, è necessario chiamare glLoadIdentity prima di chiamare gluLookAt. E l'intera modifica della telecamera dovrebbe essere eseguita nella routine di rendering, in base alla routine di aggiornamento.

Invece di fare qualsiasi trasformazione GL in update si dovrebbe piuttosto cambiare le variabili da cui dipende la fotocamera e impostare la fotocamera (gluLookAt sulla matrice modelview) nel metodo display. Per dimostrare l'uso standard di queste funzioni, il codice dovrebbe essere qualcosa del tipo:

void display() 
{ 
    <general state setup (glClear, ...)> 

    glMatrixMode(GL_MODELVIEW); 
    glLoadIdentity(); 
    glLookAt(camera);  //view transformation (camera) 

    //object 1 
    glPushMatrix();  //save modelview 
    glTranslate/glRotate/glScale;  //local model transformations 
    <draw object 1> 
    glPopMatrix(); 
    ... 
    //object n 
    glPushMatrix();  //save modelview 
    glTranslate/glRotate/glScale;  //local model transformations 
    <draw object n> 
    glPopMatrix(); 

    gluSwapBuffers(); 
} 

void update() 
{ 
    camera = ...; 
} 

}

+0

Scusa, il 'glPopMatrix()' si trova alla fine del codice skybox, prima delle montagne russe (dato che non includevo il codice skybox, è per questo che l'ho dimenticato nella domanda) - è dove dovrebbe andare, o dovrebbe essere dopo il disegno delle montagne russe? –

+0

@Logan Mentre il flusso di controllo può essere lo stesso in fase di esecuzione, 'glPopMatrix' dovrebbe essere nello stesso scope di' glPushMatrix', poiché entrambi rappresentano un'unità e dovrebbero sempre venire in coppia. –

+0

Voglio dire, dovrebbe 'glPopMatrix()' essere dopo il codice skybox commentato (prima che rc sia disegnato con 'glVertex3f') o dopo il ciclo per disegnare il rc con' glVertex3f'? –

0

gluLookAt applica sempre il suo risultato alla matrice corrente, che nel tuo caso è GL_MODEL_VIEW. Ma quando rendi le tue montagne russe, carichi identità in quella matrice, che cancella il valore che hai usato usando gluLookAt.

In questo caso, non è necessario toccare la vista del modello. Infatti, GL_MODEL_VIEW indica la matrice del modello moltiplicata per matrice di viste. In questo caso, è possibile glPushMatrix() seguito da glMulMatrix(myModelMatrix) e dopo il rendering glPopMatrix(). Con questo, puoi mantenere la tua matrice di visualizzazione all'interno di GL_MODEL_VIEW e utilizzare ancora una matrice di modelli diversa per ogni oggetto

Ti suggerisco anche di cambiare la matrice di proiezione solo una volta per un fotogramma e non per ogni fotogramma.

0

E 'passato molto tempo da quando ho toccato OpenGL, ma qui ci sono alcune cose da considerare:

  • Con ogni chiamata a display(), si sta disegnando la skybox con la matrice corrente poi caricare l'identità matrice per disegnare le montagne russe. Forse carica l'identità all'interno del push/pop in modo che lo skybox sia costante, ma le tue trasformazioni prevalenti sulle montagne russe sono applicate.
  • È necessario chiamare gluPerspective e glMatrixMode con ogni chiamata a display()?
  • Il calcolo ripetuto di binorm da su e poi su da binorm probabilmente ti darà risultati inaspettati in termini di rotazione della telecamera attorno all'asse z dello schermo.
  • La chiamata a gluLookAt sembra avere postposizioni e inversioni invertite, puntando la telecamera nella direzione opposta.
  • (solo parere) Può ancora sembrare strano con una skybox completamente stazionaria. La rotazione della telecamera corrispondente (ma non la traduzione) quando si disegna skybox e montagne russe può sembrare migliore.
+0

Grazie, il vostro suggerimento sta lavorando bene (credo) come le montagne russe stessa è ora in rotazione con la macchina fotografica. La fotocamera stessa però agisce, non segue la traccia e alla fine gira fuori controllo e va fuori dallo skybox. Ho fatto passare il nextpos e il currpos in giro, quindi forse questo è dovuto ai calcoli binorm/up vector? Sai come calcolare questi, perché quello che ho nel mio codice è ciò che è stato suggerito dal nostro TA. –

+0

Il calcolo di up dovrebbe influire solo sul rotaion della fotocamera, che non lo spiega traducendo al di fuori del skybox. I tuoi punti di controllo usano lo stesso orientamento xyz di OpenGL? – SlightNihilism

+0

Nel frattempo, se le tue montagne russe non sono mai esattamente rivolte in alto o in basso tra una scalinata e l'altra, dovresti essere in grado di farla franca mantenendo costante la "salita". Ho persino modificato temporaneamente la guida in modo da poter utilizzare questo metodo fino a quando non sono riuscito a eseguire il debug/test della posizione xyz della videocamera. Quindi mi preoccuperei di un calcolo più sicuro di "up" in seguito. Sfortunatamente, non ho una raccomandazione a portata di mano per quel calcolo. – SlightNihilism

3

Notato nel codice glPushMatrix(); viene richiamata senza glPopMatrix();

Solo un pensiero, questo potrebbe avere qualcosa a che fare con te problema.