Programação de 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 associar dados a registros de entrada para uso por sombreadores. Um fluxo é uma matriz uniforme de dados de componente, em que 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 executem um acesso direto à memória de vários buffers de vértice em paralelo e também forneçam um mapeamento mais natural dos dados do aplicativo. Eles também habilitam multitextura trivial versus multipasso. Pense assim:
- Um vértice é composto por n fluxos.
- Um fluxo é composto por elementos m.
- Um elemento é [posição, cor, normal, coordenada de textura].
O método IDirect3DDevice9::SetStreamSource associa um buffer de vértice a um fluxo de dados do 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 do 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 gravados explicitamente, usando instruções na função de sombreador.
Para essa discussão, porém, esteja menos preocupado com o mapeamento semântico de elementos para registros e mais preocupado com o motivo do uso de fluxos e qual problema é resolvido usando fluxos. O main benefício dos fluxos é que eles removem os custos de dados de vértice anteriormente associados à multitexção. Antes dos fluxos, um usuário precisava duplicar conjuntos de dados de vértice para lidar com o caso de multitextura única e sem elementos de dados não utilizados ou carregar elementos de dados que não seriam utilizados, exceto no caso de multitextura.
Aqui está um exemplo de como usar dois conjuntos de dados de vértice, um para textura única e outro para multitextaçã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 continha os dois 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, em detrimento de carregar os dois conjuntos de coordenadas de textura para renderização mesmo no caso de textura única.
Agora que a compensação é clara, os fluxos fornecem uma correção elegante para esse dilema. Aqui está um conjunto de definições de vértice para dar suporte a três fluxos: um com posição e cor, um com o primeiro conjunto de coordenadas de textura e outro 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 conforme mostrado:
LPDIRECT3DVERTEXDECLARATION9 m_pVertexDeclaration;
g_d3dDevice->CreateVertexDeclaration(dwDecl3, &m_pVertexDeclaration);
m_pd3dDevice->SetVertexDeclaration(m_pVertexDeclaration);
Exemplos de combinações
Cor difusa de um fluxo
As configurações de declaração de vértice e fluxo para renderização de cores difusas 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
As configurações de declaração de vértice e 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
As configurações de declaração de vértice e fluxo para renderização de várias texturas de duas texturas seriam semelhantes a esta:
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, as seguintes invocações IDirect3DDevice9::D rawPrimitive são suficientes.
m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLEFAN, 0, NUM_TRIS);
Isso mostra a flexibilidade dos fluxos na resolução do problema de duplicação de dados/transmissão de dados redundantes no barramento (ou seja, de desperdiçar largura de banda).
Tópicos relacionados