Les vertex array objects (VAO) d'OpenGL 4

Donald Urquhart

Depuis la version 3, OpenGL a subi beaucoup de modifications, dont la suppression des états et du mode immédiat.

Commentez

- Titre : Les vertex array objects (VAO) d'OpenGL 4

- Auteur : Donald Urquhart

- Parution : 9 juillet 2012

- Mise à jour : 28 octobre 2017

- Licence : Copyright ® 2010 Donald Urquhart. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- I. L'article original

- II. Introduction

- III. Code

- III-A. opengl_3.h

- III-B. opengl_3.cpp

- IV. Résultat

- V. Remerciements

I - L'article original

Cet article est une adaptation en langue française de 4. OpenGL 4 Vertex Array Objects (VAO), de Donald Urquhart.

II - Introduction

Avec la suppression des états OpenGL et du mode immédiat, on ne peut plus effectuer d'appel à glBegin(), soit plus de glBegin(GL_TRIANGLES) ou autres. De même, cela signifie que les appels à glVertex() ou glColor() ne sont plus possibles. Ainsi, on aura besoin d'une nouvelle manière de transférer des données à la carte graphique pour le rendu de la géométrie. On pourrait utiliser les VBO, présentés dans un tutoriel sur les terrains, ou bien les VAO, une fonctionnalité d'OpenGL 3 et plus récents. Il s'agit des vertex array objects, un seul pouvant stocker plusieurs VBO. Grâce à cette fonctionnalité, on peut stocker les données des sommets et des couleurs dans des VBO différents, mais dans le même VAO. On peut appliquer le même principe pour tous les types de données généralement transmis comme VBO, dont les données des normales ou n'importe quelle donnée requise au niveau des sommets.

Un VAO est une manière de stocker des informations sur les objets dans la carte graphique, au lieu de lui envoyer des sommets au fur et à mesure des besoins. C'est la manière de fonctionner de Direct3D, ce dernier n'ayant jamais disposé du mode immédiat d'OpenGL (abandonné avec la version 3). Ceci signifie que l'application ne doit pas passer son temps à transférer des données depuis et vers la carte graphique, d'où un grand gain de performances.

Le mieux est que cela n'est pas si compliqué à mettre en place. Au lieu d'effectuer une série d'appels à glVertex(), on stocke tous les sommets dans un tableau que l'on place dans un VBO, puis dans un VAO. OpenGL s'occupe de tout en coulisses et on dispose alors de tous les avantages associés.

III - Code

On ne considérera pas le lecteur aguerri de l'art des VBO, on repart donc des bases en expliquant les diverses notions au fur et à mesure. Il ne reste plus tellement de travail pour afficher un carré à l'écran.

III-A - opengl_3.h

Dans opengl_3.h, on crée deux variables et une méthode. Cette dernière ne prendra pas de paramètre et ne retournera rien, mais créera le VAO et le VBO nécessaires pour dessiner un carré. Dans cette optique, on la nomme createSquare().

void createSquare(void); // Méthode pour créer les VAO du carré

Les deux variables seront des tableaux d'entiers non signés de longueur unitaire, on a ainsi un VAO et un VBO. On appelle ces variables privées vaoID et vboID.

unsigned int vaoID[1]; // VAO
unsigned int vboID[1]; // VBO

III-B - opengl_3.cpp

Jusque-là, rien d'effrayant. Dans opengl_3.cpp, on commence à l'utiliser. Dans la méthode setupScene(), on ajoute un appel à createSquare() puis on s'occupe de cette dernière. On garde à l'esprit qu'on crée le carré, le VAO et le VBO avant de les utiliser, sinon on risque d'avoir des problèmes de mémoire non allouée.

void OpenGLContext::setupScene(void) {
...

createSquare(); // Crée un carré
}

Ensuite, la méthode createSquare(). On remplit ce squelette :

/**
createSquare est utilisée pour créer le VAO qui contiendra le carré. On stocke en dur ses sommets.
*/
void OpenGLContext::createSquare(void) {

}

Avant de créer le VAO et le VBO, on a besoin de données décrivant les sommets de la forme. On dessine un carré formé par deux triangles, on a donc besoin de six sommets (trois par triangle). Ensuite, puisque chaque sommet contient trois valeurs (les coordonnées x, y et z) et qu'on a six sommets, on aura un total de dix-huit valeurs pour décrire le carré. Il s'agira de valeurs float stockées dans un tableau vertices. On utilise un tableau dynamique, qu'il faudra supprimer à la fin de la méthode pour éviter les fuites de mémoire.

void OpenGLContext::createSquare(void) {
float* vertices = new float[18];  // Sommets du carré

delete [] vertices; // Supprimer les sommets
}

On remplit alors quelques valeurs pour ces sommets. On met tous les sommets à 0 sur l'axe 0 et on donne au carré une longueur d'une unité. On centre le carré à l'origine, ce qui donne un sommet en haut à gauche de coordonnées (- 0,5 ; 0,5 ; 0.0) ; en bas à droite (0,5 ; - 0,5 ; 0.0).

void OpenGLContext::createSquare(void) {
float* vertices = new float[18];  // Sommets du carré

vertices[0] = -0.5; vertices[1] = -0.5; vertices[2] = 0.0; // Coin en bas à gauche
vertices[3] = -0.5; vertices[4] = 0.5; vertices[5] = 0.0; // Coin en haut à gauche
vertices[6] = 0.5; vertices[7] = 0.5; vertices[8] = 0.0; // Coin en haut à droite

vertices[9] = 0.5; vertices[10] = -0.5; vertices[11] = 0.0; // Coin en bas à droite
vertices[12] = -0.5; vertices[13] = -0.5; vertices[14] = 0.0; // Coin en bas à gauche
vertices[15] = 0.5; vertices[16] = 0.5; vertices[17] = 0.0; // Coin en haut à droite

delete [] vertices; // Supprimer les sommets
}

Les coordonnées des sommets remplies, on peut avancer et créer un VBO avec un appel à glGenVertexArrays(). Ensuite, on utilise un appel à glBindVertexArray() pour activer le VAO. De là, on peut appeler glGenBuffers() pour créer le VBO que l'on lie avec glBindBuffer().

Dans l'ordre, on aura donc :

1. Générer le vertex array object ;

2. Lier le vertex array object ;

3. Générer le vertex buffer object ;

4. Lier le vertex buffer object ;

Dès lors, on remplit le VBO avec les données des sommets. À la création du VBO, on peut en définir le type ; dans le cas présent, on utilise GL_STATIC_DRAW pour indiquer à OpenGL qu'on n'envisage pas de changer les données, d'aucune manière, on veut juste les afficher. L'API définit également des types pour les données qui changent, notamment précisés sur le wiki OpenGL.

Ensuite, on appelle glBufferData() pour transférer les données du tableau précédemment créé dans le VBO, avant de dire à OpenGL que ce VBO servira de stockage de sommets. Finalement, on nettoie en désactivant tant le tableau d'attributs des sommets que le VAO.

void OpenGLContext::createSquare(void) {

...

glGenVertexArrays(1, &vaoID[0]); // Créer le VAO
glBindVertexArray(vaoID[0]); // Lier le VAO pour l'utiliser

glGenBuffers(1, vboID); // Générer le VBO
glBindBuffer(GL_ARRAY_BUFFER, vboID[0]); // Lier le VBO
glBufferData(GL_ARRAY_BUFFER, 18 * sizeof(GLfloat), vertices, GL_STATIC_DRAW); // Définir la taille, les données et le type du VBO

glVertexAttribPointer((GLuint)0, 3, GL_FLOAT, GL_FALSE, 0, 0); // Définir le pointeur d'attributs des sommets

glEnableVertexAttribArray(0); // Désactiver le VAO
glBindVertexArray(0); // Désactiver le VBO

delete [] vertices; // Supprimer les sommets
}

On a maintenant un VAO avec un VBO contenant les sommets d'un carré. Jusqu'ici, cela a été relativement rapide et facile, on affiche donc ces données à l'écran. On saute ainsi à la méthode renderScene() et, après la définition des variables glUniformMatrix4vf pour le shader du tutoriel précédent, on ajoute trois lignes pour le rendu. Tout d'abord, on active le VAO ; ensuite, on le dessine ; finalement, on le désactive. Cela donne :

glBindVertexArray(vaoID[0]); // Lier le VAO

glDrawArrays(GL_TRIANGLES, 0, 6); // Dessiner le carré

glBindVertexArray(0); // Délier le VAO

IV - Résultat

On a maintenant créé un carré sans mode immédiat et en stockant toutes les données sur la carte graphique, ce qui assurera des performances optimales. On pourrait optimiser ce résultat en utilisant GL_TRIANGLE_STRIP au lieu de GL_TRIANGLE et n'utiliser que quatre sommets (NDT : on aurait aussi pu utiliser des tableaux d'index). Dans le prochain tutoriel, on ajoutera une couleur au carré.

Les fichiers de projet Visual Studio 2010 de ce tutoriel sont disponibles au téléchargement.

Animation en format "youtube" non supportée.
Contenu uniquement consultable en ligne à cette adresse :
https://www.youtube.com/v/hp1rOvKQR-A?version=3&feature=player_detailpage

V - Remerciements

Merci à Alexandre Laurent pour son aide à la traduction et à Claude Leloup pour sa relecture orthographique !