OpenGL: est-il possible d'utiliser des VAO sans spécifier de VBO

12

Sur tous les tutoriels que je peux trouver sur les objets VAO (Vertex Array Objects), ils montrent comment les utiliser en configurant les attributs de vertex et en liant un VBO (Vertex Buffer Object). Mais je veux créer un VAO qui sera configuré pour un ensemble de VBO en combinaison avec un shader fixe, où chaque tampon utilise le même modèle de données (vertex, uv, color, etc.). Donc, je veux créer un VAO pour plusieurs VBO qui seront dessinés en utilisant un shader.

Je n'ai trouvé aucune démo à ce sujet, j'ai donc décidé de l'essayer. Mais cela ne fonctionne pas et se bloque à l' glDrawArrayappel. Il semble que le VBO ne soit pas lié. Voici le code que j'utilise:

Le rendu:

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

Création 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);

lsest un simple structqui contient les emplacements des attributs.

Dans la partie Rendu, l'échange de glBindBufferet glBindVertexArrayOESautour n'a pas fonctionné non plus.

Donc, la question est: est-il même possible de le faire, ou devrai-je créer pour chaque tampon un VAO? Et si je dois créer un VAO pour chaque VBO, est-il possible de mettre à jour les données du VBO en utilisant glBufferSubDataen combinaison avec un VAO?

Martijn Courteaux
la source

Réponses:

18

Les VAO ne contiennent pas l'état "glBindBuffer", à l'exception de GL_ELEMENT_ARRAY_BUFFERl'état de liaison de. Ce que vous ne comprenez pas, c'est que glBindBuffer(GL_ARRAY_BUFFER) cela ne fait rien . Eh bien, cela ne fait rien en ce qui concerne le rendu. Essayez-le; juste avant d'appeler glDraw *, appelez glBindBuffer(GL_ARRAY_BUFFER, 0); votre rendu fonctionnera très bien.

La façon dont glVertexAttribPointerfonctionne est qu'il examine ce qui est lié à GL_ARRAY_BUFFER au moment où il glVertexAttribPointerest appelé . Pas au moment du rendu. Pas plus tard. À ce moment précis. Il prend tout objet tampon qui s'y trouvait et le stocke dans un autre morceau d'état OpenGL, qui est encapsulé dans le VAO.

En général, vous avez deux options, l'une d'elles est nouvelle et ne devrait probablement pas être utilisée à ce stade.

Votre première option consiste à placer tous les objets qui utilisent le même format de sommet (c'est-à-dire tout sauf l'objet tampon et le décalage) dans le même objet tampon. Fondamentalement, créez un tableau géant qui contient tous les sommets pour tous les objets qui utilisent le même format.

Quand vient le temps de rendre, vous pouvez rendre une partie des sommets. glDrawArraysprend une série d'éléments à rendre, et vous pouvez ajuster vos indices glDrawElementspour faire de même. Vous pouvez également utiliser glDrawElementsBaseVertexpour biaiser les sommets , de sorte qu'un décalage soit ajouté à chaque index. Ce décalage est le nombre de sommets avant ce sommet dans le grand tableau.

L'autre alternative consiste à utiliser le système de séparation des attributs de format relativement nouveau ajouté dans GL 4.3. Cela vous permettrait de modifier les tampons sans réinitialiser le format. Ainsi, vous lieriez un seul VAO, puis vous le remplaceriez simplement par différents tampons selon vos besoins glBindVertexBuffer. Ceci est également disponible dans ES 3.1.

Nicol Bolas
la source
1
Les pilotes NV GL4.3 sont maintenant disponibles en version complète.
Maximus Minimus
Merci beaucoup d'avoir expliqué le fonctionnement de glVertexAttribPointer. C'était instructif et explique pourquoi et comment cela fonctionne.
Martijn Courteaux
5

Le VAO stocke l'état glVertexAttribPointer. Changer le VAO n'affecte pas le glBindBuffer actuel, ni changer le glBindBuffer n'affecte le VAO. Seul l'appel glVertexAttribPointer affecte le VAO, en enregistrant le tampon utilisé lors de l'appel.

La réponse à votre question est donc non.

Une option si vous souhaitez réduire le nombre d'objets consiste à placer toutes vos données de maillage dans un grand VBO et à spécifier où les données de maillage résident dans le VBO dans l'appel glDrawArrays en utilisant les arguments `` premier '' et `` nombre ''.

ccxvii
la source
Tous les articles sur Internet sur VAO montrent que la liaison d'un VAO lie automatiquement le VBO. Donc, je pense qu'un VAO est une configuration qui contient à la fois les états glVertexAttribPointer et l' état glBindBuffer . Et oui, lier un VBO quand un VAO est lié change le VAO. Je dis cela parce que je l'ai testé et que cela fonctionne effectivement. D'où proviennent ces informations?
Martijn Courteaux
2
@MartijnCourteaux: " Tous les articles sur Internet sur VAO montrent que lier un VAO lie automatiquement le VBO. " Non, ils ne le font pas. La spécification OpenGL Wiki on vertex ne fonctionne pas. En effet, montrez-moi un seul article sur Internet qui dit que tout glBindBufferétat sauf GL_ELEMENT_ARRAY_BUFFER est modifié en liant un VAO.
Nicol Bolas
L'autre réponse expliquait bien le fonctionnement de la méthode glVertexAttribPointer. Il utilise le VBO lié à ce moment-là. Tu as raison! Merci, je comprends tout de suite.
Martijn Courteaux