Partilhar via


Programando um ou mais fluxos (Direct3D 9)

Esta seção descreve sombreadores que podem ser usados para o modelo de fluxo programável.

Usando fluxos

O DirectX 8 introduziu a noção de um fluxo para vincular dados a registros de entrada para uso por sombreadores. Um fluxo é uma matriz uniforme de dados de componentes, onde cada componente consiste em um ou mais elementos que representam uma única entidade, como posição, normal, cor e assim por diante. Os fluxos permitem que os chips gráficos realizem um acesso direto à memória a partir de vários buffers de vértice em paralelo e também fornecem um mapeamento mais natural a partir dos dados do aplicativo. Eles também permitem multitextura trivial versus multipass. Pense nisso assim:

  • Um vértice é composto por n fluxos.
  • Um fluxo é composto de elementos m.
  • Um elemento é [posição, cor, normal, coordenada de textura].

O método IDirect3DDevice9::SetStreamSource vincula um buffer de vértice a um fluxo de dados de dispositivo, criando uma associação entre os dados de vértice e uma das várias portas de fluxo de dados que alimentam as funções de processamento primitivas. As referências reais aos dados de fluxo não ocorrem até que um método de desenho, como IDirect3DDevice9::D rawPrimitive, seja chamado.

O mapeamento dos elementos de vértice de entrada para os registros de entrada de vértice para sombreadores de vértice programáveis é definido na declaração de sombreador, mas os elementos de vértice de entrada não têm semântica específica sobre seu uso. A interpretação dos elementos de vértice de entrada é programada usando as instruções do sombreador. A função de sombreador de vértice é definida por uma matriz de instruções que são aplicadas a cada vértice. Os registros de saída de vértice são explicitamente gravados, usando instruções na função de sombreador.

Para esta discussão, porém, esteja menos preocupado com o mapeamento semântico de elementos para registros e mais preocupado com a razão do uso de fluxos e qual problema é resolvido usando fluxos. O principal benefício dos fluxos é que eles removem os custos de dados de vértice anteriormente associados à multitexturização. Antes dos fluxos, um usuário tinha que duplicar conjuntos de dados de vértice para lidar com o caso único e multitextura sem elementos de dados não utilizados, ou transportar elementos de dados que não seriam usados, exceto no caso de multitextura.

Aqui está um exemplo de uso de dois conjuntos de dados de vértice, um para textura única e outro para multitexturização.

struct CUSTOMVERTEX_TEX1
{
    FLOAT x, y, z;      // The untransformed position for the vertex
    DWORD diffColor;    // The vertex diffuse color    
    DWORD specColor;    // The vertex specular color
    float tu_1, tv_1;   // Texture coordinates for a single texture
};
 
struct CUSTOMVERTEX_TEX2
{
    FLOAT x, y, z;      // The untransformed position for the vertex
    DWORD diffColor;    // The vertex diffuse color    
    DWORD specColor;    // The vertex specular color
    float tu_2, tv_2;   // Texture coordinates for multitexturing
};

A alternativa era ter um único elemento de vértice que contivesse ambos os conjuntos de coordenadas de textura.

struct CUSTOMVERTEX_TEX2
{
    FLOAT x, y, z;      // The untransformed position for the vertex
    DWORD diffColor;    // The vertex diffuse color    
    DWORD specColor;    // The vertex specular color
    float tu_1, tv_1;   // Texture coordinates for a single texture
    float tu_2, tv_2;   // Texture coordinates for multitexturing
};

Com esses dados de vértice, apenas uma cópia dos dados de posição e cor são transportados na memória, às custas de carregar ambos os conjuntos de coordenadas de textura para renderização, mesmo no caso de textura única.

Agora que o compromisso está claro, os fluxos fornecem uma solução elegante para esse dilema. Aqui está um conjunto de definições de vértice para suportar três fluxos: um com posição e cor, um com o primeiro conjunto de coordenadas de textura e um com o segundo conjunto de coordenadas de textura.

// Multistream vertex
// Stream 0, pos, diffuse, specular
struct POSCOLORVERTEX
{
    FLOAT x, y, z;
    DWORD diffColor, specColor;
};
#define D3DFVF_POSCOLORVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_SPECULAR)
// Stream 1, tex coord 0
struct TEXC0VERTEX
{
    FLOAT tu1, tv1;
};
#define D3DFVF_TEXC0VERTEX (D3DFVF_TEX1)

// Stream 2, tex coord 1
struct TEXC1VERTEX
{
    FLOAT tu2, tv2;
};
#define D3DFVF_TEXC1VERTEX (D3DFVF_TEX0)

A declaração de vértice seria a seguinte:

// Multitexture - multistream

D3DVERTEXELEMENT9 dwDecl3[] = 
{
    {0, 0,  D3DDECLTYPE_FLOAT3,   D3DDECLMETHOD_DEFAULT, 
                                      D3DDECLUSAGE_POSITION, 0},
    {0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, 
                                      D3DDECLUSAGE_COLOR, 0},
    {0, 16, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, 
                                      D3DDECLUSAGE_COLOR, 1},
    {1,  0, D3DDECLTYPE_FLOAT2,   D3DDECLMETHOD_DEFAULT, 
                                      D3DDECLUSAGE_TEXCOORD, 0},
    {2,  0, D3DDECLTYPE_FLOAT2,   D3DDECLMETHOD_DEFAULT, 
                                      D3DDECLUSAGE_TEXCOORD, 1},
    D3DDECL_END()
};

Agora crie o objeto de declaração de vértice e defina-o como mostrado:

LPDIRECT3DVERTEXDECLARATION9 m_pVertexDeclaration;
g_d3dDevice->CreateVertexDeclaration(dwDecl3, &m_pVertexDeclaration);

m_pd3dDevice->SetVertexDeclaration(m_pVertexDeclaration);

Exemplos de combinações

Uma cor difusa de fluxo

A declaração de vértice e as configurações de fluxo para renderização de cores difusa teriam esta aparência:

D3DVERTEXELEMENT9 dwDecl3[] = 
{
    {0,  0,  D3DDECLTYPE_FLOAT3,   D3DDECLMETHOD_DEFAULT, 
                                      D3DDECLUSAGE_POSITION, 0},
    {0, 12,  D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, 
                                      D3DDECLUSAGE_COLOR, 0 ,
    {0, 16,  D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, 
                                      D3DDECLUSAGE_COLOR, 1},
    D3DDECL_END()
};
   m_pd3dDevice->SetStreamSource(0, m_pVBVertexShader0, 0,
                                      sizeof(CUSTOMVERTEX));
   m_pd3dDevice->SetStreamSource(1, NULL, 0, 0);
   m_pd3dDevice->SetStreamSource(2, NULL, 0, 0);

Dois fluxos com cor e textura

A declaração de vértice e as configurações de fluxo para renderização de textura única teriam esta aparência:

D3DVERTEXELEMENT9 dwDecl3[] = 
{
    {0, 0,  D3DDECLTYPE_FLOAT3,   D3DDECLMETHOD_DEFAULT, 
                                      D3DDECLUSAGE_POSITION, 0},
    {0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, 
                                      D3DDECLUSAGE_COLOR, 0},
    {0, 16, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, 
                                      D3DDECLUSAGE_COLOR, 1},

    {1,  0, D3DDECLTYPE_FLOAT2,   D3DDECLMETHOD_DEFAULT, 
                                      D3DDECLUSAGE_TEXCOORD, 0},

    D3DDECL_END()
};
   m_pd3dDevice->SetStreamSource(0, m_pVBPosColor, 0,
                                           sizeof(POSCOLORVERTEX));
   m_pd3dDevice->SetStreamSource(1, m_pVBTexC0, 0,
                                           sizeof(TEXC0VERTEX));
   m_pd3dDevice->SetStreamSource(2, NULL, 0, 0);

Dois fluxos com cor e duas texturas

A declaração de vértice e as configurações de fluxo para renderização multitextura de duas texturas teriam esta aparência:

D3DVERTEXELEMENT9 dwDecl3[] = 
{
    {0, 0,  D3DDECLTYPE_FLOAT3,   D3DDECLMETHOD_DEFAULT, 
                                      D3DDECLUSAGE_POSITION, 0},
    {0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, 
                                      D3DDECLUSAGE_COLOR, 0},
    {0, 16, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, 
                                      D3DDECLUSAGE_COLOR, 1},

    {1,  0, D3DDECLTYPE_FLOAT2,   D3DDECLMETHOD_DEFAULT, 
                                      D3DDECLUSAGE_TEXCOORD, 0},

    {2,  0, D3DDECLTYPE_FLOAT2,   D3DDECLMETHOD_DEFAULT, 
                                      D3DDECLUSAGE_TEXCOORD, 1},
    
    D3DDECL_END()
};
 
m_pd3dDevice->SetStreamSource(0, m_pVBPosColor, 0, 
                                          sizeof(POSCOLORVERTEX));
m_pd3dDevice->SetStreamSource(1, m_pVBTexC0, 0, 
                                          sizeof(TEXC0VERTEX));
m_pd3dDevice->SetStreamSource(2, m_pVBTexC1, 0, 
                                          sizeof(TEXC1VERTEX));

Em todos os casos, o seguinte IDirect3DDevice9::D rawPrimitive invocação é suficiente.

       m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLEFAN, 0, NUM_TRIS);

Isso mostra a flexibilidade dos fluxos na resolução do problema da duplicação de dados/transmissão redundante de dados através do barramento (ou seja, de desperdício de largura de banda).

Declaração Vertex