Cosa sono gli oggetti array Vertex?


114

Sto solo iniziando a imparare OpenGL oggi da questo tutorial: http://openglbook.com/the-book/
Sono arrivato al capitolo 2, dove disegno un triangolo, e capisco tutto tranne VAO (è questo acronimo OK?). Il tutorial ha questo codice:

glGenVertexArrays(1, &VaoId);
glBindVertexArray(VaoId);

Pur comprendendo che il codice è necessario, non ho idea di cosa faccia. Anche se non uso mai VaoId oltre questo punto (tranne che per distruggerlo), il codice non funziona senza di esso. Suppongo che ciò sia dovuto al fatto che è necessario essere vincolato, ma non so perché. Questo codice esatto deve solo far parte di ogni programma OpenGL? Il tutorial spiega i VAO come:

Un Vertex Array Object (o VAO) è un oggetto che descrive il modo in cui gli attributi dei vertici vengono memorizzati in un Vertex Buffer Object (o VBO). Ciò significa che il VAO non è l'oggetto effettivo che memorizza i dati del vertice, ma il descrittore dei dati del vertice. Gli attributi dei vertici possono essere descritti dalla funzione glVertexAttribPointer e dalle sue due funzioni sorelle glVertexAttribIPointer e glVertexAttribLPointer, la prima delle quali esploreremo di seguito.

Non capisco come il VAO descrive gli attributi dei vertici. Non li ho descritti in alcun modo. Ottiene le informazioni dal glVertexAttribPointer? Immagino debba essere questo. Il VAO è semplicemente una destinazione per le informazioni di glVertexAttribPointer?

In una nota a margine, il tutorial che sto seguendo è accettabile? C'è qualcosa a cui dovrei prestare attenzione o un tutorial migliore da seguire?

Risposte:


100

"Vertex Array Object" viene fornito dal sottocomitato OpenGL ARB per i nomi sciocchi.

Pensalo come un oggetto geometrico. (Come programmatore SGI Performer dei vecchi tempi, li chiamo geoset.) Le variabili di istanza / membri dell'oggetto sono il puntatore al vertice, il puntatore normale, il puntatore colore, il puntatore attrib N, ...

Quando un VAO viene associato per la prima volta, si assegnano questi membri chiamando

glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer...;
glEnableClientState(GL_NORMAL_ARRAY); glNormalPointer...;

e così via. Quali attributi sono abilitati e i puntatori forniti vengono memorizzati nel VAO.

Dopodiché, quando si associa nuovamente il VAO, anche tutti quegli attributi e puntatori diventano attuali. Quindi una glBindVertexArraychiamata è equivalente a tutto il codice precedentemente necessario per impostare tutti gli attributi. È utile per passare la geometria tra funzioni o metodi senza dover creare le proprie strutture o oggetti.

(Una configurazione singola, l'uso multiplo è il modo più semplice per utilizzare i VAO, ma puoi anche modificare gli attributi semplicemente collegandoli ed eseguendo più chiamate di abilitazione / puntatore. I VAO non sono costanti.)

Maggiori informazioni in risposta alle domande di Patrick:

L'impostazione predefinita per un VAO appena creato è che è vuoto (AFAIK). Nessuna geometria, nemmeno i vertici, quindi se provi a disegnarla, otterrai un errore OpenGL. Questo è ragionevolmente sano, come in "inizializza tutto su False / NULL / zero".

Hai solo bisogno di glEnableClientStatequando imposti le cose. Il VAO ricorda lo stato di abilitazione / disabilitazione per ogni puntatore.

Sì, il VAO memorizzerà glEnableVertexAttribArraye glVertexAttrib. I vecchi array di vertici, normali, color, ... sono gli stessi degli array di attributi, vertice == # 0 e così via.


62
"" Vertex Array Object "viene fornito dal sottocomitato OpenGL ARB per i nomi sciocchi." Sì, un nome così sciocco per un oggetto che memorizza i binding di array di vertici .
Nicol Bolas

2
Inoltre, i VAO sono affatto legati aglVertexAttribPointer
Patrick

2
Si prega di aggiungere alcune informazioni sull'uso di attributi vertici generici per le persone che utilizzano il profilo principale.
Oskar

8
@NicolBolas Un nome migliore sarebbe VertexArrayMacroo qualcosa di simile.
bobobobo

7
@NicolBolas "Vertex Array Object" è un nome orribile. Si tratta di legare i dati agli attributi . Non si tratta di array di vertici, come suggerisce il nome. Non vi è alcun riferimento a vincoli o attributi nel nome e poiché "array di vertici" è di per sé un concetto separato, rende la comprensione ancora più difficile. IMHO, "(Vertex) Attributes Binding Object" è più facile da capire. Anche Geometry Object è migliore: non mi piace, ma almeno non è sovraccarico.
AkiRoss

8

Gli oggetti array Vertex sono come le macro nei programmi di elaborazione testi e simili. Una buona descrizione si trova qui .

Le macro si limitano a ricordare le azioni che hai fatto, come attivare questo attributo, collegare quel buffer, ecc. Quando chiami glBindVertexArray( yourVAOId ), riproduce semplicemente quei binding del puntatore dell'attributo e del buffer.

Quindi la tua prossima chiamata per disegnare usa tutto ciò che era vincolato dal VAO.

I VAO non memorizzano i dati dei vertici . No. I dati dei vertici vengono memorizzati in un buffer dei vertici o in un array di memoria del client.


19
-1: non sono come le macro. Se lo fossero, l'associazione di un nuovo VAO non disabiliterebbe gli array di vertici abilitati da un VAO precedente, a meno che il nuovo VAO non abbia "registrato" esplicitamente la disabilitazione di tali array. I VAO, come tutti gli oggetti OpenGL, mantengono lo stato , non i comandi. I comandi cambiano semplicemente lo stato, ma gli oggetti vengono forniti con lo stato predefinito impostato. Ecco perché l'associazione di un VAO appena creato disabiliterà sempre tutti gli attributi.
Nicol Bolas

6

Penso sempre a VAO come a una serie di buffer di dati utilizzati da OpenGL. Usando il moderno OpenGL creerai un VAO e Vertex Buffer Objects.

inserisci qui la descrizione dell'immagine

//vaoB is a buffer
glGenVertexArrays(1, vaoB); //creates one VAO
glBindVertexArray(vao.get(0));
glGenBuffers(vbo.length, vbo, 0); //vbo is a buffer
glBindVertexArray(vao.get(1));
glGenBuffers(vbo1.length, vbo1, 0); //vbo1 is a buffer
glBindVertexArray(vao.get(2));
glGenBuffers(vbo2.length, vbo2, 0); //vbo2 is a buffer

Il passaggio successivo è associare i dati a un buffer:

glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
glBufferData(GL_ARRAY_BUFFER,vertBuf.limit()*4, vertBuf, GL_STATIC_DRAW); //vertf buf is a floatbuffer of vertices

A questo punto OpenGL vede:

inserisci qui la descrizione dell'immagine

Ora possiamo usare glVertexAttribPointer per dire a OpenGL cosa rappresentano i dati nel buffer:

glBindBuffer(GL_ARRAY_BUFFER, 0); //bind VBO at 0
glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0); //each vertex has 3 components of size GL_FLOAT with 0 stride (space) between them and the first component starts at 0 (start of data)

inserisci qui la descrizione dell'immagine

OpenGL ora ha i dati nel buffer e sa come i dati sono organizzati in vertici. Lo stesso processo può essere applicato alle coordinate della trama ecc. Ma per le coordinate della trama ci sarebbero due valori.

glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
glBufferData(GL_ARRAY_BUFFER,coordBuf.limit()*4, coordBuf, GL_STATIC_DRAW);
glVertexAttribPointer(0, 2, GL_FLOAT, false, 0, 0);

Successivamente puoi legare texture e disegnare array, vorrai creare uno shader Vert e Frag, compilarlo e collegarlo a un programma (non incluso qui).

glActiveTexture(textureID); //bind our texture
glBindTexture(GL_TEXTURE_2D, textureID);
glDrawArrays(GL_TRIANGLES,0,6); //in this case 6 indices are used for two triangles forming a square

5

VAO è un oggetto che rappresenta la fase di recupero del vertice della pipeline OpenGL e viene utilizzato per fornire input al vertex shader.

Puoi creare un oggetto array di vertici in questo modo

GLuint vao;
glCreateVertexArrays(1, &vao);
glBindVertexArray(vao);

Per prima cosa facciamo un semplice esempio. Considera un parametro di input di questo tipo in un codice shader

layout (location = 0) in vec4 offset; // input vertex attribute

Per compilare questo attributo possiamo usare

glVertexAttrib4fv(0, attrib); // updates the value of input attribute 0

Sebbene l'oggetto della matrice dei vertici memorizzi questi valori degli attributi statici, può fare molto di più.

Dopo aver creato l'oggetto array di vertici, possiamo iniziare a riempire il suo stato. Chiederemo a OpenGL di riempirlo automaticamente utilizzando i dati memorizzati in un oggetto buffer che forniamo. Ogni attributo di vertice ottiene i dati da un buffer associato a uno dei numerosi collegamenti di buffer di vertice. A tal fine usiamo glVertexArrayAttribBinding(GLuint vao, GLuint attribindex, GLuint bindingindex). Inoltre usiamo la glVertexArrayVertexBuffer()funzione per associare un buffer a uno dei vincoli del buffer del vertice. Usiamo la glVertexArrayAttribFormat()funzione per descrivere il layout e il formato dei dati e infine abilitiamo il riempimento automatico dell'attributo chiamando glEnableVertexAttribArray().

Quando un attributo di vertice è abilitato, OpenGL invierà i dati al vertex shader in base alle informazioni sul formato e sulla posizione che hai fornito glVertexArrayVertexBuffer()e glVertexArrayAttribFormat(). Quando l'attributo è disabilitato, al vertex shader verranno fornite le informazioni statiche a cui fornisci una chiamata glVertexAttrib*().

// First, bind a vertex buffer to the VAO
glVertexArrayVertexBuffer(vao, 0, buffer, 0, sizeof(vmath::vec4));

// Now, describe the data to OpenGL, tell it where it is, and turn on automatic
// vertex fetching for the specified attribute
glVertexArrayAttribFormat(vao, 0, 4, GL_FLOAT, GL_FALSE, 0);

glEnableVertexArrayAttrib(vao, 0);

E codifica in uno shader

layout (location = 0) in vec4 position;

Dopo tutto quello che devi chiamare glDeleteVertexArrays(1, &vao).


Puoi leggere OpenGL SuperBible per capirlo meglio.


3
È bello vedere persone che promuovono l'uso di OpenGL in stile DSA.
Nicol Bolas
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.