Differenza in glDrawArrays e glDrawElements


12

Mentre mi rinfrescavo la mente su OpenGL ES, mi sono imbattuto glDrawArrayse glDrawElements.

Capisco come vengono utilizzati e in qualche modo capisco perché sono diversi.

Ciò che non sembra capire è che non riesco a vedere come glDrawElementsposso salvare le chiamate di disegno (il salvataggio di chiamate di disegno è una descrizione che è menzionata dalla maggior parte dei libri che ho letto, quindi la mia menzione qui).

Immagina un semplice scenario in cui ho provato a disegnare un quadrato usando 2 triangoli.

Avrei bisogno di avere un set di 6 vertici usando glDrawArraysdurante l'utilizzo glDrawElements, ne avrei bisogno solo 4 oltre a un array di indici che ha 6 elementi.

Considerato quanto sopra, ecco cosa non capisco:

  1. come è possibile glDrawElementssalvare le chiamate di disegno, se è ancora necessario utilizzare l'array di indici (6 indici, nel caso di un quadrato) per indicizzare nel mio array di vertici che aveva 4 elementi (6 volte)? In altre parole, vuol dire che glDrawElementsavrebbe ancora bisogno di un totale di 6 call draw proprio come glDrawArrays?
  2. come sarebbe utilizzare lo glDrawElementsspazio di risparmio, se fosse ancora necessario disporre di 2 array, vale a dire uno per i vertici e uno per gli indici?
  3. Nel caso del disegno di un quadrato da 2 triangoli, per semplicità, quante chiamate di disegno servono glDrawElements(4 elementi in array di vertici e 6 elementi in array di indici) e glDrawArrays(6 elementi solo in array di vertici), individualmente?

Grazie.

Risposte:


16

Ogni glDraw * è un richiamo.

1 glDrawArrays è 1 call draw.
1 glDrawElements è 1 call draw.

Non importa (per quanto riguarda il conteggio delle chiamate di disegno) quanti vertici o indici usi, 1 glDraw * è 1 chiamata di disegno.

I semplici casi di disegno di quad (supponendo che la versione GL che usi non abbia rimosso quad) o triangoli non sono un buon esempio per confrontarli, perché un elenco di quad o un elenco di triangoli può essere disegnato con una sola chiamata a uno, e glDrawArrays appariranno più efficienti perché non hanno l'overhead aggiuntivo dell'indicizzazione.

Prendiamo un caso leggermente più complesso, ma che è rappresentativo di uno scenario più reale. Immagina di avere un modello composto da più strisce triangolari e ventole:

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

In questo esempio, l'utilizzo di glDrawArrays fornisce un totale di 6 chiamate di disegno per il modello. Tuttavia, sia le strisce che i fan possono essere facilmente convertiti in triangoli indicizzati, quindi aggiungi indici e diventa:

glDrawElements (GL_TRIANGLES, .....);

Questa è una chiamata di pareggio, per l'intero modello.


I vantaggi di glDrawElements rispetto a glDrawArrays non sono solo il risparmio di memoria, che è il modo ingenuo di misurarlo. Esiste il potenziale per il salvataggio della memoria in cui i vertici possono essere riutilizzati, poiché un indice è in genere più piccolo di un vertice (quindi anche se si hanno molti indici in bilico saranno più piccoli), ma altri vantaggi includono:

  • Conteggio chiamate di prelievo ridotto. Ogni chiamata di disegno comporta un certo sovraccarico dallo stato di convalida, impostazione delle cose, ecc. E gran parte di questo sovraccarico si verifica sul lato CPU. Riducendo il numero di call draw evitiamo gran parte di questo sovraccarico.

  • Riutilizzo del vertice. Questo è molto più di un semplice risparmio di memoria. La tua GPU probabilmente ha una cache dei vertici hardware, dove possono essere memorizzati vertici trasformati di recente; se lo stesso vertice si ripresenta e se si trova nella cache, può essere riutilizzato dalla cache anziché dover trasformarlo di nuovo. Il tuo hardware controllerà la cache confrontando gli indici, quindi in termini OpenGL l'unico modo per usare la cache è usare glDrawElements.


Quindi, per rispondere alle tue domande specifiche:

  1. come potrebbe glDrawElements salvare le chiamate di disegno ...? Nell'esempio che usi, non lo fa. Ognuno ha un call call. Come discuterò sopra, questo esempio è pessimo per confrontare i due.

  2. in che modo l'utilizzo di glDrawElements consente di risparmiare spazio ...? Perché gli indici sono più piccoli dei vertici. Un indice a 16 bit è di due byte, un vertice position / color / texcoord è di 24 byte. 6 vertici è 144 byte, 4 vertici più 6 indici è 108 byte.

  3. Nel caso di disegnare un quadrato da 2 triangoli ...? Uno e uno. Una chiamata glDraw * è una chiamata di disegno, il numero di vertici o indici utilizzati è irrilevante per questa misurazione. Ma devo ribadire, questo è un pessimo esempio per confrontare i due.


Infine, e solo per complicare un po 'le cose, mentre glDrawElements con i triangoli è il percorso ottimale sulle GPU desktop, sui dispositivi mobili potrebbe essere molto diverso. Alcune GPU mobili potrebbero preferire glDrawArrays con GL_TRIANGLE_STRIP (in questo caso aggiungeresti triangoli degeneri per concatenare le primitive), e non ho nemmeno toccato argomenti più avanzati come il riavvio primitivo o il disegno multiplo.


Grazie mille per il tuo feedback; Sto solo prendendo un po 'di tempo a leggere ciò che hai condiviso. Volevo solo farti sapere che ho riconosciuto la tua risposta. Grazie ancora.
Unheilig,

Nel tuo esempio di conversione di 6 chiamate DrawTriangleFans e DrawTriangleStrips in 1 chiamate DrawTriangles singole. Questo migliora davvero alcune prestazioni? Per la mia comprensione, disegnare una striscia triangolare composta da 100 triangoli è molto più efficiente che disegnare 100 triangoli singolarmente, e il vantaggio compenserebbe facilmente qualsiasi penalità derivante dall'uso di 6 chiamate di funzione piuttosto che da 1.
Samuel Li

@SamuelLi 6-a-1 non sarà un grande miglioramento, ha semplicemente lo scopo di illustrare il principio. Inoltre, e come ho indicato, le strisce non sono in genere prestazioni vincenti rispetto agli elenchi indicizzati sull'hardware desktop post-1998. Controlla la data su qualsiasi documento che ti consiglia di usare le strisce.
Maximus Minimus

Hai capito, grazie per il chiarimento! @MaximusMinimus
Samuel Li
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.