2012-01-14 12 views
7

Sono venuto da questa domanda:Struttura OpenGL di VAO/VBO per il modello con parti mobili?

opengl vbo advice

Io uso OpenGL 3.3 e volontà di non utilizzare le funzioni deprecate. Sto usando Assimp per importare i miei modelli di frullatore. Ma sono un po 'confuso su quanto dovrei dividerli in termini di VAO e VBO.

Prima di tutto una piccola domanda. Io uso glDrawElements, vuol dire che non posso intercalare i miei attributi di vertice o il VAO capisce usando il glVertexAttribPointer e l'offset glDrawElements per vedere dove si trova la mia posizione di vertice?

Domanda principale, suppongo, si riduce a come strutturare il mio VAO/VBO per un modello con più parti mobili e più meshes pr. parte.

Ogni nodo in assimp può contenere più mesh in cui ogni mesh ha trama, vertici, normali, materiale ecc. I nodi in assimp contengono le trasformazioni. Diciamo che ho una nave con una torretta di cannoni su di essa. Voglio essere in grado di guidare la torretta. Significa che renderò il nodo di spedizione un VAO separato con VBO per ogni mesh contenente i suoi attributi (o più VBO ecc.). Credo che va come

draw(ship); //call to draw ship VAO 
pushMatrix(turretMatrix) //updating uniform modelview matrix for the shader 
draw(turret); //call to draw turret VAO 

Non capisco pienamente UBO (oggetti buffer uniforme) ancora, ma sembra che io posso passare in più divise, sarà che mi aiutano a contenere un modello completo con parti mobili in un singolo VAO?

risposta

13

primo, spento VAO "memorizza" solo gli ultimi binding dell'attributo vertice (e il binding VBO per un buffer di indice (GL_ELEMENT_ARRAY_BUFFER_BINDING), se ce n'è uno). Quindi non ricorda gli offset in glDrawElements(), è necessario chiamarlo in seguito quando si utilizza VAO. Non impedisce di utilizzare array di vertici interleaved. Vorrei cercare di spiegare:

int vbo[3]; 
glGenBuffers(3, vbo); 
glBindBuffer(GL_ARRAY_BUFFER, vbo[0]); 
glBufferData(GL_ARRAY_BUFFER, data0, size0); 
glBindBuffer(GL_ARRAY_BUFFER, vbo[1]); 
glBufferData(GL_ARRAY_BUFFER, data1, size1); 
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo[2]); 
glBufferData(GL_ELEMENT_ARRAY_BUFFER, data2, size2); 
// create some buffers and fill them with data 

int vao; 
glGenVertexArrays(1, &vao); 
glBindVertexArray(vao); 
// create a VAO 

{ 
    glBindBuffer(GL_ARRAY_BUFFER, vbo[0]); // not saved in VAO 
    glVertexAttribPointer(0, 3, GL_FLOAT, false, 3 * sizeof(float), NULL); // this is VAO saved state 
    glEnableVertexAttribArray(0); // this is VAO saved state 
    // sets up one vertex attrib array from vbo[0] (say positions) 

    glBindBuffer(GL_ARRAY_BUFFER, vbo[1]); // not saved in VAO 
    glVertexAttribPointer(1, 3, GL_FLOAT, false, 5 * sizeof(float), NULL); // this is VAO saved state 
    glVertexAttribPointer(2, 2, GL_FLOAT, false, 5 * sizeof(float), (const void*)(2 * sizeof(float))); // this is VAO saved state 
    glEnableVertexAttribArray(1); // this is VAO saved state 
    glEnableVertexAttribArray(2); // this is VAO saved state 
    // sets up two more VAAs from vbo[1] (say normals interleaved with texcoords) 

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo[2]); // this is VAO saved state 
    // uses the third buffer as the source for indices 
} 
// set up state that VAO "remembers" 

glBindVertexArray(0); // bind different vaos, etc ... 

tardi ...

glBindVertexArray(vao); // bind our VAO (so we have VAAs 0, 1 and 2 as well as index buffer) 
glDrawElements(GL_TRIANGLE_STRIP, 57, GL_UNSIGNED_INT, NULL); 
glDrawElements(GL_TRIANGLE_STRIP, 23, GL_UNSIGNED_INT, (const void*)(57 * sizeof(unsigned int))); 
// draws two parts of the mesh as triangle strips 

Così si vede ... è possibile disegnare array di vertice intercalate con glDrawElements utilizzando un singolo VAO e uno o più VBOs.

Per rispondere alla seconda parte della domanda, è possibile avere diversi VAO e VBO per diverse parti della mesh (quindi disegnare parti separate è semplice) oppure è possibile fondere tutto in una coppia VBO VAO (quindi è necessario non chiamare glBind*() spesso) e utilizzare più chiamate glDraw*() per disegnare singole parti della mesh (come si vede nel codice sopra - immagina il primo glDrawElements() disegna la nave e il secondo disegna la torretta, basta aggiornare una matrice uniforme tra le chiamate).

Poiché gli shader possono contenere più matrici di modelview in uniformi, è anche possibile codificare ID di reticolo come un altro attributo di vertice e consentire al vertex shader di scegliere quale matrice utilizzare per trasformare il vertice, in base a questo attributo. Questa idea può anche essere estesa all'utilizzo di più matrici per un singolo vertice, con alcuni pesi assegnati per ciascuna matrice. Questo è comunemente usato quando si animano oggetti organici come il personaggio del giocatore (cercare "skinning").

Come oggetti buffer uniformi, l'unico vantaggio è che è possibile comprimere un sacco di dati al loro interno e che possono essere facilmente condivisi tra gli shader (basta associare l'UBO a qualsiasi shader che sia in grado di utilizzarlo). Non vi è alcun vantaggio reale nell'usarli per te, eccetto se si dovessero avere oggetti con 1OOO di matrici.

Inoltre, ho scritto i codici sorgente sopra dalla memoria. Fatemi sapere se ci sono alcuni errori/problemi ...

+0

fredda penso lo capisco con l'interleaving, devo provarlo. Ma penso che tu abbia commesso un errore, tanto per essere sicuro, nel disimpegnare il primo glVertexAttribPointer per le posizioni dei vertici, poiché ho capito che le posizioni dei vertici sono strettamente racchiuse in vbo [0] eppure hai dato un passo? Il passo non dovrebbe essere zero per le posizioni poiché non sono interfogliati. – CodeMonkey

+0

Mi piace l'idea dell'ID mesh nello shader e lo passiamo come attributo, ma come faccio a fare l'analisi in molte matrici nello shader (come un array uniforme)? E 'questo il punto in cui posso usare le UBO per passare in forse 10 diverse matrici di trasformazione per 10 diverse torrette e usare un indice analizzato come attributo per cercare la matrice corretta all'interno dello shader? Questo mi permetterebbe anche di usare le funzioni glMultiDrawElements/Arrays disegnando un'intera nave con più parti tutte in una volta sola? – CodeMonkey

+0

Ciao, buona osservazione con il passo. Ma non è un errore. O potrei lasciare il passo 0 e OpenGL saprebbe (dal secondo e terzo argomento) che ho flusso di 3D GL_FLOATS (e quindi la dimensione è 3 * sizeof (float)), o posso calcolare il passo per esso. Non c'è niente di sbagliato in questo. Per chiarire ulteriormente - la falcata è la distanza tra gli indirizzi di due vertici consecutivi, NON è lo spazio tra loro (quindi 0 non significa che non ci sono byte inutilizzati tra i vertici, significa che OpenGL dovrebbe calcolare il passo reale dal numero di dimensioni e tipo di dati utilizzati). –

0

@theswine

non vincolante questo durante l'inizializzazione VAO provoca il mio programma di crash, ma legandolo dopo il legame del VAO induce a funzionare correttamente. Sei sicuro che questo non è stato salvato nel VAO?

glBindBuffer(GL_ARRAY_BUFFER, vbo[0]); // not saved in VAO 

(BTW: dispiace per allevare un vecchio argomento, ho pensato che questo potrebbe essere utile per gli altri, questo post è stato sicuro (che mi ricorda, grazie !!))

+0

Ciao. L'ho appena visto per sbaglio, dato che gli utenti non vengono avvisati quando si pubblica una risposta, iniziando con '@ login' (solo l'OP ne viene informato). Avresti dovuto lasciare un commento nella mia risposta, sarei stato informato di ciò. Ti suggerisco di iniziare una nuova domanda e pubblicare un codice minimale che riproduca il tuo crash. Sarebbe possibile? Quindi puoi lasciare un commento '@ login' sotto questo commento e cercherò il tuo problema. –

+0

Mi dispiace, non ho potuto commentare il tuo post a causa della mia mancanza di reputazione. Ma provate a gettare qualcosa per il check-out (forse è solo il mio hardware?) – luveti

+0

Di solito è solo un indice scambiato o un binding ingarbugliato. Succede al meglio. A volte, il buffer di array di elementi (indice) crea problemi, specialmente sulle schede grafiche Intel. –