Navigation

Tutoriel précédent : interpolation   Sommaire   Tutoriel suivant : concaténation des transformations

II. Contexte

OpenGL fournit diverses fonctions de dessins. glDrawArrays, que nous avons utilisé jusqu'à présent, est classée dans la catégorie des « dessins ordonnés ». Cela signifie que le tampon de sommets est parcouru à partir de l'indice spécifié et, pour chaque X sommets (1 pour les points, 2 pour les lignes…), une primitive est générée. C'est très simple d'utilisation, cependant le revers de la pièce est que, si un sommet est utilisé dans plusieurs primitives, alors il doit être présent plusieurs fois dans le tampon de sommets. C'est-à-dire qu'il n'y a pas de concept de partage de sommets.

Le partage de sommets est fourni par les fonctions de dessins appartenant à la catégorie des « dessins indexés ». Là, en plus du tampon de sommets, il y a aussi un tampon d'indices qui contient les indices du tampon de sommets. Le parcours du tampon d'indices est similaire au parcours du tampon de sommets : tous les X indices, une primitive est générée. Pour vous exercer au partage de sommets, vous pouvez simplement répéter l'indice du sommet partagé plusieurs fois. Le partage de sommets est très important en termes d'occupation mémoire, car la plupart des objets sont représentés par des maillages fermés de triangles, et la plupart des sommets prennent part dans la composition de plus d'un triangle.

Voici un exemple de dessin ordonné :

Image non disponible

Si nous effectuons un rendu de triangles, le GPU va générer la liste suivante : V0/1/2, V3/4/5 V6/7/8, etc.

Voici un exemple de dessin indexé :

Image non disponible

Dans ce cas le GPU va générer les triangles suivants : V4/0/1, V5/2/1, V6/1/7, etc.

L'utilisation de dessins indexés en OpenGL requiert la génération et le remplissage d'un tampon d'indices. Ce tampon doit être lié, en plus du tampon de sommets, avant la fonction de dessin et une fonction différente doit être utilisée.

III. Explication du code

 
Sélectionnez
GLuint IBO;

Nous avons ajouté un nouvel identifiant pour le tampon d'indices.

 
Sélectionnez
Vertices[0] = Vector3f(-1.0f, -1.0f, 0.0f);
Vertices[1] = Vector3f(0.0f, -1.0f, 1.0f);
Vertices[2] = Vector3f(1.0f, -1.0f, 0.0f);
Vertices[3] = Vector3f(0.0f, 1.0f, 0.0f);

Pour montrer le partage de sommets, nous avons besoin d'un maillage un peu plus complexe. De nombreux tutoriels utilisent le fameux cube tournant pour cela. Il requiert huit sommets et douze triangles. Comme je suis fainéant, j'utilise la pyramide tournante à la place. Elle requiert uniquement quatre sommets et quatre triangles, ce qui est beaucoup plus rapide à générer manuellement.

Lorsque l'on regarde ces sommets de dessus (le long de l'axe Y), nous voyons le schéma suivant :

Image non disponible
 
Sélectionnez
unsigned int Indices[] = { 0, 3, 1,
                           1, 3, 2,
                           2, 3, 0,
                           0, 1, 2 };

Le tampon d'indices est rempli en utilisant un tableau d'indices. Les indices correspondent à la position des sommets dans le tampon d'indices. Lorsque l'on regarde le tableau et le schéma au-dessus, nous pouvons voir que le dernier triangle est la base de la pyramide, tandis que les trois autres constituent ses faces. La pyramide n'est pas symétrique mais est très facile à spécifier.

 
Sélectionnez
glGenBuffers(1, &IBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(Indices), Indices, GL_STATIC_DRAW);

Nous créons et remplissons le tampon d'indices en utilisant notre tableau. Vous pouvez voir que la seule différence, entre la création d'un tampon de sommets et la création d'un tampon d'indices, est que le tampon de sommets prend GL_ARRAY_BUFFER en tant que type de tampon, alors que le tampon d'indices prend GL_ELEMENT_ARRAY_BUFFER.

 
Sélectionnez
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO);

En plus de lier le tampon de sommets, nous devons aussi lier le tampon d'indices avant de dessiner. Là encore, nous utilisons GL_ELEMENT_ARRAY_BUFFER comme type de tampon.

 
Sélectionnez
glDrawElements(GL_TRIANGLES, 12, GL_UNSIGNED_INT, 0);

Nous utilisons glDrawElements au lieu de glDrawArrays. Le premier paramètre est le type de primitives à dessiner (comme pour glDrawArrays). Le second paramètre est le nombre d'indices, parmi ceux contenus dans le tampon d'indices, à utiliser pour la génération des primitives. Le paramètre suivant est le type de chaque indice. Le GPU doit être informé de la taille de chaque indice, sinon il ne saura pas comment parcourir le tampon. Les valeurs possibles ici sont GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT, GL_UNSIGNED_INT. Si l'intervalle d'indices est petit, nous voudrons le plus petit type de données possible, qui prend moins de place en mémoire, et si l'intervalle d'indices est grand, nous voudrons les types les plus larges. Le dernier paramètre indique au GPU le point de départ en octets à partir duquel il commence le parcours du tampon. C'est utile quand le même tampon d'indices contient les indices de plusieurs objets. En spécifiant un point de départ et un nombre d'indices, nous précisons au GPU quel objet dessiner. Dans notre cas nous voulons commencer au début, donc nous spécifions zéro. Notons que le type du dernier paramètre est Glvoid*, ainsi, si nous voulons spécifier autre chose que zéro, nous devrons le convertir dans ce type.

IV. Sources

Vous pouvez télécharger les sources de ce projet en suivant ce lien :

Récupérer les sources

V. Remerciements

Merci à Etay Meiri de nous permettre de traduire son tutoriel.

Merci à LittleWhite pour ses corrections et à jacques_jean pour sa relecture.

Navigation

Tutoriel précédent : interpolation   Sommaire   Tutoriel suivant : concaténation des transformations