OpenGL: è possibile utilizzare VAO senza specificare un VBO


12

In tutti i tutorial che posso trovare su VAO (Vertex Array Objects), mostrano come usarli configurando gli attributi dei vertici e associando un VBO (Vertex Buffer Object). Ma voglio creare un VAO che verrà configurato per un set di VBO in combinazione con uno shader fisso, in cui ogni buffer utilizza lo stesso modello di dati (vertice, uv, colore, ecc.). Quindi, voglio creare un VAO per più VBO che verranno disegnati usando uno shader.

Non ho trovato alcuna demo su questo, quindi ho deciso di provarlo. Ma non funziona e si blocca durante la glDrawArraychiamata. Sembra che il VBO non sia vincolato. Ecco il codice che sto usando:

Rendering:

/* Prepare vertex attributes */
glBindVertexArrayOES(vao);

/* Upload the buffer to the GPU */
glBindBuffer(GL_ARRAY_BUFFER, pool->next());
glBufferSubData(GL_ARRAY_BUFFER, 0, parts * buffer.stride() * 6, buffer.getBuffer());

/* Draw the triangles */
glDrawArrays(GL_TRIANGLES, 0, parts * 6);

glBindVertexArrayOES(0);

Creazione VAO:

glBindVertexArrayOES(vao);

glEnableVertexAttribArray(ls.position);
glVertexAttribPointer(ls.position, 2, GL_FLOAT, GL_FALSE, buffer.stride(), 0);

glEnableVertexAttribArray(ls.color);
glVertexAttribPointer(ls.color, 3, GL_FLOAT, GL_FALSE, buffer.stride(), GL_BUFFER_OFFSET(buffer.dataTypeSize * 2));

glBindVertexArrayOES(0);

Dov'è lsun semplice structche contiene le posizioni degli attributi.

Nella parte Rendering, anche lo scambio di glBindBuffere glBindVertexArrayOESdintorni non ha funzionato.

Quindi, la domanda è: è anche possibile farlo, o dovrò creare un VAO per ciascun buffer? E se devo creare un VAO per ciascun VBO, è possibile aggiornare i dati del VBO utilizzando glBufferSubDatain combinazione con un VAO?

Risposte:


18

I VAO non contengono lo stato "glBindBuffer", ad eccezione dello GL_ELEMENT_ARRAY_BUFFERstato di associazione di. Quello che non capisci è che glBindBuffer(GL_ARRAY_BUFFER) non fa nulla . Bene, non fa nulla per quanto riguarda il rendering. Provalo; prima di chiamare glDraw *, chiama glBindBuffer(GL_ARRAY_BUFFER, 0); il tuo rendering funzionerà bene.

Il modo in cui glVertexAttribPointerfunziona è che guarda ciò che è legato a GL_ARRAY_BUFFER al momento in cui glVertexAttribPointerviene chiamato . Non al momento del rendering. Non più tardi. Proprio in quel preciso momento. Prende qualsiasi oggetto buffer presente e lo memorizza in un altro pezzo di stato OpenGL, incapsulato all'interno del VAO.

In generale, hai due opzioni, una delle quali è nuova e probabilmente non dovrebbe essere utilizzata in questo momento.

La tua prima opzione è di mettere tutti gli oggetti che usano lo stesso formato di vertice (cioè: tutto tranne l'oggetto buffer e offset) nello stesso oggetto buffer. Fondamentalmente, crea un array gigante che contenga tutti i vertici per tutti gli oggetti che usano lo stesso formato.

Quando arriva il momento di eseguire il rendering, è possibile eseguire il rendering di una parte dei vertici. glDrawArraysrichiede una serie di elementi per il rendering e puoi regolare i tuoi indici glDrawElementsper fare lo stesso. In alternativa, è possibile utilizzare glDrawElementsBaseVertexper inclinare i vertici , in modo che un offset sia aggiunto a ciascun indice. Questo offset è il numero di vertici prima di quel vertice nella matrice grande.

L'altra alternativa è quella di utilizzare il relativamente nuovo sistema di separazione degli attributi di formato aggiunto in GL 4.3. Ti consentirebbe di modificare i buffer senza ripristinare il formato. In questo modo assoceresti un singolo VAO, quindi sostituiscilo in buffer diversi secondo necessità glBindVertexBuffer. Questo è disponibile anche in ES 3.1.


1
I driver NV GL4.3 sono ora in versione completa.
Maximus Minimus

Grazie mille per aver spiegato come funziona glVertexAttribPointer. Ciò è stato illuminante e spiega perché e come funziona.
Martijn Courteaux,

5

Il VAO memorizza lo stato glVertexAttribPointer. La modifica del VAO non influisce sul glBindBuffer corrente, né la modifica del glBindBuffer influisce sul VAO. Solo la chiamata glVertexAttribPointer influisce sul VAO, registrando il buffer in uso durante la chiamata.

Quindi la risposta alla tua domanda è no.

Un'opzione se si desidera ridurre il numero di oggetti è inserire tutti i dati mesh in un VBO di grandi dimensioni e specificare dove risiedono i dati mesh nel VBO nella chiamata glDrawArrays usando gli argomenti 'first' e 'count'.


Tutti gli articoli su Internet di VAO mostrano che l'associazione di un VAO vincola automaticamente il VBO. Quindi, penso che un VAO sia una configurazione che contiene sia gli stati glVertexAttribPointer che lo stato glBindBuffer . E sì, l'associazione di un VBO quando un VAO è associato cambia il VAO. Lo dico perché l'ho provato e lo fa efficacemente. Da dove provengono queste informazioni?
Martijn Courteaux,

2
@MartijnCourteaux: " Tutti gli articoli su Internet di VAO mostrano che l'associazione di un VAO vincola automaticamente il VBO. " No, non lo fanno. La specifica OpenGL Wiki on vertex no. In effetti, mostrami un singolo articolo su Internet in cui si afferma che qualsiasi glBindBufferstato tranne GL_ELEMENT_ARRAY_BUFFER viene modificato vincolando un VAO.
Nicol Bolas,

L'altra risposta ha spiegato bene come funziona il metodo glVertexAttribPointer. Usa il VBO associato in quel momento. Hai ragione! Grazie, ho capito adesso.
Martijn Courteaux,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.