Différence entre glDrawArrays et glDrawElements

12

Alors que mon esprit rafraîchissant sur OpenGL ES, je suis tombé glDrawArraysetglDrawElements .

Je comprends comment ils sont utilisés et je comprends en quelque sorte pourquoi ils sont différents.

Ce que je ne semble pas comprendre, c'est que je ne vois pas comment glDrawElementsenregistrer les appels est une description qui est mentionnée par la plupart des livres que j'ai lus, d'où ma mention ici).

Imaginez un scénario simple dans lequel j'ai essayé de dessiner un carré en utilisant 2 triangles.

J'aurais besoin d'un ensemble de 6 sommets en utilisant glDrawArraystout en utilisantglDrawElements , j'aurais besoin de seulement 4 en plus d'un tableau d'index qui a 6 éléments.

Compte tenu de ce qui précède, voici ce que je ne comprends pas:

  1. comment glDrawElementsenregistrer les appels de tirage, s'il doit encore utiliser le tableau d'index (6 indices, dans le cas d'un carré) pour indexer dans mon tableau de sommets qui avait 4 éléments (6 fois)? En d'autres termes, cela signifie-t-ilglDrawElements faudrait toujours avoir un total de 6 appels de tirage comme glDrawArrays?
  2. comment utiliser glDrawElements économie d’espace, si l’on avait encore besoin de 2 tableaux, à savoir un pour les sommets et un pour les indices?
  3. Dans le cas du dessin d'un carré à partir de 2 triangles, pour plus de simplicité, combien d'appels de dessin glDrawElements(4 éléments dans le tableau de sommets et 6 éléments dans le tableau d'index) et glDrawArrays(6 éléments uniquement dans le tableau de sommets) ont-ils besoin, individuellement?

Merci.

Unheilig
la source

Réponses:

16

Chaque glDraw * est un appel de tirage.

1 glDrawArrays est 1 appel nul.
1 glDrawElements est 1 appel nul.

Peu importe (en ce qui concerne le nombre d'appels de tirage) combien de sommets ou d'index vous utilisez, 1 glDraw * est 1 appel de tirage.

Les cas simples de dessin de quads (en supposant que la version GL que vous utilisez n'a pas supprimé les quads) ou de triangles ne sont pas un bon exemple pour les comparer, car une liste de quads ou une liste de triangles peut être dessinée avec un seul appel à l'un ou l'autre, et glDrawArrays apparaîtra plus efficace car il n'a pas la surcharge supplémentaire d'indexation.

Prenons un cas un peu plus complexe, mais qui est représentatif d'un scénario plus réel. Imaginez que vous ayez un modèle composé de plusieurs bandes triangulaires et ventilateurs:

glDrawArrays (GL_TRIANGLE_FAN, .....);
glDrawArrays (GL_TRIANGLE_STRIP, .....);
glDrawArrays (GL_TRIANGLE_STRIP, .....);
glDrawArrays (GL_TRIANGLE_FAN, .....);
glDrawArrays (GL_TRIANGLE_STRIP, .....);
glDrawArrays (GL_TRIANGLE_FAN, .....);

Dans cet exemple, l'utilisation de glDrawArrays vous donne un total de 6 appels de dessin pour le modèle. Cependant, les bandes et les ventilateurs peuvent facilement être convertis en triangles indexés, alors ajoutez des indices et cela devient:

glDrawElements (GL_TRIANGLES, .....);

C'est un appel nul, pour l'ensemble du modèle.


Les avantages de glDrawElements par rapport à glDrawArrays sont plus que la simple économie de mémoire, ce qui est la manière naïve de la mesurer. Il y a un potentiel d'économie de mémoire là où les sommets peuvent être réutilisés, car un index est généralement plus petit qu'un sommet (donc même si vous avez beaucoup d'indices en équilibre, ils seront plus petits), mais d'autres avantages incluent:

  • Nombre d'appels de tirage réduit. Chaque appel de tirage entraîne une surcharge de validation de l'état, de configuration, etc., et une grande partie de cette surcharge se produit du côté du processeur. En réduisant le nombre d'appels de tirage, nous évitons une grande partie de ces frais généraux.

  • Réutilisation des sommets. C'est bien plus qu'une simple économie de mémoire. Votre GPU a probablement un cache de vertex matériel, où les sommets récemment transformés peuvent être stockés; si le même sommet revient, et s'il est dans le cache, il peut être réutilisé depuis le cache plutôt que d'avoir à se transformer à nouveau. Votre matériel vérifiera le cache en comparant les indices, donc en termes OpenGL, la seule façon d'utiliser le cache est d'utiliser glDrawElements.


Donc pour répondre à vos questions spécifiques:

  1. comment glDrawElements pourrait-il sauver les appels de tirage ...? Dans l'exemple que vous utilisez, ce n'est pas le cas. Chacun a un appel nul. Comme je l'ai expliqué ci-dessus, cet exemple est très mauvais pour comparer les deux.

  2. comment l'utilisation de glDrawElements permettrait-elle d'économiser de l'espace ...? Parce que les indices sont plus petits que les sommets. Un index de 16 bits est de deux octets, un sommet position / couleur / texcoord est de 24 octets. 6 sommets est de 144 octets, 4 sommets plus 6 indices est de 108 octets.

  3. Dans le cas de dessiner un carré à partir de 2 triangles ...? Un et un. Un appel glDraw * est un appel nul, le nombre de sommets ou d'indices utilisés n'est pas pertinent pour cette mesure. Mais je dois souligner à nouveau, c'est un très mauvais exemple pour comparer les deux.


Enfin, et pour compliquer un peu les choses, alors que glDrawElements avec des triangles est le chemin optimal sur les GPU de bureau, sur mobile, il peut être très différent. Certains GPU mobiles pourraient préférer glDrawArrays avec GL_TRIANGLE_STRIP (vous ajouteriez des triangles dégénérés pour concaténer des primitives dans ce cas), et je n'ai même pas abordé des sujets plus avancés tels que le redémarrage primitif ou le multi-dessin.

Maximus Minimus
la source
Merci beaucoup pour vos commentaires; Je prends juste un peu de temps pour lire ce que vous avez partagé. Je voulais juste vous faire savoir que j'ai reconnu votre réponse. Merci encore.
Unheilig
Dans votre exemple de conversion de 6 appels DrawTriangleFans et DrawTriangleStrips en 1 appels DrawTriangles simples. Est-ce que cela améliore vraiment certaines performances? À ma connaissance, dessiner une bande de triangle composée de 100 triangles est beaucoup plus efficace que dessiner 100 triangles individuellement, et l'avantage compenserait facilement toute pénalité survenue en utilisant 6 appels de fonction plutôt que 1.
Samuel Li
@SamuelLi 6-to-1 ne sera pas une énorme amélioration, il est simplement destiné à illustrer le principe. De plus, et comme je l'ai indiqué, les bandes ne sont généralement pas un gain de performances par rapport aux listes indexées sur le matériel de bureau post-1998. Vérifiez la date sur tout document vous conseillant d'utiliser des bandelettes.
Maximus Minimus
J'ai compris, merci pour la clarification! @MaximusMinimus
Samuel Li