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 Objecto VAO, di cui parlerò più avanti
- A
Buffer Object, comunemente indicato come a Vertex Buffer Objectquando si memorizzano i vertici, o VBO in breve, è ciò che stai chiamando solo a Buffer.
- Niente viene salvato nell'array dei vertici,
glVertexAttribPointerfunziona esattamente come glVertexPointero glTexCoordPointerfunziona, 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 glVertexAttribPointerchiamate vengono messe in coda per la prossima volta che chiami glDrawArrayso 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_FALSEsignifica 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 glVertexAttribPointerchiamata 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 glVertexAttribPointerchiamate 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 Objecto VAO viene utilizzato per memorizzare lo stato di tutte le glVertexAttribPointerchiamate e dei VBO targetizzati quando ciascuna delle glVertexAttribPointerchiamate è 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 glVertexAttribPointerchiamate, devi solo associare il VAO con glBindVertexArraypoi chiama glDrawArrayso glDrawElementse 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.