Directx11教程(44) alpha blend(1)


   我們知道,D3D11中按Frame來渲染物體,每個Frame中又可能包含若干個primitive,如下面的示意圖所示:

image

image

     gpu在實際渲染中,會按幀來渲染,比如上圖frame0中,有兩個primitive(三角形),經過vs以后,PA(primitive assemble) block會進行體元裝配,然后進行光柵化操作,光柵化操作時候,會比較depth buffer的值。因為紅色的三角形面的z值更小,所以它會覆蓋黑色三角形一部分。

      如果我們想要混合2個三角形的顯示,該怎么做呢?這時就需要alpha blend操作,就是后緩沖中內容和當前ps輸出的pixel顏色進行混合操作。使用alpha blend操作,我們可以實現透明等效果。

    

現在我們看看D3D11中alpha blend的實現原理:

 

     1、混合方程

image

       假定現在ps輸出的像素顏色是Csrc = (Rs , Gs , Bs),后緩沖中的對應像素顏色值是Cdst = (Rd , Gd , Bd),

顏色Fsrc和Fdst稱作源混合(blend)因子和目的混合(blend)因子,image表示顏色按分量相乘,image表示任意操作符,比如加法,減法等等。

      通過方程計算后得到的C是最終的顏色值,它將覆蓋后緩沖的像素顏色。

       以上方程是對於RGB顏色來說的,對於alpha值也有相應的方程:

image

     2、blend操作

      混合方程中的image為下面的操作符之一:

typedef enum D3D11_BLEND_OP { D3D11_BLEND_OP_ADD = 1, D3D11_BLEND_OP_SUBTRACT = 2, D3D11_BLEND_OP_REV_SUBTRACT = 3, D3D11_BLEND_OP_MIN = 4, D3D11_BLEND_OP_MAX = 5, } D3D11_BLEND_OP;
Constants
D3D11_BLEND_OP_ADD  image,把兩個顏色加起來。
D3D11_BLEND_OP_SUBTRACT image,Source1減去source2。
D3D11_BLEND_OP_REV_SUBTRACT image,source2減去source1
D3D11_BLEND_OP_MIN image 取最小顏色值。
D3D11_BLEND_OP_MAX image取最大顏色值。

     3、blend因子

D3D11_BLEND_ZERO F = (0, 0, 0, 0)
D3D11_BLEND_ONE F = (1, 1, 1, 1)
D3D11_BLEND_SRC_COLOR F = (Rs , Gs , Bs)
D3D11_BLEND_INV_SRC_COLOR F = (1 – Rs ,1 – Gs ,1 - Bs)
D3D11_BLEND_SRC_ALPHA F = (Alphas , Alphas, Alphas ), 混合因子為源顏色的alpha值。
D3D11_BLEND_INV_SRC_ALPHA F = (1 - Alphas , 1 - Alphas, 1 - Alphas )
D3D11_BLEND_DEST_ALPHA F = (Alphad , Alphad , Alphad ), 混合因子為目的顏色的alpha值。
D3D11_BLEND_INV_DEST_ALPHA F = (1 - Alphad , 1 - Alphad , 1 - Alphad ),
D3D11_BLEND_DEST_COLOR F = (Rd , Gd , Bd)
D3D11_BLEND_INV_DEST_COLOR F = (1 – Rd ,1 – Gd ,1 – Bd)
D3D11_BLEND_SRC_ALPHA_SAT F = (Alpha’s , Alpha’s, Alpha’s ), Alpha’s  = clamp(Alphas , 0, 1) image

     這兒還有一些其它的blend因子設置,具體請查看Directx的文檔。需要注意的是對於alpha blend因子:結尾是_COLOR的不能使用

     4、blend狀態

      使用alpha blend之前,我們需要設置blend state,並enalbe它。

      首先我們要填寫一個D3D11_BLEND_DESC結構,然后調用CreateBlendState,就可以創建blend狀態了。

      重要的是我們要在MRT中設置blend因子以及操作方式等等。(一般是MRT[0],對應一個輸出,如果使用多個MRT,可以設置不同blend因子或者操作方式)。

typedef struct D3D11_BLEND_DESC

{ BOOL AlphaToCoverageEnable;

BOOL IndependentBlendEnable;

D3D11_RENDER_TARGET_BLEND_DESC RenderTarget[8];

} D3D11_BLEND_DESC;

typedef struct D3D11_RENDER_TARGET_BLEND_DESC

{

BOOL BlendEnable;

D3D11_BLEND SrcBlend;

D3D11_BLEND DestBlend;

D3D11_BLEND_OP BlendOp;

D3D11_BLEND SrcBlendAlpha;

D3D11_BLEND DestBlendAlpha;

D3D11_BLEND_OP BlendOpAlpha;

UINT8 RenderTargetWriteMask;

} D3D11_RENDER_TARGET_BLEND_DESC;

    現在我們修改myTutorialD3D11_38的代碼,增加blend支持,使水有透明的效果。其實代碼很簡單,首先在D3DClass類中增加兩個函數。

void D3DClass::TurnOnAlphaBlending()
    {
    float blendFactor[4];


   // 設置blend因子
    blendFactor[0] = 0.0f;
    blendFactor[1] = 0.0f;
    blendFactor[2] = 0.0f;
    blendFactor[3] = 0.0f;

    // 打開alpha blend
    m_deviceContext->OMSetBlendState(m_alphaEnableBlendingState, blendFactor, 0xffffffff);

    return;
    }

void D3DClass::TurnOffAlphaBlending()
    {
    float blendFactor[4];


   // 設置blend因子
    blendFactor[0] = 0.0f;
    blendFactor[1] = 0.0f;
    blendFactor[2] = 0.0f;
    blendFactor[3] = 0.0f;

    // 關閉alpha blend
    m_deviceContext->OMSetBlendState(m_alphaDisableBlendingState, blendFactor, 0xffffffff);

    return;
    }

我們還要在初始化函數中,創建兩個blend狀態,一個表示enable blend,一個表示disable blend。

D3D11_BLEND_DESC blendStateDescription;

// 初始化blend描述符
ZeroMemory(&blendStateDescription, sizeof(D3D11_BLEND_DESC));

// 創建一個alpha blend狀態.
blendStateDescription.RenderTarget[0].BlendEnable = TRUE;
blendStateDescription.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
blendStateDescription.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
blendStateDescription.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
blendStateDescription.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
blendStateDescription.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
blendStateDescription.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
blendStateDescription.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;//0x0f;

// 用描述符創建一個alpha blend狀態
result = m_device->CreateBlendState(&blendStateDescription, &m_alphaEnableBlendingState);
if(FAILED(result))
    {
    return false;
    }

//修改描述符.
blendStateDescription.RenderTarget[0].BlendEnable = FALSE;

//創建一個新的blend狀態.
result = m_device->CreateBlendState(&blendStateDescription, &m_alphaDisableBlendingState);

在GraphicsClass類中,渲染水時,打開alpha blend

// 打開alpha blend.
m_D3D->TurnOnAlphaBlending();

// 把模型頂點和索引緩沖放入管線,准備渲染.
m_WaterModel->Render(m_D3D->GetDeviceContext());

result = m_LightTexShader->Render(m_D3D->GetDeviceContext(), m_WaterModel->GetIndexCount(), worldMatrix, viewMatrix, projectionMatrix,
    light, material, camera,m_TexManager->createTex(m_D3D->GetDevice(),string("water2.dds")));
if(!result)
    {
    return false;
    }

// 關閉alpha blend.
m_D3D->TurnOffAlphaBlending();

最后一點就是在lighttex.ps中做小小的改動,

     float4 finalcolor1;
     finalcolor1 = float4(finalcolor.xyz,0.5);
     return finalcolor1;

這是因為我們的混合因子都是來自於alpha值

blendStateDescription.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;

blendStateDescription.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;

程序最終執行效果如下:

image

完整的代碼請參考:

工程文件myTutorialD3D11_39

代碼下載:

http://files.cnblogs.com/mikewolf2002/d3d1139-49.zip

http://files.cnblogs.com/mikewolf2002/pictures.zip


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM