本節描述可用於可程式化數據流模型的著色器。
使用數據流
DirectX 8 引進數據流的概念,以將數據系結至著色器使用的輸入緩存器。 數據流是元件數據的統一數位列,其中每個元件都包含一或多個元素,代表單一實體,例如位置、一般、色彩等等。 串流可讓圖形晶元以平行方式從多個頂點緩衝區執行直接記憶體取,同時從應用程式數據提供更自然的對應。 它們也會啟用簡單多文字與 multipass。 請這樣想一下:
- 頂點是由 n 個數據流所組成。
- 數據流是由 m 元素所組成。
- 元素為 [位置、色彩、一般、紋理座標]。
IDirect3DDevice9::SetStreamSource 方法會將頂點緩衝區系結至裝置數據流,建立頂點數據與數個數據流埠之一之間的關聯,以饋送基本處理函式。 在呼叫繪圖方法,例如 IDirect3DDevice9::D rawPrimitive之前,才會發生數據流數據的實際參考。
輸入頂點元素與可程式化頂點著色器的頂點輸入緩存器的對應是在著色器宣告中定義,但輸入頂點元素沒有其使用的特定語意。 輸入頂點元素的解譯是使用著色器指示進行程序設計。 頂點著色器函式是由套用至每個頂點的指令陣列所定義。 使用著色器函式中的指示,明確寫入頂點輸出緩存器。
不過,對於此討論,較不關心元素的語意對應,而更關心使用數據流的原因,以及使用數據流所解決的問題。 數據流的主要優點是,它們會移除先前與多重文字相關聯的頂點數據成本。 在串流之前,用戶必須有重複的頂點數據集來處理沒有未使用之數據元素的單一和多重文字案例,或攜帶數據元素,但多文本案例除外。
以下是使用兩組頂點數據的範例,一組用於單一紋理,另一組用於多重紋理。
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
};
替代方法是具有包含這兩組紋理座標的單一頂點元素。
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
};
使用此頂點數據時,只有一份位置和色彩數據會攜帶在記憶體中,而代價是將這兩組紋理座標繞在周圍轉譯,即使在單一紋理案例中也是如此。
現在,取捨是明確的,數據流提供了一個優雅的修正這個兩難境地。 以下是一組頂點定義來支援三個數據流:一個具有位置和色彩,一個具有第一組紋理座標,另一個具有第二組紋理座標。
// 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)
頂點宣告如下所示:
// 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()
};
現在建立頂點宣告物件,並將其設定為如下所示:
LPDIRECT3DVERTEXDECLARATION9 m_pVertexDeclaration;
g_d3dDevice->CreateVertexDeclaration(dwDecl3, &m_pVertexDeclaration);
m_pd3dDevice->SetVertexDeclaration(m_pVertexDeclaration);
組合範例
一個數據流擴散色彩
擴散色彩轉譯的頂點宣告和數據流設定看起來會像這樣:
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);
具有色彩和紋理的兩個數據流
單一紋理轉譯的頂點宣告和數據流設定看起來會像這樣:
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);
具有色彩和兩個紋理的兩個數據流
雙紋理多重紋理轉譯的頂點宣告和數據流設定看起來會像這樣:
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));
在每個案例中,下列 IDirect3DDevice9::D rawPrimitive 調用已足夠。
m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLEFAN, 0, NUM_TRIS);
這顯示了串流在解決跨總線的數據重複/備援數據傳輸問題時彈性(也就是浪費頻寬)。
相關主題