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 :
- 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);
.
- 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);
.
- 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.
- Dessinez quelque chose avec -
glDrawArrays(GL_TRIANGLES, 0, 6);
- 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.