Directx11教程(44) alpha blend(1)

來源:互聯網
上載者:User

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

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

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

    

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

 

     1、混合方程

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

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

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

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

     2、blend操作

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

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  ,把兩個顏色加起來。
D3D11_BLEND_OP_SUBTRACT ,Source1減去source2。
D3D11_BLEND_OP_REV_SUBTRACT ,source2減去source1
D3D11_BLEND_OP_MIN 取最小顏色值。
D3D11_BLEND_OP_MAX 取最大顏色值。

     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)

     這兒還有一些其它的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;

程式最終執行效果如下:

完整的代碼請參考:

工程檔案myTutorialD3D11_39

代碼下載:

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

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

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.