遊戲開發基礎(十七)

第十七章

頂點着色器(vertex shader)是一段運行在圖形卡GPU中的程序,可取代固定功能流水線中的變換和光照環節(當然,不是絕對的,在硬件部支持頂點着色器的情況下,Direct3D運行時就會用軟件運算方式來模擬頂點着色器).

頂點着色器其實就是用HLSL語言編寫的一段定製程序,這樣在可實現的圖形效果上就獲得了很大的靈活性,例,藉助頂點着色器,可使用任何可在頂點着色器中實現的光照算法

使用頂點數據結構也更加靈活,而且可編程流水線中的頂點結構可以包含比固定功能流水線更加豐富的數據

頂點着色器是一項比較新的特性,目前許多圖形卡尚不支持該特性,尤其伴隨DirectX 9.0發佈的那些較新的頂點着色器版本,可通過檢查D3DCAPS9結構的成員VertexShaderVersion並與宏D3DVS_VERSION進行比較,來檢測圖形卡是否支持某個頂點着色器版本

檢測過程:

 //if the device's supported version is less than version 2.0
 if (caps.VertexShaderVersion < D3DVS_VERSION(2,0))//主次版本號
  // then vertex shader version 2.0 is not supported on this device
目前D3DXCompileShaderFromFile函數支持的頂點着色器版本爲1.1,2.0和3.0

頂點聲明:
在可編程流水線中,頂點結構甚至可以包含那些超出FVF描述能力的數據,因此,通常使用能力更強,功能更豐富的頂點聲明(vertex declaration)

在可編程流水線中,如果頂點結構可用FVF來描述,仍可使用,但是,這是爲了表示方便,實際上可編程流水線內部,FVF最終被轉換爲頂點聲明。

頂點聲明描述爲一個D3DVERTEXELEMENT9類型的結構數組,該結構數組中的每個元素都描述了頂點結構的一個分量,所以,如果頂點結構具有3個分量(比如位置,法向量,顏色),則相應的頂點聲明級可用一個維數爲3的D3DVERTEXELEMENT9類型的結構數組來描述

typedef struct D3DVERTEXELEMENT9
{
 WORD Stream;//指定與頂點分量關聯的數據流
 WORD Offset;//自頂點數據起始點到特定數據類型相關的數據的字節偏移量
 BYTE Type;//指定數據類型,該參數可取枚舉類型D3DDECLTYPE的任何一個成員,D3DDECLTYPE_FLOAT1浮點類型標    //量,D3DDECLTYPE_FLOAT2浮點類型的2D向量,D3DDECLTYPE_FLOAT3浮點類型的3D向量,D3DDECLTYPE_FLOAT4浮點   //類型的4D向量,D3DDECLTYPE_D3DCOLOR一個被擴展爲RGBA浮點類型顏色向量(r,g,b,a)的D3DCOLOR類型,其顏色  //向量的每個分量都被規範化至區間[0,1]內
 BYTE Method;//指定了網格化(tesselation)方法,該章默認使用D3DDECLMETHOD_DEFAULT來指定
 BYTE Usage;//指定了頂點分量的用途,例,即,某一個分量是作爲位置向量,法向量還是紋理向量等,標識符取自枚舉類    //型D3DDECLUSAHE;
 BYTE UsageIndex;//標識具有同用法的多個頂點分量,用法索引(usage index)是一個位於區間[0,15]內的整數,例,有3   //個頂點分量的用法都爲D3DDECLUSAGE_NORMAL,則可按序將這3個頂點分量的用法索引分別指定爲      //0,1,2,按照這種方式,可通過用法索引表示每個特定的法向量
}D3DVERTEXELEMENT9,*LPD3DVERTEXELEMENT9;

typedef enum D3DDECLUSAGE
{
 D3DDECLUSAGE_POSITION     = 0,//如果一個頂點聲明中具有該標識,則表明該頂點已經經過了變換,並指示圖形卡不要     //將該頂點輸送到頂點處理環節中(變換和光照處理)
 D3DDECLUSAGE_BLENDWEIGHT  = 1,
 D3DDECLUSAGE_BLENDINDICES = 2,
 D3DDECLUSAGE_NORMAL       = 3,
 D3DDECLUSAGE_PSIZE        = 4,//用於指定頂點的點尺寸,該類型主要用於點精靈(point sprite),這樣對每個尺寸進行     //控制
 D3DDECLUSAGE_TEXCOORD     = 5,

 D3DDECLUSAGE_TANGENT      = 6,
 D3DDECLUSAGE_BINORMAL     = 7,
 D3DDECLUSAGE_TESSFACTOR   = 8,
 D3DDECLUSAGE_POSITIONT    = 9,
 D3DDECLUSAGE_COLOR        = 10,
 D3DDECLUSAGE_FOG          = 11,
 D3DDECLUSAGE_DEPTH        = 12,
 D3DDECLUSAGE_SAMPLE       = 13
}D3DDECLUSAGE,*LPD3DECLUSAGE;

按照這種方式,就可通過用法索引表示每個特定的法向量

例:要描述的頂點格式包含了一個位置向量和3個法向量,則相應的頂點聲明可指定爲
 D3DVERTEXELEMENT9 decl{} =
 {
 {0,0,D3DDECLTYPE_FLOAT3,D3DDECLMETHOD_DEFAULT,D3DDECLUSAGE_POSITION,0},
 {0,12,D3DDECLTYPE_FLOAT3,D3DDECLMETHOD_DEFAULT,D3DDECLUSAGE_NORMAL,0},
 {0,24,D3DDECLTYPE_FLOAT3,D3DDECLMETHOD_DEFAULT,D3DDECLUSAGE_NORMAL,1},
 {0,36,D3DDECLTYPE_FLOAT3,D3DDECLMETHOD_DEFAULT,D3DDECLUSAGE_NORMAL,2},
 D3DDECL_END()//初始化D3DVERTEXELEMENT9數組中的最後一個頂點元素
 };


頂點聲明的創建: 將頂點聲明描述爲一個D3DVERTEXELEMENT9類型的數組,就可用如下方法獲得指向接口IDirect3DVertexDeclaration9指針:
HRESULT CreateVertexDeclaration(
    CONST D3DVERTEXELEMENT9* pVertexElements,//指向一個D3DVERTEXELEMENT9類型的結構數組          //描述了要創建的頂點聲明
    IDirect3DVertexDeclaration9** ppDecl//返回指向所創建的IDirect3DVertexDeclaration9接        //口指針
    );

例 :
 IDirect3DVertexDeclaration9* _decl = 0 ;
 hr = _device->CreateVertexDeclaration(decl,&_decl);

靈活頂點格式是一項很有用的特性,在可編程流水線內部它將被轉換爲頂點聲明,所以,直接使用頂點聲明時,無需調用:
 Device->SetFVF(fvf);
而只是調用:
 Device->SetVertexDeclaration(_decl);//_decl是一個指向接口IDirect3DVertexDeclaration的指針

需要一種方式來定義從頂點聲明中的元素到頂點着色器的輸入結構的數據成員的映射,在輸入結構中通過爲每個數據成員指定一種語義(:usage -type[usage-index])來定義這種映射,該語義通過用法類型和用法索引來標識頂點聲明中的每個元素,由數據成員的語義所標識的那個頂點元素就被映射到該數據成員的那個元素
例:與前面提到的那個頂點聲明對用的輸入結構爲:
struct VS_INPUT
{
 vector position:POSITION;
 vector normal  :NORMAL0;
 vector facenormal1  :NORMAL1;
 vector facenormal2  :NORMAL2;
};

如果略去了用法索引,就意味着該索引爲0,例,POSITION含義與POSITION0完全相同

頂點着色器支持的輸入用法包括:
#POSITION[n]位置
#BLENDWEIGHTS[n]位置融合權值(blend weights)
#BLENDINDICES[n]融合索引(blend indices)
#NORMAL[n]法向量
#PSIZE[n]頂點的點尺寸
#DIFFUSE[n]漫反射顏色
#SPECULAR[n]高光顏色(specular color)
#TEXCOORD[n]紋理座標
#TANGENT[n]切向量(tangent vector)
#BINORMAL[n]副法向量(binormal vector)
#TESSFACTOR[n]網格化因子(tessellation factor)
n爲一個可選整數,但必須取自區間[0,15]內

對於輸出結構,必須指定每個成員的用途,例如,該數據成員應看作位置向量,顏色向量,還是紋理座標等,對於各數據成員的用途,圖形卡無從知曉,需要顯示指定,這種指定也是在語義層次實現,例:
 struct VS_OUTPUT
 {
  vector position :POSITION;
  vector diffuse :COLOR0;
  vector specular :COLOR1;
 };

頂點着色器支持的輸出用法包括:
#POSITION[n]位置
#PSIZE[n]頂點的點尺寸
#FOG[n]霧融合值(fog blend value)
#COLOR[n]頂點顏色,注意可輸出多個頂點顏色,這些顏色混合在一起生成最終顏色
#TEXCOORD[n]頂點紋理座標,注意,可能輸出多個頂點紋理座標
n爲一個可選整數,但必須取自區間[0,15]內


使用頂點着色器的步驟:
1 編寫頂點着色器程序,並進行編譯
2 創建一個IDirect3DVertexShader9接口的對象,以表示基於所編譯的着色器代碼的頂點着色器
3 用IDirect3DDevice9::SetVertexShader方法啓用頂點着色器

當頂點着色器使用完畢後,必須進行銷燬


該方法獲取IDirect3DVertexShader9接口指針,該接口代表一個頂點着色器
HRESULT IDirect3DDevice9::CreateVertexShader(
         const DWORD *pFunction,//指向經過編譯的代碼指針,
         IDirect3DVertexShader9** ppShader//指向IDirect3DVertexShader接口的指針
         );

例;變量shader是一個指向ID3DXBuffer接口指針,則獲取指向IDirect3DVertexShader9接口指針:
 IDirect3DVertexShader9* ToonShader = 0 ;
 hr = Device->CreateVertexShader(
     (DWORD*)Shader->GetBufferPointer(),
     &ToonShader);

D3DXCompileShaderFromFile函數能夠返回經過編譯的着色器代碼(對應上面的shader)

該方法啓用頂點着色器
HRESULT IDirect3DDevice9::SetVertexShader(IDirect3DVertexShader9 * pShader);
該方法接收一個單個參數,可將一個指向希望被啓用的頂點着色器的指針賦給該參數
例:
 Device->SetVertexShader(ToonShader);

IDirect3DVertexShader9在使用完畢後,必須調用其自身的Release來釋放資源
例:
 d3d::Release<IDirect3DVertexShader9*>(ToonShader);

發佈了79 篇原創文章 · 獲贊 17 · 訪問量 23萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章