3.7 Afficher un VBO

Jusqu'à ce chapitre, pour afficher un modèle 3D nous devions envoyer les données à l'aide de la fonction glVertexAttribPointer() puis nous affichions le tout avec la fonction glDrawArrays(). Nous continuerons à procéder ainsi sauf que nous ajouterons le verrouillage du VBO juste avant la fonction glVertexAttribPointer().

En effet, même si les données se trouvent dans la mémoire vidéo, OpenGL ne sait pas où elles se situent exactement, c'est à nous de lui dire. Pour ça, on va toujours utiliser la fonction glVertexAttribPointer() sauf qu'on va modifier son dernier paramètre. Je vous redonne son prototype pour que vous visualisiez le paramètre en question :

1
void glVertexAttribPointer(GLuint index, GLuint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer);

Le paramètre pointer permet à OpenGL de savoir où se trouvent nos données (vertices et toute la clique je le rappelle). Avant nous donnions directement les tableaux à ce paramètre, ils étaient stockés dans la RAM ça ne posait pas de problème. Mais maintenant nous devons lui donner l'adresse des tableaux à l'intérieur de la mémoire vidéo.

plop

Lorsque le VBO est verrouillé, OpenGL sait qu'il doit aller chercher les données dans la plage mémoire qui lui est consacrée. A partir de maintenant, le paramètre pointer n'attend plus un tableau mais un offset.

Offset ça ne vous rappelle pas un paramètre ? C'est celui de la fonction glBufferSubData(), il représente la case (le décalage en mémoire) où le transfert doit commencer. Et bien c'est justement ce qu'attend OpenGL maintenant. Nous lui donnerons donc l'offset correspondant aux tableaux de données dans la mémoire vidéo.

Pour les vertices, cet offset sera de 0 car ils se situent au début de la zone mémoire. Pour les couleurs, cet offset sera égal à l'attribut tailleVerticesBytes car elles sont situées juste après les vertices dans la zone mémoire. Et si vous rajouter autre chose après (en l'ayant bien alloué bien sûr) se sera tailleVerticesBytes + tailleCouleursBytes et ainsi de suite.

Voici un affichage en considérant que vboID est l'ID d'un VBO bien alloué, avec des données bien copiées dans la VRAM :

1
2
3
4
5
6
7
8
9
10
// Verrouillage du VBO
glBindBuffer(GL_ARRAY_BUFFER, vboID);
	// Accès aux vertices dans la mémoire vidéo
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
	glEnableVertexAttribArray(0);
	// Accès aux couleurs dans la mémoire vidéo
	glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, tailleVerticesBytes);
	glEnableVertexAttribArray(1);
// Déverrouillage du VBO
glBindBuffer(GL_ARRAY_BUFFER, 0);

Heu, monsieur l'arbitre, c'est pas un pointeur qu'on passe en dernier paramètre

Techniquement, on ne peut pas compiler ce code car le paramètre pointer attend un décalage (représenté par une adresse et non une variable). Or nous, nous lui donnons une variable de type intégré. Alors bon, pour le 0 ça passe encore mais pour tailleVerticesBytes notre compilateur va nous râler dessus.

Pour utiliser les variables tailleXXX en décalage, OpenGL nous demande de les encadrer avec la macro suivante :

1
2
3
#ifndef BUFFER_OFFSET
    #define BUFFER_OFFSET(offset) ((char*)NULL + (offset))
#endif

Ce code permet de spécifier un décalage offset en partant de l'adresse NULL (ou 0) qui indique le début du VBO. Le mot-clef char permet simplement de faire le lien avec les bytes, je vous rappelle que les variables de type char sont codées sur 1 byte.

Pensez à inclure ce code dans chaque fichier où vous utiliserez les VBO.

En utilisant cette macro, le compilateur comprend bien qu'on veut lui envoyer une adresse à l'aide d'une variable. Nous encadrons donc le paramètre pointer par BUFFER_OFFSET() :

1
2
3
4
5
6
7
8
9
10
// Verrouillage du VBO
glBindBuffer(GL_ARRAY_BUFFER, vboID);
	// Accès aux vertices dans la mémoire vidéo
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
	glEnableVertexAttribArray(0);
	// Accès aux couleurs dans la mémoire vidéo
	glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(tailleVerticesBytes));
	glEnableVertexAttribArray(1);
// Déverrouillage du VBO
glBindBuffer(GL_ARRAY_BUFFER, 0);

Voilà pour l'affichage.