Renderização de buffers de vértice e índice (Direct3D 9)

Os métodos de desenho indexados e não indexados têm suporte do Direct3D. Os métodos indexados usam um único conjunto de índices para todos os componentes de vértice. Os dados de vértice são armazenados em buffers de vértice e os dados de índice são armazenados em buffers de índice. Veja abaixo alguns cenários comuns para desenhar primitivos usando buffers de vértice e índice.

Estes exemplos comparam o uso de IDirect3DDevice9::D rawPrimitive e IDirect3DDevice9::D rawIndexedPrimitive

Cenário 1: Desenhando dois triângulos sem indexação

Digamos que você queira desenhar o quadriciclo mostrado na ilustração a seguir.

ilustração de um quadrado que consiste em dois triângulos

Se você usar o tipo primitivo Lista de Triângulos para renderizar os dois triângulos, cada triângulo será armazenado como 3 vértices individuais, resultando em um buffer de vértice semelhante à ilustração a seguir.

diagrama de um buffer de vértice que define três vértices para dois triângulos

A chamada de desenho é muito simples; começando no local 0 dentro do buffer de vértice, desenhe dois triângulos. Se o abate estiver habilitado, a ordem dos vértices será importante. Este exemplo pressupõe o estado padrão de abate no sentido anti-horário, portanto, triângulos visíveis devem ser desenhados em ordem no sentido horário. O tipo primitivo Lista de Triângulos simplesmente lê três vértices em ordem linear do buffer para cada triângulo, portanto, essa chamada desenhará triângulos (0, 1, 2) e (3, 4, 5):

DrawPrimitive( D3DPT_TRIANGLELIST, // PrimitiveType
               0,                  // StartVertex
               2 );                // PrimitiveCount

Cenário 2: Desenhando dois triângulos com indexação

Como você observará, o buffer de vértice contém dados duplicados nos locais 0 e 4, 2 e 5. Isso faz sentido porque os dois triângulos compartilham dois vértices comuns. Esses dados duplicados são um desperdício e o buffer de vértice pode ser compactado usando um buffer de índice. Um buffer de vértice menor reduz a quantidade de dados de vértice que precisam ser enviados para o adaptador gráfico. Ainda mais importante, o uso de um buffer de índice permite que o adaptador armazene vértices em um cache de vértice; se o primitivo que está sendo desenhado contiver um vértice usado recentemente, esse vértice poderá ser buscado do cache em vez de lê-lo do buffer de vértice, o que resulta em um grande aumento de desempenho.

Um buffer de índice 'indexes' no buffer de vértice para que cada vértice exclusivo precise ser armazenado apenas uma vez no buffer de vértice. O diagrama a seguir mostra uma abordagem indexada para o cenário de desenho anterior.

diagrama de um buffer de índice para o buffer de vértice anterior

O buffer de índice armazena valores de Índice de VB, que fazem referência a um vértice específico dentro do buffer de vértice. Um buffer de vértice pode ser considerado como uma matriz de vértices, portanto, o Índice de VB é simplesmente o índice no buffer de vértice para o vértice de destino. Da mesma forma, um Índice IB é um índice no buffer de índice. Isso pode ficar muito confuso muito rapidamente se você não tiver cuidado, portanto, certifique-se de que está claro sobre o vocabulário que está sendo usado: índice de valores de índice VB no buffer de vértice, índice de valores de índice IB no buffer de índice e o próprio buffer de índice armazena valores de índice VB.

A chamada de desenho é mostrada abaixo. Os significados de todos os argumentos são discutidos longamente para o próximo cenário de desenho; por enquanto, basta observar que essa chamada está novamente instruindo o Direct3D a renderizar uma lista de triângulos que contém dois triângulos, começando no local 0 dentro do buffer de índice. Essa chamada desenhará os mesmos dois triângulos exatamente na mesma ordem de antes, garantindo uma orientação adequada no sentido horário:

   
DrawIndexedPrimitive( D3DPT_TRIANGLELIST, // PrimitiveType
                    0,                  // BaseVertexIndex
                    0,                  // MinIndex
                    4,                  // NumVertices
                    0,                  // StartIndex
                    2 );                // PrimitiveCount

Cenário 3: Desenhando um triângulo com indexação

Finja agora que deseja desenhar apenas o segundo triângulo, mas deseja usar o mesmo buffer de vértice e buffer de índice que são usados ao desenhar o quad inteiro, conforme mostrado no diagrama a seguir.

diagrama do buffer de índice e do buffer de vértice para o segundo triângulo

Para essa chamada de desenho, o primeiro Índice IB usado é 3; esse valor é chamado de StartIndex. O índice de VB mais baixo usado é 0; esse valor é chamado de MinIndex. Embora apenas três vértices sejam necessários para desenhar o triângulo, esses três vértices são distribuídos em quatro locais adjacentes no buffer de vértice; o número de locais dentro do bloco contíguo de memória de buffer de vértice necessário para a chamada de desenho é chamado numVertices e será definido como 4 nesta chamada. Os valores MinIndex e NumVertices são realmente apenas dicas para ajudar o Direct3D a otimizar o acesso à memória durante o processamento de vértice de software e podem simplesmente ser definidos para incluir todo o buffer de vértice ao preço do desempenho.

Aqui está a chamada de desenho para o caso de triângulo único; O significado do argumento BaseVertexIndex será explicado a seguir:

   
DrawIndexedPrimitive( D3DPT_TRIANGLELIST, // PrimitiveType
                    0,                  // BaseVertexIndex
                    0,                  // MinIndex
                    4,                  // NumVertices
                    3,                  // StartIndex
                    1 );                // PrimitiveCount

Cenário 4: Desenhando um triângulo com indexação de deslocamento

BaseVertexIndex é um valor que é efetivamente adicionado a cada índice de VB armazenado no buffer de índice. Por exemplo, se tivéssemos passado um valor de 50 para BaseVertexIndex durante a chamada anterior, isso seria funcionalmente o mesmo que usar o buffer de índice no diagrama a seguir durante a chamada DrawIndexedPrimitive:

diagrama de um buffer de índice com um valor de 50 para basevertexindex

Esse valor raramente é definido como algo diferente de 0, mas pode ser útil se você quiser desacoplar o buffer de índice do buffer de vértice: se ao preencher o buffer de índice para uma malha específica, o local da malha dentro do buffer de vértice ainda não for conhecido, você poderá simplesmente fingir que os vértices de malha estarão localizados no início do buffer de vértice; quando chegar a hora de fazer a chamada de desenho, basta passar o local inicial real como BaseVertexIndex.

Essa técnica também pode ser usada ao desenhar várias instâncias de uma malha usando um único buffer de índice; por exemplo, se o buffer de vértice contiver duas malhas com ordem de desenho idêntica, mas vértices ligeiramente diferentes (talvez cores difusas ou coordenadas de textura diferentes), ambas as malhas poderão ser desenhadas usando valores diferentes para BaseVertexIndex. Levando esse conceito um passo adiante, você pode usar um buffer de índice para desenhar várias instâncias de uma malha, cada uma contida em um buffer de vértice diferente, simplesmente pedalando qual buffer de vértice está ativo e ajustando o BaseVertexIndex conforme necessário. Observe que o valor BaseVertexIndex também é adicionado automaticamente ao argumento MinIndex, o que faz sentido quando você vê como ele é usado:

Finja agora que queremos desenhar novamente apenas o segundo triângulo do quad usando o mesmo buffer de índice que antes; no entanto, um buffer de vértice diferente está sendo usado no qual o quad está localizado no Índice de VB 50. A ordem relativa dos vértices quad permanece inalterada, apenas o local inicial dentro do buffer de vértice é diferente. O buffer de índice e o buffer de vértice seriam semelhantes ao diagrama a seguir.

diagrama do buffer de índice e do buffer de vértice com um índice vb de 50

Aqui está a chamada de desenho apropriada; Observe que BaseVertexIndex é o único valor que foi alterado em relação ao cenário anterior:

   
DrawIndexedPrimitive( D3DPT_TRIANGLELIST, // PrimitiveType
                    50,                 // BaseVertexIndex
                    0,                  // MinIndex
                    4,                  // NumVertices
                    3,                  // StartIndex
                    1 );                // PrimitiveCount

Renderizando primitivos