92 votes

clarification de glVertexAttribPointer

Je veux juste m'assurer que je comprends bien (je demanderais bien sur SO Chat, mais c'est mort là-dedans !):

Nous avons un tableau de sommets, que nous rendons "actuel" en le liant
puis nous avons un tampon, que nous lions à une cible.
alors nous remplissons cette cible via glBufferData qui remplit essentiellement ce qui a été lié à cette cible, c'est-à-dire notre Buffer
et ensuite nous appelons glVertexAttribPointer qui décrit comment les données sont disposées -- les données étant ce qui est lié à GL_ARRAY_BUFFER et ce descripteur est sauvegardé dans notre tableau de sommets original.

(1) Ma compréhension est-elle correcte ?
Le site documentation est un peu clairsemé sur la façon dont tout est corrélé.

(2) Existe-t-il une sorte de tableau de sommets par défaut ? Parce que j'ai oublié/omis glGenVertexArrays y glBindVertexArray et mon programme fonctionnait bien sans ça.


Editar: J'ai raté une étape... glEnableVertexAttribArray .

(3) Est-ce que l'attribut de sommet est lié au tableau de sommets au moment où l'attribut de sommet est utilisé ? glVertexAttribPointer est appelé, et ensuite nous pouvons activer/désactiver cet attribut par l'intermédiaire de glEnableVertexAttribArray à tout moment, quel que soit le tableau de sommets actuellement lié ?

Ou (3b) Est-ce que l'attribut de sommet est lié au tableau de sommets au moment où glEnableVertexAttribArray est appelé, et nous pouvons donc ajouter le même attribut de sommet à plusieurs tableaux de sommets en appelant glEnableVertexAttribArray à différents moments, lorsque différentes matrices de sommets sont liées ?

207voto

Robert Rouhani Points 8317

Certains termes sont un peu faux :

  • A Vertex Array est simplement un tableau (généralement un float[] ) qui contient les données des sommets. Il n'a pas besoin d'être lié à quoi que ce soit. À ne pas confondre avec un Vertex Array Object ou VAO, dont je parlerai plus tard.
  • A Buffer Object communément appelé Vertex Buffer Object lors du stockage des sommets, ou VBO pour faire court, est ce que vous appelez juste un Buffer .
  • Rien n'est sauvegardé dans le tableau des sommets, glVertexAttribPointer fonctionne exactement comme glVertexPointer o glTexCoordPointer fonctionne, simplement au lieu d'attributs nommés, vous devez fournir un nombre qui spécifie votre propre attribut. Vous passez cette valeur comme index . Tous vos glVertexAttribPointer les appels sont mis en file d'attente pour la prochaine fois que vous appelez. glDrawArrays o glDrawElements . Si vous avez un VAO lié, le VAO stockera les paramètres de tous vos attributs.

Le principal problème ici est que vous confondez les attributs de vertex avec les VAO. Les attributs de sommets sont simplement la nouvelle façon de définir les sommets, les texcoords, les normales, etc. pour le dessin. Les VAOs stockent l'état. Je vais d'abord expliquer comment le dessin fonctionne avec les attributs de sommets, puis comment réduire le nombre d'appels de méthodes avec les VAO :

  1. 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 en tant que premier attribut, 0. Donc, avant d'effectuer le rendu, vous devez l'activer avec la commande glEnableVertexAttribArray(0); .
  2. Maintenant qu'un attribut est activé, vous devez définir les données qu'il va utiliser. Pour ce faire, vous devez relier votre VBO - glBindBuffer(GL_ARRAY_BUFFER, myBuffer); .
  3. Et maintenant nous pouvons définir l'attribut - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0); . Dans l'ordre des paramètres : 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 stride ou d'offset sur les sommets.
  4. Dessinez quelque chose avec - glDrawArrays(GL_TRIANGLES, 0, 6);
  5. Le prochain objet que vous dessinerez n'utilisera peut-être pas l'attribut 0 (en réalité, il l'utilisera, mais il s'agit d'un exemple), nous pouvons donc le désactiver glDisableVertexAttribArray(0);

Enveloppez cela dans glUseProgram() et vous avez un système de rendu qui fonctionne correctement avec les shaders. Mais disons que vous avez 5 attributs différents, des sommets, des texcoordes, des normales, des couleurs et des coordonnées de lightmap. Tout d'abord, vous feriez un unique glVertexAttribPointer pour chacun de ces attributs, et vous devrez activer tous les attributs au préalable. Disons que vous définissez les attributs 0 à 4 tels que je les ai énumérés. Vous les activeriez tous de la manière suivante :

for (int i = 0; i < 5; i++)
    glEnableVertexAttribArray(i);

Il faudrait alors lier des VBO différents pour chaque attribut (à moins de les stocker tous dans un seul VBO et d'utiliser des offsets/stride), ce qui nécessiterait de créer 5 VBO différents. glVertexAttribPointer appels, de glVertexAttribPointer(0,...); a glVertexAttribPointer(4,...); pour les sommets aux coordonnées de la carte lumineuse respectivement.

J'espère que ce système seul a un sens. Je vais maintenant passer aux VAO pour expliquer comment les utiliser afin de 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 toutes les glVertexAttribPointer et les VBOs qui ont été ciblés lorsque chacun des glVertexAttribPointer Des appels ont été passés.

Vous en générez un avec un appel à glGenVertexArrays . Pour stocker tout ce dont vous avez besoin dans un VAO, liez-le avec glBindVertexArray puis faire un appel de tirage complet . Tous les dessiner les appels liés sont interceptés et stockés par le VAO. Vous pouvez délier le VAO avec glBindVertexArray(0);

Maintenant, lorsque vous souhaitez dessiner l'objet, vous n'avez pas besoin de rappeler tous les liens VBO ou les liens glVertexAttribPointer il suffit de lier le VAO à l'aide de la fonction glBindVertexArray puis appeler glDrawArrays o glDrawElements et vous dessinerez exactement la même chose que si vous faisiez tous ces appels de méthode. Vous voudrez probablement aussi délier le VAO par la suite.

Une fois que vous avez délié le VAO, tous les états reviennent à ce qu'ils étaient avant que vous ne liiez le VAO. Je ne suis pas sûr que les modifications apportées pendant que le VAO est lié soient conservées, mais cela peut facilement être vérifié avec un programme de test. Je suppose que vous pouvez penser à glBindVertexArray(0); comme contraignant pour le VAO "par défaut"...


Mise à jour : Quelqu'un a attiré mon attention sur la nécessité de l'appel de tirage au sort. Il s'avère que vous n'avez pas besoin de faire un appel de tirage complet lors de la mise en place du VAO, juste de faire toutes les liaisons. Je ne sais pas pourquoi j'ai pensé que c'était nécessaire plus tôt, mais c'est corrigé maintenant.

3voto

ap-osd Points 66

La terminologie et la séquence des API à appeler sont en effet assez déroutantes. Ce qui est encore plus déroutant, c'est la manière dont les différents aspects - tampon, attribut de sommet générique et variable d'attribut de shader - sont associés. Voir OpenGL-Terminologie pour une bonne explication.

En outre, le lien OpenGL-VBO,shader,VAO montre un exemple simple avec les appels API nécessaires. Il est particulièrement utile pour ceux qui passent du mode immédiat au pipeline programmable.

J'espère que cela vous aidera.

Editar: Comme vous pouvez le voir dans les commentaires ci-dessous, les gens peuvent faire des suppositions et sauter aux conclusions. La réalité est que c'est assez déroutant pour les débutants.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X