web-dev-qa-db-fra.com

Que sont les objets Vertex Array?

Je commence tout juste à apprendre OpenGL aujourd'hui à partir de ce tutoriel: http://openglbook.com/the-book/
Je suis arrivé au chapitre 2, où je dessine un triangle et je comprends tout sauf les VAO (cet acronyme est-il correct?). Le tutoriel a ce code:

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

Bien que je comprenne que le code est nécessaire, je n’ai aucune idée de ce qu’il fait. Bien que je n’utilise jamais VaoId après ce point (sauf pour le détruire), le code ne fonctionne pas sans lui. Je suppose que c'est parce qu'il faut être lié, mais je ne sais pas pourquoi. Ce code exact doit-il simplement faire partie de chaque programme OpenGL? Le tutoriel explique les VAO en tant que:

Un objet Vertex Array (ou VAO) est un objet qui décrit comment les attributs de sommet sont stockés dans un objet Vertex Buffer Object (ou VBO). Cela signifie que le VAO n'est pas l'objet réel stockant les données de sommet, mais le descripteur des données de sommet. Les attributs de sommet peuvent être décrits par la fonction glVertexAttribPointer et ses deux fonctions sœurs, glVertexAttribIPointer et glVertexAttribLPointer, la première de celles-ci.

Je ne comprends pas comment le VAO décrit les attributs de sommet. Je ne les ai décrites d'aucune façon. Obtient-il les informations du glVertexAttribPointer? Je suppose que ça doit être ça. Le VAO est-il simplement une destination pour les informations de glVertexAttribPointer?

Le tutoriel que je suis est-il acceptable? Y a-t-il quelque chose que je devrais surveiller ou un meilleur tutoriel à suivre?

96
Patrick

"Vertex Array Object" vous est proposé par le sous-comité OpenGL ARB pour les noms idiots.

Pensez-y comme un objet de géométrie. (En tant qu'ancien programmeur SGI Performer, je les appelle des géosets.) Les variables d'instance/membres de l'objet sont votre pointeur de sommet, votre pointeur normal, votre pointeur de couleur, le pointeur attribut N, ...

Quand un VAO est lié pour la première fois, vous affectez ces membres en appelant

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

etc. Les attributs activés et les pointeurs que vous fournissez sont stockés dans le VAO.

Ensuite, lorsque vous liez de nouveau le VAO, tous ces attributs et pointeurs deviennent également courants. Donc, un appel glBindVertexArray équivaut à tout le code nécessaire auparavant pour configurer tous les attributs. C'est pratique pour passer de la géométrie entre des fonctions ou des méthodes sans avoir à créer vos propres structures ou objets.

(Une configuration unique, l’utilisation multiple est le moyen le plus simple d’utiliser des VAO, mais vous pouvez également modifier des attributs simplement en le liant et en effectuant davantage d’appels d’activation/pointeur. Les VAO ne sont pas des constantes.)

Plus d'infos en réponse aux questions de Patrick:

La valeur par défaut pour un VAO nouvellement créé est qu'il est vide (autant que je sache). Aucune géométrie du tout, pas même les sommets, donc si vous essayez de la dessiner, vous obtiendrez une erreur OpenGL. Ceci est raisonnablement sain, comme dans "tout initialiser à False/NULL/zéro".

Vous n'avez besoin que de glEnableClientState lorsque vous configurez les choses. Le VAO garde en mémoire l'état d'activation/désactivation de chaque pointeur.

Oui, le VAO stockera glEnableVertexAttribArray et glVertexAttrib. Les anciens tableaux vertex, normal, color, ... sont identiques aux tableaux d'attributs, vertex == # 0, etc.

88
Hugh

Vertex Array Les objets ressemblent à des macros dans les programmes de traitement de texte, etc. Une bonne description est trouvée ici .

Les macros just rappelez-vous les actions que vous avez effectuées, telles qu'activer cet attribut, lier ce tampon, etc. Lorsque vous appelez glBindVertexArray( yourVAOId ), il vous suffit rejoue ces liaisons de pointeur d'attribut et de tampon.

Donc, votre prochain appel à dessiner utilise tout ce qui était lié par le VAO.

Les VAO ne stockent pas données de sommet. Les données de sommet sont stockées dans un sommet tampon ou dans un tableau de la mémoire client.

7
bobobobo

VAO est un objet qui représente l'étape d'extraction de vertex du pipeline OpenGL et est utilisé pour fournir une entrée au vertex shader.

Vous pouvez créer un objet tableau de sommets comme ceci

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

D'abord, faisons un exemple simple. Considérons un tel paramètre d'entrée dans un code de shader

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

Pour renseigner cet attribut, nous pouvons utiliser

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

Bien que l'objet tableau de sommets stocke ces valeurs d'attributs statiques pour vous, il peut en faire beaucoup plus.

Après avoir créé un objet tableau de sommets, nous pouvons commencer à renseigner son état. Nous demanderons à OpenGL de le remplir automatiquement en utilisant les données stockées dans un objet tampon fourni. Chaque attribut de sommet doit extraire les données d'un tampon lié à l'une des liaisons de tampon de vertex. Pour cela, nous utilisons glVertexArrayAttribBinding(GLuint vao, GLuint attribindex, GLuint bindingindex). Nous utilisons également la fonction glVertexArrayVertexBuffer() pour lier un tampon à l’une des liaisons de tampon de sommets. Nous utilisons la fonction glVertexArrayAttribFormat() pour décrire la présentation et le format des données. Enfin, nous activons le remplissage automatique de l'attribut en appelant glEnableVertexAttribArray().

Lorsqu'un attribut de sommet est activé, OpenGL fournira des données au vertex shader en fonction du format et des informations de localisation que vous avez fournis avec glVertexArrayVertexBuffer() et glVertexArrayAttribFormat(). Lorsque l'attribut est désactivé, le vertex shader reçoit les informations statiques que vous fournissez avec un appel à 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);

Et code dans un shader

layout (location = 0) in vec4 position;

Après tout, vous devez appeler glDeleteVertexArrays(1, &vao).


Vous pouvez lire OpenGL SuperBible pour mieux le comprendre.

5
Yola

Je pense toujours à VAO comme un tableau de tampons de données utilisés par OpenGL. En utilisant OpenGL moderne, vous créerez un VAO et des objets Vertex Buffer.

enter image description here

//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

L'étape suivante consiste à lier les données à un tampon:

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

À ce stade, OpenGL voit:

enter image description here

Nous pouvons maintenant utiliser glVertexAttribPointer pour indiquer à OpenGL ce que les données du tampon représentent:

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)

enter image description here

OpenGL a maintenant les données dans le tampon et sait comment les données sont organisées en sommets. Le même processus peut être appliqué aux coordonnées de texture, etc., mais pour les coordonnées de texture, il y aurait deux valeurs.

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);

Ensuite, vous pouvez lier une texture et dessiner des tableaux, vous voudrez créer un shader Vert et Frag, le compiler et l’attacher à un programme (non inclus ici).

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
1
vasmos