(Direct3D 9) 程式設計一或多個資料流程
本節描述可用於可程式化資料流程模型的著色器。
使用資料流程
DirectX 8 引進了資料流程的概念,以將資料系結至輸入暫存器,以供著色器使用。 資料流程是元件資料的統一陣列,其中每個元件都包含一或多個元素,代表單一實體,例如位置、標準、色彩等等。 串流可讓圖形晶片以平行方式從多個頂點緩衝區執行直接記憶體存取,也提供更自然的應用程式資料對應。 它們也會啟用 trivial multitexture 與 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);
這顯示資料流程在解決跨匯流排 (傳輸資料重複/備援資料傳輸問題時的彈性,也就是浪費頻寬) 。
相關主題