Microsoft® DirectX® 8.0引入了數據流的概念,用來把數據綁定到着色器使用的輸入寄存器。一個數據流是一個成員數據的數組,每個成員由一個或多個元素構成,這些元素代表單個實體,如位置、法向、顏色等等。數據流使圖形芯片能並行地從多個頂點緩存執行直接內存訪問(DMA)操作,同時也降低了多重紋理的開銷。可以這樣理解數據流:
一個頂點由n個數據流組成。
一個數據流由m個元素組成。
一個元素是[位置、顏色、法向、紋理座標]。
IDirect3DDevice9::SetStreamSource方法把一個頂點緩存綁定到一個設備數據流,這樣就在頂點數據和一個頂點數據流端口之間建立了聯繫,有多個數據流端口用來給圖元處理函數輸入數據。對數據流中的數據的真正引用只有在調用諸如IDirect3DDevice9::DrawPrimitive之類的繪製方法時才發生,中國自學編程網,www.zxbc.cn 。
從輸入頂點元素到可編程頂點着色器使用的頂點輸入寄存器的映射是在着色器聲明中定義的,但是輸入頂點元素並沒有專門的語義來描述它們的使用。對輸入頂點元素的解釋通過着色器指令進行編程。頂點着色器函數由一個指令數組定義,這些指令會應用於每個頂點。頂點輸出寄存器用着色器函數中的指令顯式地寫入。
本節的討論較少關注從元素到寄存器的語義映射,而更側重於“爲什麼要使用數據流?”和“數據流可以解決什麼問題?”這些問題。數據流的最大好處是消除了原來和多重紋理有關的頂點數據的開銷。在引入數據流之前,爲了處理單紋理和多重紋理的情況,用戶要麼複製兩份頂點數據,每份頂點數據中都沒有用不到的數據;要麼在一份頂點數據中包含所有的數據元素,但其中一部分數據除了多重紋理的情況以外不會被用到。
這裏是一個使用兩份頂點數據的示例,一份用於單紋理,另一份用於多重紋理。
struct CUSTOMVERTEX_TEX1
{
FLOAT x, y, z; // 未經變換的頂點位置
DWORD diffColor; // 頂點的漫反射色
DWORD specColor; // 頂點的鏡面反射色
float tu_1, tv_1; // 單紋理的紋理座標
};
struct CUSTOMVERTEX_TEX2
{
FLOAT x, y, z; // 未經變換的頂點位置
DWORD diffColor; // 頂點的漫反射色
DWORD specColor; // 頂點的鏡面反射色
float tu_2, tv_2; // 多重紋理的紋理座標
};
另一種方法是在一個頂點元素中包含全部兩組紋理座標。
struct CUSTOMVERTEX_TEX2
{
FLOAT x, y, z; // 未經變換的頂點位置
DWORD diffColor; // 頂點的漫反射色
DWORD specColor; // 頂點的鏡面反射色
float tu_1, tv_1; // 單紋理的紋理座標
float tu_2, tv_2; // 多重紋理的紋理座標
};
如果使用這份頂點數據,那麼只要在內存中保存一份頂點和顏色數據,代價是在渲染過程中保存了全部兩組紋理座標,甚至在單紋理的情況下也是如此。
現在這其中的權衡已經很清楚了,數據流爲這種左右爲難的情況提供了一種極好的解決方案。這裏提供了一套頂點定義,用來支持三個數據流:一個數據流包含位置和顏色,一個數據流包含第一組紋理座標,另一個數據流包含第二組紋理座標。
// 多數據流頂點
// 數據流0, 位置, 漫反射色, 鏡面反射色
struct POSCOLORVERTEX
{
FLOAT x, y, z;
DWORD diffColor, specColor;
};
#define D3DFVF_POSCOLORVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_SPECULAR)
// 數據流1, 紋理座標組0
struct TEXC0VERTEX
{
FLOAT tu1, tv1;
};
#define D3DFVF_TEXC0VERTEX (D3DFVF_TEX1)
// 數據流2, 紋理座標組1
struct TEXC1VERTEX
{
FLOAT tu2, tv2;
};
#define D3DFVF_TEXC1VERTEX (D3DFVF_TEX0)
頂點定義爲:
// 多重紋理 – 多重數據流
D3DVERTEXELEMENT9 dwDecl3[] =
{
{ 0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
{ 0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0 },
{ 0, 28, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 1 },
{ 1, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 },
{ 2, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 },
D3DDECL_END()
};
現在創建頂點聲明對象,如下所示:
LPDIRECT3DVERTEXDECLARATION9 m_pVertexDeclaration;
g_d3dDevice->CreateVertexDeclaration( dwDecl3, m_pVertexDeclaration );
組合的示例
一個數據流,只使用漫反射色
只用漫反射色渲染的頂點聲明和數據流設置看起來會如下所示:
D3DVERTEXELEMENT9 dwDecl3[] =
{
{ 0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
{ 0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0 },
{ 0, 28, 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, 28, 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, 28, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 1 },
{ 1, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 },
{ 2, 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, m_pVBTexC1, 0, sizeof(TEXC1VERTEX) );
以上所有三種情況,都可以調用以下IDirect3DDevice9::DrawPrimitive。
m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLEFAN, 0, NUM_TRIS );
這個例子顯示了數據流在解決重複的數據/冗餘數據在總線上的傳輸(也就是說,帶寬的浪費)問題上的靈活性。
本文來自: 中國自學編程網(www.zxbc.cn) 詳細出處參考:http://www.zxbc.cn/html/20071116/29530_4.html