Une partie de la terminologie est un peu décalée:
- A
Vertex Array
est juste un tableau (généralement a float[]
) qui contient des données de sommet. Il n'a besoin d'être lié à rien. A ne pas confondre avec a Vertex Array Object
ou VAO, que je reviendrai plus tard
- A
Buffer Object
, communément appelé a Vertex Buffer Object
lors du stockage de sommets, ou VBO en abrégé, est ce que vous appelez simplement un Buffer
.
- Rien n'est enregistré dans le tableau de sommets,
glVertexAttribPointer
fonctionne exactement comme glVertexPointer
ou glTexCoordPointer
fonctionne, juste au lieu d'attributs nommés, vous obtenez un nombre qui spécifie votre propre attribut. Vous passez cette valeur comme index
. Tous vos glVertexAttribPointer
appels sont mis en file d'attente pour la prochaine fois que vous appelez glDrawArrays
ou glDrawElements
. Si vous avez une liaison VAO, le VAO stockera les paramètres pour tous vos attributs.
Le principal problème ici est que vous confondez les attributs de sommet avec les VAO. Les attributs Vertex ne sont que la nouvelle façon de définir des sommets, des texcoords, des normales, etc. pour le dessin. État du magasin VAO. Je vais d'abord expliquer comment le dessin fonctionne avec les attributs de sommet, puis comment vous pouvez réduire le nombre d'appels de méthode avec les VAO:
- Vous devez activer un attribut avant de pouvoir l'utiliser dans un shader. Par exemple, si vous voulez envoyer des sommets à un shader, vous allez probablement l'envoyer comme premier attribut, 0. Donc, avant de rendre, vous devez l'activer avec
glEnableVertexAttribArray(0);
.
- Maintenant qu'un attribut est activé, vous devez définir les données qu'il va utiliser. Pour ce faire, vous devez lier votre VBO -
glBindBuffer(GL_ARRAY_BUFFER, myBuffer);
.
- Et maintenant, nous pouvons définir l'attribut -
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
. Dans l'ordre du paramètre: 0 est l'attribut que vous définissez, 3 est la taille de chaque sommet, GL_FLOAT
est le type, GL_FALSE
signifie ne pas normaliser chaque sommet, les 2 derniers zéros signifient qu'il n'y a pas de foulée ou de décalage sur les sommets.
- Dessinez quelque chose avec -
glDrawArrays(GL_TRIANGLES, 0, 6);
- La prochaine chose que vous dessinez peut ne pas utiliser l'attribut 0 (de manière réaliste, mais c'est un exemple), nous pouvons donc le désactiver -
glDisableVertexAttribArray(0);
Enveloppez cela dans les glUseProgram()
appels et vous avez un système de rendu qui fonctionne correctement avec les shaders. Mais disons que vous avez 5 attributs, sommets, texcoords, normales, couleurs et coordonnées lightmap différents. Tout d'abord, vous feriez un seul glVertexAttribPointer
appel pour chacun de ces attributs et vous devrez activer tous les attributs au préalable. Supposons que vous définissiez les attributs 0-4 tels que je les ai répertoriés. Vous les activeriez tous comme ceci:
for (int i = 0; i < 5; i++)
glEnableVertexAttribArray(i);
Et puis, vous devrez lier différents VBO pour chaque attribut (à moins que vous ne les stockiez tous dans un seul VBO et que vous utilisiez des décalages / foulée), puis vous devez faire 5 glVertexAttribPointer
appels différents , de glVertexAttribPointer(0,...);
à glVertexAttribPointer(4,...);
pour les sommets aux coordonnées de lightmap respectivement.
Espérons que ce système à lui seul a du sens. Je vais maintenant passer aux VAO pour expliquer comment les utiliser pour réduire le nombre d'appels de méthode lors de ce type de rendu. Notez que l'utilisation d'un VAO n'est pas nécessaire.
A Vertex Array Object
ou VAO est utilisé pour stocker l'état de tous les glVertexAttribPointer
appels et des VBO ciblés lors de chacun des glVertexAttribPointer
appels.
Vous en générez un avec un appel à glGenVertexArrays
. Pour stocker tout ce dont vous avez besoin dans un VAO, associez-le glBindVertexArray
, puis effectuez un appel de tirage complet . Tous les appels draw bind sont interceptés et stockés par le VAO. Vous pouvez dissocier le VAO avecglBindVertexArray(0);
Maintenant, lorsque vous voulez dessiner l'objet, vous n'avez pas besoin de rappeler toutes les liaisons VBO ou les glVertexAttribPointer
appels, il vous suffit de lier le VAO avec glBindVertexArray
puis d'appeler glDrawArrays
ou glDrawElements
et vous dessinerez exactement la même chose que si vous faisaient tous ces appels de méthode. Vous voudrez probablement aussi dissocier le VAO par la suite.
Une fois que vous avez dissocié le VAO, tout l'état revient à ce qu'il était avant la liaison du VAO. Je ne sais pas si les modifications que vous apportez pendant que le VAO est lié sont conservées, mais cela peut facilement être compris avec un programme de test. Je suppose que vous pouvez penser glBindVertexArray(0);
que cela est lié au VAO "par défaut" ...
Mise à jour: Quelqu'un a attiré mon attention sur la nécessité de l'appel de tirage au sort. En fait, vous n'avez pas vraiment besoin de faire un appel de dessin COMPLET lors de la configuration du VAO, juste toutes les choses de liaison. Je ne sais pas pourquoi je pensais que c'était nécessaire plus tôt, mais c'est corrigé maintenant.
glVertexAttribPointer
? Dans mes tests, l'ordre ne semble pas avoir d'importance. (2) Si je vous comprends bien, les attributs Vertex sont globaux et seul leur état activé / désactivé est enregistré dans le VAO actuellement lié?glDrawArrays
ouglDrawElements
. Je mettrai à jour l'article pour refléter cela (2) Oui, mais ce n'est pas seulement l'état d'activation / désactivation qui est stocké, c'est tout ce qui concerne ces appels - ce qui était lié à GL_ARRAY_BUFFER à l'époque, le type, la foulée et le décalage. Essentiellement, il stocke suffisamment pour modifier tous les attributs de sommet de la manière dont vous les avez configurés avec le VAO.layout(location = x)
le shader ou avecglBindAttributeLocation
lors de la compilation du shader. ExempleLa terminologie et la séquence des API à appeler sont en effet assez déroutantes. Ce qui est encore plus déroutant, c'est la façon dont les différents aspects - tampon, attribut de sommet générique et variable d'attribut de shader sont associés. Voir OpenGL-Terminology pour une assez bonne explication.
De plus, le lien OpenGL-VBO, shader, VAO montre un exemple simple avec les appels API nécessaires. C'est particulièrement bien pour ceux qui passent du mode immédiat au pipeline programmable.
J'espère que ça aide.
Edit: Comme vous pouvez le voir dans les commentaires ci-dessous, les gens peuvent faire des hypothèses et tirer des conclusions. La réalité est que c'est assez déroutant pour les débutants.
la source
void glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid * pointer)
l'identifiant est appeléindex
. Le même identifiant dans le contexte du programme est appelélocation
dans l'API glGetAttribLocation .