Parte della terminologia è un po 'fuori luogo:
- A
Vertex Array
è solo un array (tipicamente a float[]
) che contiene i dati dei vertici. Non ha bisogno di essere legato a nulla. Da non confondere con a Vertex Array Object
o VAO, di cui parlerò più avanti
- A
Buffer Object
, comunemente indicato come a Vertex Buffer Object
quando si memorizzano i vertici, o VBO in breve, è ciò che stai chiamando solo a Buffer
.
- Niente viene salvato nell'array dei vertici,
glVertexAttribPointer
funziona esattamente come glVertexPointer
o glTexCoordPointer
funziona, solo che al posto degli attributi denominati, puoi fornire un numero che specifica il tuo attributo. Si passa questo valore come index
. Tutte le tue glVertexAttribPointer
chiamate vengono messe in coda per la prossima volta che chiami glDrawArrays
o glDrawElements
. Se si dispone di un limite VAO, il VAO memorizzerà le impostazioni per tutti gli attributi.
Il problema principale qui è che stai confondendo gli attributi dei vertici con i VAO. Gli attributi dei vertici sono solo il nuovo modo di definire vertici, texcoords, normali, ecc. Per il disegno. Stato del negozio VAO. Per prima cosa spiegherò come funziona il disegno con gli attributi dei vertici, quindi spiegherò come ridurre il numero di chiamate al metodo con i VAO:
- È necessario abilitare un attributo prima di poterlo utilizzare in uno shader. Ad esempio, se vuoi inviare vertici a uno shader, molto probabilmente lo invierai come primo attributo, 0. Quindi, prima di renderizzare, devi abilitarlo con
glEnableVertexAttribArray(0);
.
- Ora che un attributo è abilitato, è necessario definire i dati che utilizzerà. Per fare ciò devi associare il tuo VBO -
glBindBuffer(GL_ARRAY_BUFFER, myBuffer);
.
- E ora possiamo definire l'attributo -
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
. In ordine di parametro: 0 è l'attributo che stai definendo, 3 è la dimensione di ogni vertice, GL_FLOAT
è il tipo, GL_FALSE
significa non normalizzare ogni vertice, gli ultimi 2 zeri significano che non c'è passo o offset sui vertici.
- Disegna qualcosa con esso -
glDrawArrays(GL_TRIANGLES, 0, 6);
- La prossima cosa che disegni potrebbe non usare l'attributo 0 (realisticamente lo farà, ma questo è un esempio), quindi possiamo disabilitarlo -
glDisableVertexAttribArray(0);
Avvolgilo nelle glUseProgram()
chiamate e avrai un sistema di rendering che funziona correttamente con gli shader. Ma diciamo che hai 5 diversi attributi, vertici, texcoords, normali, colore e coordinate lightmap. Prima di tutto, faresti una singola glVertexAttribPointer
chiamata per ciascuno di questi attributi e dovresti abilitare tutti gli attributi in anticipo. Supponiamo che tu definisca gli attributi 0-4 come li ho elencati. Abilitali tutti in questo modo:
for (int i = 0; i < 5; i++)
glEnableVertexAttribArray(i);
E poi dovresti associare diversi VBO per ogni attributo (a meno che non li memorizzi tutti in un VBO e usi offset / falcata), quindi devi effettuare 5 glVertexAttribPointer
chiamate diverse , rispettivamente da glVertexAttribPointer(0,...);
a glVertexAttribPointer(4,...);
per vertici a coordinate lightmap.
Si spera che quel sistema da solo abbia un senso. Ora passerò ai VAO per spiegare come usarli per ridurre il numero di chiamate al metodo quando si esegue questo tipo di rendering. Notare che l'utilizzo di un VAO non è necessario.
A Vertex Array Object
o VAO viene utilizzato per memorizzare lo stato di tutte le glVertexAttribPointer
chiamate e dei VBO targetizzati quando ciascuna delle glVertexAttribPointer
chiamate è stata effettuata.
Ne generi uno con una chiamata a glGenVertexArrays
. Per memorizzare tutto ciò di cui hai bisogno in un VAO, collegalo con glBindVertexArray
, quindi fai un full draw call . Tutte le chiamate di pareggio vengono intercettate e archiviate dal VAO. Puoi svincolare il VAO conglBindVertexArray(0);
Ora, quando vuoi disegnare l'oggetto, non hai bisogno di richiamare tutti i binding VBO o le glVertexAttribPointer
chiamate, devi solo associare il VAO con glBindVertexArray
poi chiama glDrawArrays
o glDrawElements
e disegnerai esattamente la stessa cosa come se tu stavano facendo tutte quelle chiamate di metodo. Probabilmente in seguito vorrai anche svincolare il VAO.
Una volta svincolato il VAO, tutto lo stato torna a com'era prima di vincolare il VAO. Non sono sicuro che le modifiche apportate mentre il VAO è associato vengano mantenute, ma ciò può essere facilmente capito con un programma di prova. Immagino che tu possa pensare a glBindVertexArray(0);
come vincolante al VAO "predefinito" ...
Aggiornamento: qualcuno ha portato alla mia attenzione la necessità dell'effettiva chiamata al sorteggio. A quanto pare, in realtà non è necessario eseguire una chiamata FULL draw quando si imposta il VAO, ma solo tutte le cose vincolanti. Non so perché prima pensavo fosse necessario, ma ora è stato risolto.