Quel est le rôle de glBindVertexArrays vs glBindBuffer et quelle est leur relation?

Je suis nouveau à OpenGL et la programmation graphique. J'ai lu un manuel qui a été vraiment complet et bien écrit jusqu'à présent.Cependant, j'ai atteint un point dans le code que je ne comprends pas tout à fait et j'aimerais donner un sens à ces lignes avant de passer à autre chose.

GLuint abuffer;

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

GLuint buffer;
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(points), points, GL_STATIC_DRAW);

Le livre explique que les trois premières lignes créent un objet vertex-array , qui est utilisé pour regrouper les données associées avec un tableau de vertex. La deuxième ligne trouve un nom inutilisé (je suis deviner un identifiant entier non signé stocké dans abuffer) et la troisième ligne crée l'objet / le rend actif.

Le livre explique que les 4ème-7ème lignes créent un objet tampon pour stocker nos données, avec la 5ème ligne nous donnant un identifiant inutilisé (similaire à la ligne 2 pour l'objet de tableau de vertex?), la 6ème ligne créant le tampon, et la 7ème ligne allouant suffisamment de mémoire sur le CPU et créant un pointeur vers nos données (points) pour GL_STATIC_DRAW.

Qu'est-ce que cela signifie pour que l'objet soit active? Quand utiliseriez-vous par la suite abuffer? Qu'est-ce que cela signifie pour un tableau de sommets de regrouper les données associées, et quand les données ont-elles été associées à cet objet de tableau de Sommets?

Je suis confus au sujet de la relation entre abuffer et buffer. Je suis confus quant à la relation du tableau de vertex avec l'objet tampon, et à quel point cette relation est formée. Je ne suis pas sûr qu'ils soient, en fait, liés, mais ils sont présentés dans le manuel immédiatement après l'autre.

Toute aide serait appréciée. Grâce.

60
demandé sur Vallentin 2014-02-09 02:25:41

5 réponses

D'un point de vue de bas niveau, vous pouvez penser à un tableau comme ayant deux parties:

  • Informations sur la taille, la forme et le type du tableau (par exemple, des nombres à virgule flottante 32 bits, contenant des lignes de vecteurs avec quatre éléments chacun).

  • Les données du tableau, qui n'est guère plus qu'un gros blob d'octets.

Même si le concept de bas niveau est resté le plus souvent le même, la façon dont vous spécifiez les tableaux a changé plusieurs fois an.

OpenGL 3.0 / ARB_vertex_array_object

C'est la façon dont vous probablement devrait faire les choses aujourd'hui. Il est très rare de trouver des gens qui ne peuvent pas exécuter OpenGL 3.x et pourtant encore de l'argent à dépenser sur votre logiciel.

Un objet tampon dans OpenGL est un gros blob de bits. Pensez au tampon "actif" comme une variable globale, et il y a un tas de fonctions qui utilisent le tampon actif au lieu d'utiliser un paramètre. Ces variables d'état sont le côté laid D'OpenGL (avant accès direct de l'état, qui est couvert ci-dessous).

GLuint buffer;

// Generate a name for a new buffer.
// e.g. buffer = 2
glGenBuffers(1, &buffer);

// Make the new buffer active, creating it if necessary.
// Kind of like:
// if (opengl->buffers[buffer] == null)
//     opengl->buffers[buffer] = new Buffer()
// opengl->current_array_buffer = opengl->buffers[buffer]
glBindBuffer(GL_ARRAY_BUFFER, buffer);

// Upload a bunch of data into the active array buffer
// Kind of like:
// opengl->current_array_buffer->data = new byte[sizeof(points)]
// memcpy(opengl->current_array_buffer->data, points, sizeof(points))
glBufferData(GL_ARRAY_BUFFER, sizeof(points), points, GL_STATIC_DRAW);

Maintenant, votre shader de vertex typique prend Vertex en entrée, pas un gros blob de bits. Vous devez donc spécifier comment le blob de bits (le tampon) est décodé en Sommets. C'est le travail de la matrice. De même, il existe un tableau "actif" que vous pouvez considérer comme une variable globale:

GLuint array;
// Generate a name for a new array.
glGenVertexArrays(1, &array);
// Make the new array active, creating it if necessary.
glBindVertexArray(array);

// Make the buffer the active array buffer.
glBindBuffer(GL_ARRAY_BUFFER, buffer);
// Attach the active buffer to the active array,
// as an array of vectors with 4 floats each.
// Kind of like:
// opengl->current_vertex_array->attributes[attr] = {
//     type = GL_FLOAT,
//     size = 4,
//     data = opengl->current_array_buffer
// }
glVertexAttribPointer(attr, 4, GL_FLOAT, GL_FALSE, 0, 0);
// Enable the vertex attribute
glEnableVertexAttribArray(attr);

OpenGL 2.0 (l'ancienne façon)

Dans OpenGL 2.x, il n'y avait pas de vertex tableaux et les données étaient juste globales. Vous deviez toujours appeler glVertexAttribPointer() et glEnableVertexAttribArray(), mais vous deviez les appeler chaque fois que vous utilisiez un tampon. Dans OpenGL 3.x, vous venez de configurer le tableau une fois.

Pour en revenir à OpenGL 1.5, vous pouvez réellement utiliser des tampons, mais vous avez utilisé une fonction distincte pour lier chaque type de données. Par exemple, glVertexPointer() était pour les données de sommet, et glNormalPointer() était pour les données normales. Avant OpenGL 1.5, il n'y avait pas de tampons, mais vous pouviez utiliser des pointeurs dans votre application mémoire.

OpenGL 4.3 / ARB_vertex_attrib_binding

Dans 4.3, ou si vous avez L'extension ARB_vertex_attrib_binding, vous pouvez spécifier le format d'attribut et les données d'attribut séparément. C'est bien car il vous permet de basculer facilement un tableau de Sommets entre différents tampons.

GLuint array;
// Generate a name for a new array array.
glGenVertexArrays(1, &array);
// Make the new array active, creating it if necessary.
glBindVertexArray(array);

// Enable my attributes
glEnableVertexAttribArray(loc_attrib);
glEnableVertexAttribArray(normal_attrib);
glEnableVertexAttribArray(texcoord_attrib);
// Set up the formats for my attributes
glVertexAttribFormat(loc_attrib,      3, GL_FLOAT, GL_FALSE, 0);
glVertexAttribFormat(normal_attrib,   3, GL_FLOAT, GL_FALSE, 12);
glVertexAttribFormat(texcoord_attrib, 2, GL_FLOAT, GL_FALSE, 24);
// Make my attributes all use binding 0
glVertexAttribBinding(loc_attrib,      0);
glVertexAttribBinding(normal_attrib,   0);
glVertexAttribBinding(texcoord_attrib, 0);

// Quickly bind all attributes to use "buffer"
// This replaces several calls to glVertexAttribPointer()
// Note: you don't need to bind the buffer first!  Nice!
glBindVertexBuffer(0, buffer, 0, 32);

// Quickly bind all attributes to use "buffer2"
glBindVertexBuffer(0, buffer2, 0, 32);

OpenGL 4.5 / ARB_direct_state_access

OpenGL 4.5, ou si vous avez la ARB_direct_state_access extension, vous n'avez plus besoin d'appeler glBindBuffer() ou glBindVertexArray() juste pour définir l' les choses... vous spécifiez directement les tableaux et les tampons. Vous avez seulement besoin de lier le tableau à la fin de la dessiner.

GLuint array;
// Generate a name for the array and create it.
// Note that glGenVertexArrays() won't work here.
glCreateVertexArrays(1, &array);
// Instead of binding it, we pass it to the functions below.

// Enable my attributes
glEnableVertexArrayAttrib(array, loc_attrib);
glEnableVertexArrayAttrib(array, normal_attrib);
glEnableVertexArrayAttrib(array, texcoord_attrib);
// Set up the formats for my attributes
glVertexArrayAttribFormat(array, loc_attrib,      3, GL_FLOAT, GL_FALSE, 0);
glVertexArrayAttribFormat(array, normal_attrib,   3, GL_FLOAT, GL_FALSE, 12);
glVertexArrayAttribFormat(array, texcoord_attrib, 2, GL_FLOAT, GL_FALSE, 24);
// Make my attributes all use binding 0
glVertexArrayAttribBinding(array, loc_attrib,      0);
glVertexArrayAttribBinding(array, normal_attrib,   0);
glVertexArrayAttribBinding(array, texcoord_attrib, 0);

// Quickly bind all attributes to use "buffer"
glVertexArrayVertexBuffer(array, 0, buffer, 0, 32);

// Quickly bind all attributes to use "buffer2"
glVertexArrayVertexBuffer(array, 0, buffer2, 0, 32);

// You still have to bind the array to draw.
glBindVertexArray(array);
glDrawArrays(...);

ARB_direct_state_access est agréable pour beaucoup de raisons. Vous pouvez oublier de lier des tableaux et des tampons (sauf lorsque vous dessinez) afin de ne pas avoir à penser aux variables globales cachées qu'OpenGL suit pour vous. Vous pouvez oublier la différence entre "générer un nom pour un objet "et" créer un objet " car glCreateBuffer() et glCreateArray() font les deux à la fois même temps.

Vulkan

Vulkan va encore plus loin et vous fait écrire du code comme le pseudocode que j'ai écrit ci-dessus. Donc, vous verrez quelque chose comme:

// This defines part of a "vertex array", sort of
VkVertexInputAttributeDescription attrib[3];
attrib[0].location = 0; // Feed data into shader input #0
attrib[0].binding = 0;  // Get data from buffer bound to slot #0
attrib[0].format = VK_FORMAT_R32G32B32_SFLOAT;
attrib[0].offset = 0;
// repeat for attrib[1], attrib[2]
111
répondu Dietrich Epp 2016-10-20 03:54:23

Votre interprétation du livre n'est pas tout à fait correcte. Les objets de tableau de Vertex ne stockent aucune donnée. Ils sont une classe d'objets appelés conteneurs, comme les objets Framebuffer. Vous pouvez attacher / associer d'autres objets avec eux, mais ils ne stockent jamais les données eux-mêmes. En tant que tels, ils ne sont pas une ressource partageable en contexte.

Fondamentalement, les objets de Tableau de Vertex encapsulent l'état du tableau de vertex dans OpenGL 3.0. En commençant par OpenGL 3.1 (au lieu de GL_ARB_compatibility) et OpenGL 3.2+ profils de base, vous devez avoir un VAO non nul lié à tout moment pour des commandes comme glVertexAttribPointer (...) ou glDrawArrays (...) pour fonctionner. Le vao lié forme le contexte nécessaire pour ces commandes, et stocke l'état de manière persistante.

Dans les anciennes versions de GL (et compatibilité), L'état stocké par VAOs faisait partie de la machine d'état global.

Il convient également de mentionner que la liaison" actuelle " pour GL_ARRAY_BUFFER est Non L'un des états que VAOs suivre. Alors que cette liaison est utilisée par des commandes telles que glVertexAttribPointer (...), VAOs ne stockez pas la liaison, ils stockent uniquement des pointeurs (le GL_ARB_vertex_attrib_binding l'extension introduite aux côtés de GL 4.3 complique un peu cela, alors ignorons-le pour plus de simplicité).

VAOs fais rappelez-vous ce qui est lié à GL_ELEMENT_ARRAY_BUFFER, cependant, de sorte que les commandes de dessin indexées telles que glDrawElements (...) fonctionnent comme prévu ( par exemple {[17] } VAO réutilisent le dernier tampon de tableau d'éléments lié).

13
répondu Andon M. Coleman 2014-02-08 23:08:34

La relation est créée lors de l'appel de glVertexAttribPointer.

Vue d'ensemble des VertexArrays

GL_VERTEX_ARRAY_BINDING et GL_ARRAY_BUFFER_BINDING sont des constantes, mais ils peuvent pointer à l'état global de la liaison. Je fais référence à l'état pas à la constante (orange) dans l'image. Utilisez glGet pour trouver les différents états globaux.

VertexArray regroupe des informations (y compris un tampon de tableau) sur un sommet ou plusieurs sommets parallèles.

Utiliser GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING avec glGetVertexAttrib pour trouver quel tampon de tableau d'attributs est défini.

GlBindBuffer (GL_ARRAY_BUFFER définit l'état global GL_ARRAY_BUFFER_BINDING

GlBindVertexArray définit l'état global GL_VERTEX_ARRAY_BINDING

5
répondu Jossi 2017-04-23 06:22:51

OpenGL est une interface avec État. C'est mauvais, désuet et laid, mais c'est un héritage pour vous.

Un objet de tableau de vertex est une collection de liaisons de tampon que le pilote peut utiliser pour obtenir les données pour les appels De Tirage, la plupart des tutoriels n'utilisent que l'un et n'expliquent jamais comment utiliser plusieurs Vao.

Une liaison tampon indique à opengl d'utiliser ce tampon pour les méthodes associées, en particulier pour les méthodes glVertexAttribPointer.

3
répondu ratchet freak 2015-07-06 14:08:24

Il n'y a pas de relation entre VertexArray et VBO.

Un tableau de Sommets alloue la mémoire en RAM et envoie un pointeur à L'API. VBO alloue la mémoire dans la carte graphique - la mémoire du système n'a pas d'adresse pour cela. Si vous devez accéder aux données vbo du système, vous devez d'abord les copier depuis vbo vers le système.

En outre, dans les versions plus récentes D'OpenGL, les tableaux de vertex sont complètement supprimés (dépcréciés dans 3.0, supprimés dans 3.1)

-2
répondu Gasim 2014-02-08 22:47:14