DirectX 9.0c遊戲開發手記之RPG編程自學日誌之13: Drawing with DirectX Graphics (用DirectX圖形繪圖)(第6節)

        本文由哈利_蜘蛛俠原創,轉載請註明出處!有問題請聯繫[email protected]

 

        這一次我們繼續來講述Jim Adams老哥的RPG編程書籍第二版第二章的第6節:Alpha Blending,也就是alpha混合。這一節的內容不多,所以就一次性講完吧!

 

        我們先將這一節的各小節的標題列在下面,以供大家參考:

1、 Enabling Alpha Blending (開啓alpha混合)

2、 Drawing with Alpha Blending (alpha混合進行繪圖)

3、 Transparent Blitting with Alpha Testing (alpha測試進行透明的blitting)

4、 Loading Textures with Color Keying (載入帶顏色關鍵字的紋理)

5、 Enabling Alpha Testing (開啓alpha測試)

6、 A Transparent Blitting Example (一個透明的blitting示例)

 

        注意:原書這一節還包括幾個小節關於光照的內容,不過我覺得還是把它們作爲第7節內容講述比較好。當然,這也就意味後面的章節號都有相應的延遲。

 

        原文翻譯:

 

===============================================================================

 

2.6 Alpha混合

 

        想象着站在世界上最高的建築之一上面,走向一個窗口,然後凝視着下面的廣闊的城市。窗戶玻璃的淺藍色色調給了所有東西一種類似於早晨的天空的平靜的着色。

        想象着同樣的場景,但是這次是用3-D圖形的語言。整個世界都是由多邊形構造的,這些多邊形對於所有的實際應用來說都是實心的物體。你不能夠看穿它們。那麼如果你想在你的遊戲中看透一扇窗戶呢?剛纔的那個窗戶給予所有物體一種漂亮的色調的效果呢?

        你想要的酷炫的效果不僅僅是剛纔提到過的, 還有一些叫做透明blits(transparent blits)(也就是,你想要繪製一個一部分是完全透明的多邊形)的東西。

        將繪製一個部分透明(部分透明,是指圖片的一部分是完全透明的,而不是指整個圖片是半透明的)的物體用這樣的術語描述,就是繪製一箇中間有洞的牆。這個洞是完全透明的,儘管這牆是實心的;你穿過洞的視線不會受到阻礙。

        這些效果通過使用一種叫做alpha混合(alpha blending)的技術是可能實現的。使用alpha混合,你可以改變一個多邊形的透明度,使得你可以將它看穿。如果多邊形是上了色的,那麼其顏色將會與該多邊形後面的所有東西進行混合。更奇妙的是,你還可以在這個多邊形上運用紋理來創建一些很牛的效果!

        一個物體的透明度叫做alpha(alpha value)。你也許已經注意到了,Direct3D有好幾種方式來使用alpha值。例如,使用紋理時,你可以設定一個使用alpha值的格式。alpha值被儲存在一個叫做alpha通道(alpha channel)的地方。

 

 

        注意

===============================================================================

        alpha通道是一個很像顏色成分(紅、綠、藍)的值。它設定要運用的透明度,表面上的每一個像素都有自己的一個alpha通道。

        這個alpha通道可以在1位和8位之間變動。如果你有一個8位的alpha通道,你可以設定256個alpha值(從0變動到255)。一個4位的alpha通道使用16個alpha值(0-15)。

===============================================================================

 

2.6.1 Enabling Alpha Blending (啓用alpha混合)

 

        啓用Direct3D 的alpha混合函數很簡單,只要使用IDirect3DDevice9::SetRenderState 函數並設定適當的渲染狀態(render states)就OK了。第一個渲染狀態是D3DRS_ALPHABLENDENABLE,它實際上啓用了alpha混合:

// g_pD3DDevice =pre-initialized 3-D device object
 
// To enablealpha-blending, use:
g_pD3DDevice->SetRenderState(D3DRS_ALPHABLENDENBALE,TRUE);
 
// Set the type ofalpha blending
g_pD3DDevice->SetRenderState(D3DRS_SRCBLEND,                    \
                                             D3DBLEND_SRCALPHA);
g_pD3DDevice->SetRenderState(D3DRS_DESTBLEND,                    \
                                             D3DBLEND_INVSRCALPHA);
 
// To disablealpha-blending, use:
g_pD3DDevice->SetRenderState(D3DRS_ALPHABLENDENBALE,FALSE);

 

        注意到在前面的代碼中還有另外兩個渲染狀態(D3DRS_SRCBLEND和D3DRS_DESTBLEND)。這兩個狀態告訴Direct3D你想要在渲染的時候想要使用alpha的值。有時候,你會看到D3DRS_DESTBLEND值被設爲D3DBLEND_ONE而不是D3DBLEND_INVSRCALPHA。我會在它們出現的時候向你指出來的。

 


2.6.2 Drawing with Alpha Blending (alpha混合進行繪製)

 

        爲了使用alpha混合,你唯一需要的額外的信息是如何將alpha值添加到你的自定義頂點信息之中。你通過增加漫反射顏色成分到自定義頂點結構體和描述器中而實現這一點。當你定義漫反射顏色的時候,你必須設定alpha值。

        下面的例子建立了一個簡單的頂點結構,它儲存了3-D座標和漫反射顏色成分(它現在包含了一個alpha值):

// The custom vertexstructure and descriptor
typedef struct {
  FLOAT    x, y, z;
  D3DCOLOR diffuse;
} sVertex;
#define VertexFVF(D3DFVF_XYZ | D3DFVF_DIFFUSE)
 
// Define 3 verticesin a local array
sVertex Verts = {
  {     0.0f,  100.0f,  0.0f,  D3DCOLOR_RGBA(255, 0, 0, 64)   },
  {   100.0f, -100.0f,  0.0f,  D3DCOLOR_RGBA(0, 255, 0, 128)  },
  { -100.0f,  - 100.0f,  0.0f, D3DCOLOR_RGBA(0, 0, 255, 255)  },
};

 

        第一個頂點設成紅色,並且是1.4半透明的(顏色的1.4會被混合)。第二個頂點是綠色的,使用1.2的半透明度度(顏色的1.2會被混合)。第三個頂點是藍色的,並且是完全不透明的,表示不會有顏色被混合進來。(其實這段話很抽象。反正alpha值位0則表示完全透明,爲255則表示完全不透明啦!)

        如果你增加紋理映射座標,並設置有效的紋理,你可以將漫反射顏色設爲滿值(紅、綠、藍都設爲255),然後設置alpha值來混合紋理。

 


2.6.3 Transparent Blitting with Alpha Testing (alpha測試進行透明的blitting)

 

        alpha測試(alpha testing)是這樣一種技術,它在像素被繪製到顯示屏之前測試其alpha值。

        具有那些不落在某個特定範圍內的alpha值的像素會被拒絕,因此就不會到達渲染階段。跟前一節中獲得半透明效果的方式類似,你可以使用alpha測試來渲染包含完全透明的部分的多邊形。

        使用前一節中的“牆中之洞”的例子,想象牆是一個多邊形,然後你想要在其中心畫一個洞。你想要這個多邊形是完全不透明的(實心的),除了這個洞以外。你想要這個洞是完全透明的。爲了實現這個效果,你使用一種稱爲透明的blit的技術(transparent blit),它使得你可以將一個紋理的某些部分排除掉,這樣允許你可以從這些空洞中窺見背面的圖形。

        透明的blitting的祕密是建立你的紋理,並將單獨的一個顏色設爲顏色關鍵字。顏色關鍵字(color key)是在多邊形被渲染時不會被繪製的顏色。

        比如,如果你有一個紋理,它在中間有一個圓,被黑色所包圍(如圖2.17所示),你可以將顏色關鍵字設爲黑色。當這個紋理被運用到一個多邊形、該多邊形被繪製的時候,Direct3D不會揮着這些黑色的像素,這樣使得只有中間的圓會被渲染。


        在實際應用中,並不是顏色關鍵字標記了透明的像素,而是像素的alpha值。爲了讓一個像素完全透明,它的alpha值必須被設爲0。對於要被繪製的像素,alpha值必須被設爲最高,也就是255。

        正如你可能已經猜到的那樣,與顏色關鍵字匹配的像素具有爲0的alpha值;其他的所有像素具有更高的alpha值。

 

 

2.6.4 Loading Textures with Color Keying (載入帶顏色關鍵字的紋理)

 

        當使用這種方式使用alpha測試的時候,你不需要在你的自定義頂點結構體或者描述器中設定漫反射顏色成分。alpha值直接儲存在了紋理的像素數據中了。爲了設置紋理像素數據中的alpha值,你使用擴展版本的D3DXCreateTextureFromFile函數載入紋理,如下所示:

HRESULT D3DXCreateTextureFromFileEx(
LPDIRECT3DDEVICE9      pDevice, // device object to create with
LPCSTR                pSrcFile, // filename of texture to load
UINT                     Width, // D3DX_DEFAULT
UINT                     Height,// D3DX_DEFAULT
UINT                 MipLevels, // D3DX_DEFAULT
DWORD                     Usage,// 0
D3DFORMAT                Format,// color format to use
D3DPOOL                    Pool,// D3DPOOL_MANAGED
DWORD                   Filter, // D3DX_FILTER_TRIANGLE
DWORD                 MipFilter,// D3DX_FILTER_TRIANGLE
D3DCOLOR              ColorKey, // Color key to use!
D3DXIMAGE_INFO       *pSrcInfo, // NULL
PALETTEENTRY         *pPalette, // NULL
LPDIRECT3DTEXTURE9 *ppTexture); // texture object to create

        大多數參數使用上面顯示的默認參數。你唯一需要提供的東西是要載入的位圖的文件名、在創建紋理時要使用哪個3-D設備對象、在載入紋理時使用的顏色格式(以D3DFMT_開頭的類型,它必須使用一個alpha值,例如D3DFMT_A8R8B8G8)以及顏色關鍵字(以D3DCOLOR的格式)。

        在設定顏色關鍵字的值時,使用D3DCOLOR_RGBA 或D3DCOLOR_COLORVALUE 宏來設定你想要的顏色。例如,如果你想要避免黑色被繪製,那麼使用一個顏色關鍵字來載入紋理:

D3DCOLOR_RGBA(0, 0,0, 255);

        注意alpha 的值爲255。這很重要!在載入位圖文件(.BMP)的時候,你還必須將alpha的值設定爲255。如果你在處理已經包含了alpha通道值的非位圖文件(例如.TGA),你必須將設定的alpha值與儲存在圖像文件中的alpha值相匹配。

        在此書中,我只使用位圖文件,所以只需要記住使用等於255的alpha值。在將紋理的每個像素的alpha值都設定好後,使用alpha測試來基於像素的alpha值對其拒絕就是小意思了。

 


2.6.5 Enabling Alpha Testing (啓用alpha測試)

 

        一旦載入了紋理(並且設置了顏色關鍵字和alpha值),你可以在你初始化時或者渲染循環中添加下列代碼來啓用alpha測試:

// g_pD3DDevice = pre-initialized deviceobject
g_pD3DDevice->SetRenderState(D3DRS_ALPHATESTENABLE,TRUE);
g_pD3DDevice->SetRenderState(D3DRS_ALPHAREF,0x08);
g_pD3DDevice->SetRenderState(D3DRS_ALPHAFUNC,                  \
                                             D3DCMP_GREATEREQUAL);

D3DRS_ALPHAREF 狀態很神奇,因爲它告訴Direct3D允許哪些alpha值(從0到255之間變動)。在剛纔展示的三種函數被調用後,所有的alpha值低於8的像素將會被拒絕。如果你正確地設定了顏色關鍵字,這三個函數會迫使所有具有零值的alpha的紋理從渲染階段中排除掉,這樣就使得它們透明瞭!

 


 

2.6.6 A Transparent Blitting Example (一個透明的Blitting 示例)

 

        已經說夠了;是時候給出一些代碼了!下面是一個載入一個按鈕圖像並將之顯示到屏幕上的小小例子。紋理的黑色像素被拒絕了,這樣就允許背景顏色透出來:

// g_pD3DDevice = pre-initialized deviceobject
// Custom vertex structure and descriptor
typedef struct {
  FLOATx, y, z, rhw; // Screen coordinates
  FLOAT        u, v; // Texture coordinates
} sVertex;
#define VertexFVF (D3DFVF_XYZRHW |D3DFVF_TEX1)
 
// Vertex buffer and texture
IDirect3DVertexBuffer9 *g_pVB = NULL;
IDirect3DTexture9 *g_pTexture = NULL;
// Set up the vertex buffer and texture
// assuming a 400x400 window
BYTE *Ptr;
sVertex Verts[4] = {
  {  0.0f,  0.0f, 0.0f, 1.0f, 0.0f, 0.0f },
  {399.0f,   0.0f, 0.0f, 1.0f, 1.0f, 0.0f },
  {  0.0f, 399.0f, 0.0f, 1.0f, 0.0f, 1.0f },
  {399.0f, 399.0f, 0.0f, 1.0f, 1.0f, 1.0f }
};
 
// Create vertex buffer and stuff in data
g_pD3DDevice->CreateVertexBuffer(sizeof(sVertex)*4,0,                       \
                                VertexFVF,D3DPOOL_MANAGED, &g_pVB, NULL))) {
g_pVB->Lock(0,0, (void**)&Ptr, 0)))
memcpy(Ptr, Verts, sizeof(Verts));
g_pVB->Unlock();
 
// Get texture
D3DXCreateTextureFromFileEx(g_pD3DDevice, “button.bmp”,                           \
                             D3DX_DEFAULT,D3DX_DEFAULT, D3DX_DEFAULT, 0,            \
                             D3DFMT_A8R8G8B8,D3DPOOL_MANAGED, D3DX_FILTER_TRIANGLE, \
                             D3DX_FILTER_TRIANGLE,D3DCOLOR_RGBA(0,0,0,255), NULL,   \
                             NULL,&g_pTexture);
 
// Set alpha testing
g_pD3DDevice->SetRenderState(D3DRS_ALPHATESTENABLE,TRUE);
g_pD3DDevice->SetRenderState(D3DRS_ALPHAREF,0x01);
g_pD3DDevice->SetRenderState(D3DRS_ALPHAFUNC,   \
                             D3DCMP_GREATEREQUAL);
 
// Clear device backbuffer
g_pD3DDevice->Clear(0, NULL,D3DCLEAR_TARGET,             \
                     D3DCOLOR_RGBA(0,128,128,255),1.0f, 0);
if(SUCCEEDED(g_pD3DDevice->BeginScene())){
    //Set stream source to particle vertex buffer
    g_pD3DDevice->SetStreamSource(0,g_pVB, 0, sizeof(sVertex));
    //Set vertex shader to particle type
    g_pD3DDevice->SetFVF(VertexFVF);
    //Set texture
    g_pD3DDevice->SetTexture(0,g_pTexture);
    //Draw vertex buffer
    g_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP,0, 2);
    g_pD3DDevice->EndScene();
    //Clear texture
    g_pD3DDevice->SetTexture(0,NULL);
    //Turn off alpha testing
    g_pD3DDevice->SetRenderState(D3DRS_ALPHATESTENABLE,FALSE);
}
 
// Flip surfaces to display work
g_pD3DDevice->Present(NULL, NULL, NULL,NULL);

===============================================================================

 

        好啦,翻譯完這一節了!下面是時候送上代碼了!跟上次一樣,我將同時送上原書的代碼以及本人更新後的代碼。下面是我的更新版代碼運行時的截圖:


        幾點說明:

1、  更新版代碼在前面的更新版Draw2D基礎上更改而得。

2、  用了兩幅美女圖來讓程序不至於太枯燥。

3、  原書是簡單的帶顏色的頂點組成的兩個長方形,頂點顏色自帶alpha值;而現在用的兩幅圖不帶alpha值,所以如果按照原來的blend factor來寫代碼的話,那麼效果很不理想(大家可以試試),所以我把它換成了另外一種blend factor,效果……還真不錯!

 

最後給出下載地址:

alpha代碼下載地址


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章