Condividi tramite


Programmazione di uno o più flussi (Direct3D 9)

Questa sezione descrive gli shader che possono essere usati per il modello di flusso programmabile.

Uso di flussi

DirectX 8 ha introdotto la nozione di un flusso per associare i dati ai registri di input da usare da shader. Un flusso è una matrice uniforme di dati del componente, in cui ogni componente è costituito da uno o più elementi che rappresentano un'unica entità, ad esempio posizione, normale, colore e così via. I flussi consentono ai chip grafici di eseguire un accesso diretto alla memoria da più buffer vertici in parallelo e forniscono anche un mapping più naturale dai dati dell'applicazione. Abilitano anche la multitexture banale rispetto al multipass. Pensa a questo:

  • Un vertice è costituito da n flussi.
  • Un flusso è costituito da m elements.
  • Un elemento è [posizione, colore, normale, coordinata trama].

Il metodo IDirect3DDevice9::SetStreamSource associa un buffer dei vertici a un flusso di dati del dispositivo, creando un'associazione tra i dati del vertice e una delle diverse porte di flusso di dati che generano le funzioni di elaborazione primitiva. I riferimenti effettivi ai dati del flusso non si verificano finché non viene chiamato un metodo di disegno, ad esempio IDirect3DDevice9::D rawPrimitive.

Il mapping degli elementi del vertice di input ai registri di input dei vertici per i vertex shader programmabili è definito nella dichiarazione shader, ma gli elementi del vertice di input non dispongono di semantiche specifiche sull'uso. L'interpretazione degli elementi del vertice di input è programmata usando le istruzioni del shader. La funzione vertex shader è definita da una matrice di istruzioni applicate a ogni vertice. I registri di output dei vertici vengono scritti in modo esplicito, usando istruzioni nella funzione shader.

Per questa discussione, tuttavia, essere meno interessati al mapping semantico degli elementi ai registri e più interessato al motivo dell'uso dei flussi e del problema risolto tramite flussi. Il vantaggio principale dei flussi è che rimuove i costi dei dati dei vertici precedentemente associati al multitexturing. Prima dei flussi, un utente deve duplicare i set di dati dei vertici per gestire il caso singolo e multitexture senza elementi dati inutilizzati o inserire elementi di dati inutilizzati, ad eccezione del caso multitexture.

Ecco un esempio di uso di due set di dati vertex, uno per una trama singola e una per il multitexturing.

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
};

L'alternativa era quella di avere un singolo elemento vertice che contiene entrambi i set di coordinate della trama.

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
};

Con questi dati di vertice, viene eseguita una sola copia dei dati di posizione e colore in memoria, a spese del trasporto di entrambi i set di coordinate della trama intorno per il rendering anche nel caso di trama singola.

Ora che il compromesso è chiaro, i flussi forniscono una soluzione elegante a questo dilemma. Ecco un set di definizioni di vertice per supportare tre flussi: uno con posizione e colore, uno con il primo set di coordinate della trama e uno con il secondo set di coordinate della trama.

// 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)

La dichiarazione del vertice sarà la seguente:

// 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()
};

Creare ora l'oggetto dichiarazione del vertice e impostarlo come illustrato:

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

m_pd3dDevice->SetVertexDeclaration(m_pVertexDeclaration);

Esempi di combinazioni

Colore di diffusione di un flusso

La dichiarazione dei vertici e le impostazioni di flusso per il rendering dei colori diffusi sono simili al seguente:

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);

Due flussi con colore e trama

La dichiarazione del vertice e le impostazioni di flusso per il rendering di trame singole sono simili al seguente:

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);

Due flussi con colore e due trame

La dichiarazione dei vertici e le impostazioni di flusso per il rendering multi-trama a due trame sarà simile al seguente:

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));

In ogni caso, le chiamate IDirect3DDevice9::D rawPrimitive sono sufficienti.

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

In questo modo viene illustrata la flessibilità dei flussi nella risoluzione del problema della trasmissione dei dati/ridondanza dei dati nel bus, ovvero della larghezza di banda di larghezza di banda.

Dichiarazione vertex