天天看點

8.3 初步了解 Texture Alpha

引入

(1)上篇中學習了Alpha混合技術,其中涉及到頂點Alpha和材質Alpha兩種。但是Alpha還有一種來源就是紋理(Texture)。另外,通過借助紋理的Alpha值,可以實作紋理的透明效果,這讓遊戲世界變得更有趣、更逼真!

(2)然而,這裡雖然仍是學習Alpha混合,但是涉及到的是紋理Alpha的混合方式,這使得Alpha混合變得不再單純,并且更加複雜!因為紋理就是一個尤其複雜的主題,想想最多可以設定8個紋理層就能感受的到,僅紋理的渲染狀态的選擇就夠讓我們手忙腳亂的,可選的枚舉值大概有二十個。是以這裡我們先初步了解紋理Alpha混合的使用,更複雜的内容将在後續文章中逐漸展開。

Texture Alpha混合中像素Alpha值的形成

當對物體表面使用了紋理之後,像素Alpha值就是紋理Alpha混合之後的值,是以這又取決于紋理的Alpha混合方法,紋理Alpha混合方法決定了紋理Alpha混合之後的Alpha值是取自材料還是取自紋理,或者取自兩者的某種運算。

像素的Alpha值的具體計算過程是這樣的,首先得到頂點Alpha值,頂點Alpha值可能是直接指定的,也可能是光照計算得到的,然後根據着色模式對頂點Alpha值進行插值,得到的結果再根據紋理Alpha混合方法和紋理采樣得到的Alpha值進行指定的運算,得到最終每個像素的Alpha的值。其中,紋理的混合方法與之前紋理顔色的混合方法基本相同,差別是紋理Alpha混合的結果是像素的Alpha值,紋理顔色混合的結果是像素顔色的RGB值。

“紋理階段混合狀态”

紋理映射本質上是從紋理中擷取顔色值,然後應用到物體的表面,多層紋理映射本質上就是混合多層紋理的顔色,然後應用到物體的表面。為了處理上的友善,Direct3D将顔色的RGB通道和Alpha通道分别進行處理,具體的操作方法通過紋理階段混合狀态進行設定。也即紋理階段混合狀态用于指定目前紋理階段(總共有八個階段,即Stage0到Stage7)紋理顔色值和Alpha值的混合方法。

由于紋理混合對RGB顔色值混合和Alpha值混合是分别處理的,是以本節隻讨論紋理的Alpha值混合,RGB顔色值混合在之後的文章中介紹,并且本節中隻涉及1層(即第0層)紋理,是以相對好了解的多!

我們分幾個步驟來介紹“紋理階段混合狀态”的設定方法:

(1)LPDIRECT3DDEVICE9::SetTextureStageState()函數的使用

(2)設定紋理渲染狀态

(3)設定紋理渲染狀态值

(4)“紋理混合狀态”與紋理的Alpha混合

(1)LPDIRECT3DDEVICE9::SetTextureStageState()函數的使用

紋理混合狀态由LPDIRECT3DDEVICE9::SetTextureStageState()設定,該函數的聲明如下:

HRESULT SetTextureStageState() {
    DWORD Stage,
    D3DTEXTURESTAGESTATETYPE Type,
    DWORD Value
};
           
8.3 初步了解 Texture Alpha

(2)設定紋理渲染狀态

渲染狀态是上面函數的第二個參數,通過設定渲染狀态可以控制紋理的混合模式,如指定紋理顔色值的混合方法還是Alpha值的混合方法;也可以設定相關混合的參數,如指定Alpha值混合的第一個參數(Arg1)和第二個參數(Arg2)。

枚舉類型D3DTEXTURESTAGESTATETYPE的定義為:

8.3 初步了解 Texture Alpha

下面是枚舉類型D3DTEXTURESTAGESTATETYPE的詳細說明:

8.3 初步了解 Texture Alpha

不要為此感到驚訝,畢竟最多可以有八層紋理!雖然有如此衆多的可選項,但是還記的我們本節的主題嗎,我們關心的紋理Alpha值的混合狀态設定,為此我們隻設定D3DTSS_ALPHAOP、D3DTSS_ALPHAARG1和D3DTSS_ALPHAARG2即可。下面我們來詳細介紹一下這三個選項。

(1)D3DTSS_ALPHAOP的含義是:指定紋理層Alpha值混合方法,Vlaue值屬于D3DTEXTUREOP枚舉類型。

(2)D3DTSS_ALPHAARG1的含義是:Alpha混合的第一個參數,Value屬于D3DTA類型常量預設為D3DTA_TEXTURE,即紋理Alpha值

(3)D3DTSS_ALPHAARG2的含義是:Alpha混合的第二個參數,Value屬于D3DTA類型常量,預設為D3DTA_CURRENT,即前一個紋理層的輸出Alpha值,當Stage=0時,Value值為D3DTA_DIFFUSE,即像素的漫反射Alpha值

解釋:

通過這三個參數,我們指定了一個紋理Alpha混合的公式:

8.3 初步了解 Texture Alpha
即括号中的兩個參數通過指定的運算來得出目前階段紋理的Alpha,然後傳給下一個階段,并将最終的Alpha值表現到顯示器上。

剩下的就是設定這些選項的值了,接下來我們隻介紹本節中我們使用到的3個選項的值的設定。

(3)設定紋理渲染狀态值

我們的任務是設定3個與紋理Alpha混合相關選項的值,再重複一遍,分别是:D3DTSS_ALPHAOP,D3DTSS_ALPHAARG1和D3DTSS_ALPHAARG2。

通過上面的表格,我們知道D3DTSS_ALPHAOP的值取自D3DTEXTUREOP枚舉值,下面是D3DTEXTUREOP的定義:

8.3 初步了解 Texture Alpha

這僅供欣賞,具體的注釋及含義可以檢視源碼檔案和官方手冊。我們本節執行個體示例中使用的相關設定是:

8.3 初步了解 Texture Alpha

運算方式,我們選擇了D3DTOP_MODULATE,它的含義是:

8.3 初步了解 Texture Alpha

即将所提供的兩個參數的Alpha值相乘;第一個參數我們設定為D3DTA_TEXTURE,即指定其Alpha值來源于紋理;第二個參數我們設定為D3DTA_DIFFUSE,即像素的漫反射顔色值。其實此處隻有一個紋理階段(即Stage0),即使我們不顯式的指定,預設值也是像素的漫反Alpha值。

(4)“紋理混合狀态”與紋理的Alpha混合

現在讓我們總結一下我們為了實作紋理Alpha混合,我們對紋理階段混合狀态做了什麼:首先,我們指定了紋理Alpha混合的操作方式是兩個參數相乘,并且給了操作方式兩個參數,又因為紋理可能有多級,這成為了我們設定這兩個參數的依據。通過這些設定我們便告訴了Direct3D在進行紋理Alpha混合的時候應該怎麼做,又應該從哪裡取得Alpha值。

即使搞不清楚上面的那些可選項的設定方法和具體含義我們依舊可以在程式中使用紋理的Alpha混合,畢竟這隻涉及到紋理混合的一小部分。下面通過一個示例來了解紋理Alpha混合的工作過程。

示例三——紋理Alpha

(1)運作結果

8.3 初步了解 Texture Alpha

(2)What’s this?

看到運作結果,你可能會有些疑惑,程式是怎樣展現出紋理Alpha混合的呢?

首先,我們準備了一幅精靈的圖檔,這張圖檔的格式值得我們注意,可以通過DirectX中的DxTex工具檢視(相對路徑為Microsoft DirectX SDK (June 2010)\Utilities\bin\x64):

8.3 初步了解 Texture Alpha

從工具中可以看出,這是一幅顔色格式為32位的圖像,RGBA每個通道各占8位,我們需要注意的是,這張圖檔是包含Alpha通道的,這很重要!因為隻有紋理中包含Alpha通道,才存在紋理Alpha混合的概念。

另外,讓我們打開圖檔的另一個視圖(工具的View->Alpha Channel Only):

8.3 初步了解 Texture Alpha

這個視圖是隻保留了Alpha通道。上圖中的結果意味着什麼?黑色部分代表Alpha值為0,即全透明;白色的部分代表Alpha值為1,表示完全不透明。那Alpha值隻能非0即1嗎?當然不是:

8.3 初步了解 Texture Alpha

我們把另一張圖檔的Alpha通道與所用精靈圖檔進行對比,可以知道右邊圖檔中的Alpha值是從四周向圓心遞增的。

(3)程式效果産生的原因!

從上面的分析,我們得知了精靈圖檔中:那個飛機圖案的alpha值是1,而四周也就是背景的alpha值是0。這意味着,在進行紋理alpha值混合的時候,背景處的alpha值依次與頂點的alpha值和背景緩沖區中的alpha值混合(乘積)都是0,即完全透明;而飛機圖案alpha=1而完全不透明。最終在打開和關閉紋理混合的時候,呈現出運作中的效果。

(4)關鍵代碼

有關渲染狀态的設定:

//設定渲染狀态
    g_pd3dDevice->SetRenderState(D3DRS_LIGHTING, FALSE);

    g_pd3dDevice->SetTextureStageState(, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
    g_pd3dDevice->SetTextureStageState(, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
    g_pd3dDevice->SetTextureStageState(, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);

    g_pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);    
    g_pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
    g_pd3dDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);    
           

從檔案中加載紋理:

//建立紋理對象
    if (FAILED(D3DXCreateTextureFromFile(g_pd3dDevice, "images/plane5.png", &g_pTexture))) {
        MessageBox(NULL, "fail to create texture.", "error", MB_OK);
        return E_FAIL;
    }
           

場景渲染:

//開始渲染圖形
    if (SUCCEEDED(g_pd3dDevice->BeginScene())) {
        g_pd3dDevice->SetTexture(, g_pTexture);
        g_pd3dDevice->SetStreamSource(, g_pVB, , sizeof(CUSTOMVERTEX));
        g_pd3dDevice->SetFVF(D3DFVF_CUSTOMVERTEX);
        g_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, , );
        g_pd3dDevice->EndScene();
    }
           

源碼下載下傳

連結:https://pan.baidu.com/s/1HCOIeY-_Ai2hfnEGDzPzYA 密碼:dxao

有關紋理渲染狀态的設定是一個龐大并且複雜的主題,在以後的文章中還會接觸和學習。通過這個小例子可以看出紋理alpha混合可以很好的制作出透明精靈的效果,在2D遊戲中也有廣泛的應用。