Diferença no glDrawArrays e glDrawElements

12

Enquanto refrescante minha mente em OpenGL ES, me deparei glDrawArrayse glDrawElements.

Eu entendo como eles são usados ​​e meio que entendo por que eles são diferentes.

O que parece que eu não entendo é que, não consigo ver como glDrawElementssalvar chamadas de empate ( salvar chamadas de empate é uma descrição mencionada na maioria dos livros que li, por isso mencionei aqui).

Imagine um cenário simples em que tentei desenhar um quadrado usando 2 triângulos.

Eu precisaria ter um conjunto de 6 vértices usando glDrawArraysenquanto estiver usando glDrawElements, eu precisaria de apenas 4, além de uma matriz de índice que tenha 6 elementos.

Dado o exposto, aqui está o que eu não entendo:

  1. como glDrawElementssalvar chamadas de desenho, se ele ainda precisa usar a matriz de índice (6 índices, no caso de um quadrado) para indexar em minha matriz de vértices que tinha 4 elementos (6 vezes)? Em outras palavras, isso significa glDrawElementsque ainda precisaria ter um total de 6 chamadas iguais glDrawArrays?
  2. como o uso de glDrawElementseconomia de espaço seria necessário se ainda houvesse duas matrizes, a saber, uma para os vértices e outra para os índices?
  3. No caso de desenhar um quadrado a partir de 2 triângulos, para simplificar, quantas chamadas de desenho são necessárias glDrawElements(4 itens na matriz de vértices e 6 itens na matriz de índice) e glDrawArrays(6 itens apenas na matriz de vértices) individualmente?

Obrigado.

Unheilig
fonte

Respostas:

16

Cada glDraw * é uma chamada de empate.

1 glDrawArrays é uma chamada de empate.
1 glDrawElements é uma chamada de empate.

Não importa (no que diz respeito à contagem de chamadas de draw) quantos vértices ou índices você usa, 1 glDraw * é 1 chamada de draw.

Os casos simples de desenhar quads (assumindo que a versão GL usada não removeu quads) ou triângulos não são um bom exemplo para compará-los, porque uma lista de quads ou uma lista de triângulos pode ser desenhada com uma única chamada, e glDrawArrays parecerão mais eficientes porque não possuem a sobrecarga adicional de indexação.

Vamos considerar um caso um pouco mais complexo, mas que é representativo de um cenário mais real. Imagine que você tem um modelo composto por várias tiras de triângulo e ventiladores:

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

Neste exemplo, o uso de glDrawArrays fornece um total de 6 chamadas de desenho para o modelo. No entanto, tiras e ventiladores podem ser facilmente convertidos em triângulos indexados; portanto, adicione índices e ele se tornará:

glDrawElements (GL_TRIANGLES, .....);

Essa é uma chamada de empate, para todo o modelo.


As vantagens do glDrawElements sobre o glDrawArrays são mais do que apenas economia de memória, que é a maneira ingênua de medi-lo. Existe o potencial de economia de memória onde os vértices podem ser reutilizados, porque um índice geralmente é menor que um vértice (portanto, mesmo se você tiver muitos índices em equilíbrio, eles serão menores), mas outras vantagens incluem:

  • Contagem reduzida de chamadas de empate. Cada chamada de desenho incorre em alguma sobrecarga de validação do estado, configuração, etc., e grande parte dessa sobrecarga acontece no lado da CPU. Ao reduzir o número de chamadas de empate, evitamos muito dessa sobrecarga.

  • Reutilização de vértices. Isso é muito mais do que apenas economia de memória. Sua GPU provavelmente possui um cache de vértices de hardware, onde os vértices transformados recentemente podem ser armazenados; se o mesmo vértice entrar novamente e se estiver no cache, ele poderá ser reutilizado a partir do cache, em vez de ter que se transformar novamente. Seu hardware verificará o cache comparando índices, portanto, nos termos do OpenGL, a única maneira de usar o cache é usar o glDrawElements.


Então, para responder suas perguntas específicas:

  1. como o glDrawElements pode salvar chamadas de desenho ...? No exemplo que você usa, não. Cada um tem uma chamada de empate. Como discuti acima, este exemplo é muito ruim para comparar os dois.

  2. como usar glDrawElements economizaria espaço ...? Porque os índices são menores que os vértices. Um índice de 16 bits tem dois bytes, um vértice position / color / texcoord tem 24 bytes. 6 vértices são 144 bytes, 4 vértices mais 6 índices são 108 bytes.

  3. No caso de desenhar um quadrado de 2 triângulos ...? Um e um. Uma chamada glDraw * é uma chamada de compra, o número de vértices ou índices usados ​​é irrelevante para esta medida. Mas devo enfatizar novamente, este é um exemplo muito ruim para comparar os dois.


Finalmente, e apenas para complicar um pouco as coisas, enquanto glDrawElements com triângulos é o caminho ideal nas GPUs de desktop, no celular, pode ser muito diferente. Algumas GPUs móveis podem preferir glDrawArrays com GL_TRIANGLE_STRIP (neste caso, você adicionaria triângulos degenerados para concatenar primitivas), e eu nem sequer toquei em tópicos mais avançados, como reinicialização primitiva ou desenho múltiplo.

Maximus Minimus
fonte
Muito obrigado por seu feedback; Estou demorando um pouco para ler o que você compartilhou. Só queria que você soubesse que reconheci sua resposta. Obrigado novamente.
Unheilig
No seu exemplo de conversão de 6 chamadas DrawTriangleFans e DrawTriangleStrips para uma única chamada DrawTriangles. Isso realmente melhora algum desempenho? Para o meu entendimento desenhar uma tira triângulo composto por 100 triângulos é muito mais eficiente do que o desenho 100 triângulos individualmente, eo benefício seria facilmente compensar qualquer penalidade ocorreu de usar 6 chamadas de função em vez de 1.
Samuel Li
O @SamuelLi 6 para 1 não será uma grande melhoria, apenas pretende ilustrar o princípio. Além disso, e como indiquei, as tiras normalmente não representam uma conquista de desempenho sobre as listas indexadas no hardware de desktop pós-1998. Verifique a data em qualquer documento que o aconselhe a usar tiras.
Maximus Minimus
Entendi, obrigado pelo esclarecimento! @MaximusMinimus
Samuel Li