Directx11學習筆記【十八】 Blending混合

本文由zhangbaochong原創,轉載請註明出處http://www.cnblogs.com/zhangbaochong/p/5634580.htmlhtml

     在d3d11中是按frame來渲染物體的,在同一frame中又可能不止一種primitive,例以下圖:架構

 

image

     gpu實際渲染時,會按幀渲染,像上圖中的一幀中含有兩個三角形 ,通過vs之後,PA(primitive assemble) block會進行體元裝配,而後進行光柵化操做,光柵化操做時候,會比較depth buffer的值,紅色三角形的z值更小,因此會將黑色三角形覆蓋一部分。less

    而當混合功能啓用時,決定最終的顏色方法會變得不一樣,當一個片斷經過深度測試時,並非直接取代後緩衝的顏色,而是經過必定的方法比例與之混合,從而顯示混合後的顏色。函數

1.混合方程

    混合方程以下:測試

image

    C是混合結果,Csrc是源顏色,也就是當前要處理的片斷顏色,而Cdst是目標顏色,也就是後緩衝區的顏色。F則是對應的混合因子,等會兒會詳細說明。這裏的image能夠看做是份量相乘,即顏色中的R、G、B值分別相乘。image則是混合操做,和四則運算操做相似。ui

2.混合操做

    對於混合操做image,在d3d中定義在一個枚舉中,原型以下:spa

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;

    在MSDN中解釋以下:3d

D3D11_BLEND_OP_ADD

Add source 1 and source 2.code

D3D11_BLEND_OP_SUBTRACT

Subtract source 1 from source 2. orm

D3D11_BLEND_OP_REV_SUBTRACT

Subtract source 2 from source 1. 

D3D11_BLEND_OP_MIN

Find the minimum of source 1 and source 2.

D3D11_BLEND_OP_MAX

Find the maximum of source 1 and source 2.

3.混合因子

    對於混合因子F,在d3d中也定義爲枚舉,原型以下:

typedef enum D3D11_BLEND { 
  D3D11_BLEND_ZERO              = 1,
  D3D11_BLEND_ONE               = 2,
  D3D11_BLEND_SRC_COLOR         = 3,
  D3D11_BLEND_INV_SRC_COLOR     = 4,
  D3D11_BLEND_SRC_ALPHA         = 5,
  D3D11_BLEND_INV_SRC_ALPHA     = 6,
  D3D11_BLEND_DEST_ALPHA        = 7,
  D3D11_BLEND_INV_DEST_ALPHA    = 8,
  D3D11_BLEND_DEST_COLOR        = 9,
  D3D11_BLEND_INV_DEST_COLOR    = 10,
  D3D11_BLEND_SRC_ALPHA_SAT     = 11,
  D3D11_BLEND_BLEND_FACTOR      = 14,
  D3D11_BLEND_INV_BLEND_FACTOR  = 15,
  D3D11_BLEND_SRC1_COLOR        = 16,
  D3D11_BLEND_INV_SRC1_COLOR    = 17,
  D3D11_BLEND_SRC1_ALPHA        = 18,
  D3D11_BLEND_INV_SRC1_ALPHA    = 19
} D3D11_BLEND;

    在MSDN中解釋以下:

D3D11_BLEND_ZERO

The blend factor is (0, 0, 0, 0). No pre-blend operation.

D3D11_BLEND_ONE

The blend factor is (1, 1, 1, 1). No pre-blend operation.

D3D11_BLEND_SRC_COLOR

The blend factor is (Rₛ, Gₛ, Bₛ, Aₛ), that is color data (RGB) from a pixel shader. No pre-blend operation.

D3D11_BLEND_INV_SRC_COLOR

The blend factor is (1 - Rₛ, 1 - Gₛ, 1 - Bₛ, 1 - Aₛ), that is color data (RGB) from a pixel shader. The pre-blend operation inverts the data, generating 1 - RGB.

D3D11_BLEND_SRC_ALPHA

The blend factor is (Aₛ, Aₛ, Aₛ, Aₛ), that is alpha data (A) from a pixel shader. No pre-blend operation.

D3D11_BLEND_INV_SRC_ALPHA

The blend factor is ( 1 - Aₛ, 1 - Aₛ, 1 - Aₛ, 1 - Aₛ), that is alpha data (A) from a pixel shader. The pre-blend operation inverts the data, generating 1 - A.

D3D11_BLEND_DEST_ALPHA

The blend factor is (Ad Ad Ad Ad), that is alpha data from a render target. No pre-blend operation.

D3D11_BLEND_INV_DEST_ALPHA

The blend factor is (1 - Ad 1 - Ad 1 - Ad 1 - Ad), that is alpha data from a render target. The pre-blend operation inverts the data, generating 1 - A.

D3D11_BLEND_DEST_COLOR

The blend factor is (Rd, Gd, Bd, Ad), that is color data from a render target. No pre-blend operation.

D3D11_BLEND_INV_DEST_COLOR

The blend factor is (1 - Rd, 1 - Gd, 1 - Bd, 1 - Ad), that is color data from a render target. The pre-blend operation inverts the data, generating 1 - RGB.

D3D11_BLEND_SRC_ALPHA_SAT

The blend factor is (f, f, f, 1); where f = min(Aₛ, 1 - Ad). The pre-blend operation clamps the data to 1 or less.

D3D11_BLEND_BLEND_FACTOR

The blend factor is the blend factor set with ID3D11DeviceContext::OMSetBlendState. No pre-blend operation.

D3D11_BLEND_INV_BLEND_FACTOR

The blend factor is the blend factor set with ID3D11DeviceContext::OMSetBlendState. The pre-blend operation inverts the blend factor, generating 1 - blend_factor.

D3D11_BLEND_SRC1_COLOR

The blend factor is data sources both as color data output by a pixel shader. There is no pre-blend operation. This blend factor supports dual-source color blending.

D3D11_BLEND_INV_SRC1_COLOR

The blend factor is data sources both as color data output by a pixel shader. The pre-blend operation inverts the data, generating 1 - RGB. This blend factor supports dual-source color blending.

D3D11_BLEND_SRC1_ALPHA

The blend factor is data sources as alpha data output by a pixel shader. There is no pre-blend operation. This blend factor supports dual-source color blending.

D3D11_BLEND_INV_SRC1_ALPHA

The blend factor is data sources as alpha data output by a pixel shader. The pre-blend operation inverts the data, generating 1 - A. This blend factor supports dual-source color blending.

4.具體使用方法

    在d3d11中,要使用混合首先要建立混合狀態接口ID3D11BlendState,建立要調用CreateBlendState函數,原型以下:

HRESULT CreateBlendState(
  [in]            const D3D11_BLEND_DESC *pBlendStateDesc,
  [out, optional]       ID3D11BlendState **ppBlendState
);

    D3D11_BLEND_DESC 是描述混合狀態的結構,原型以下:

typedef struct D3D11_BLEND_DESC {
  BOOL                           AlphaToCoverageEnable;
  BOOL                           IndependentBlendEnable;
  D3D11_RENDER_TARGET_BLEND_DESC RenderTarget[8];
} D3D11_BLEND_DESC;

    第一個參數設置是否打開AlphaToCoverage,AlphaToCoverage在後面會詳細介紹,暫時先不用,設置爲false;

    第二個參數是針對不一樣的RenderTarget使用不一樣的混合方式,最多支持8個不一樣的RenderTarget,咱們暫時還用不到設爲false;

    第三個參數爲針對8個不一樣RenderTarget分別指定的混合狀態參數,當第二個參數爲false時,這裏咱們只須要設置第一個元素便可。

    D3D11_RENDER_TARGET_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;

    MSDN中解釋以下:

BlendEnable

Type: BOOL

Enable (or disable) blending.

 

SrcBlend

Type: D3D11_BLEND

This blend option specifies the operation to perform on the RGB value that the pixel shader outputs. The BlendOp member defines how to combine the SrcBlend and DestBlend operations.

 

DestBlend

Type: D3D11_BLEND

This blend option specifies the operation to perform on the current RGB value in the render target. The BlendOp member defines how to combine the SrcBlend and DestBlend operations.

 

BlendOp

Type: D3D11_BLEND_OP

This blend operation defines how to combine the SrcBlend and DestBlend operations.

 

SrcBlendAlpha

Type: D3D11_BLEND

This blend option specifies the operation to perform on the alpha value that the pixel shader outputs. Blend options that end in _COLOR are not allowed. The BlendOpAlpha member defines how to combine the SrcBlendAlpha and DestBlendAlpha operations.

 

DestBlendAlpha

Type: D3D11_BLEND

This blend option specifies the operation to perform on the current alpha value in the render target. Blend options that end in _COLOR are not allowed. The BlendOpAlpha member defines how to combine the SrcBlendAlpha and DestBlendAlpha operations.

 

BlendOpAlpha

Type: D3D11_BLEND_OP

This blend operation defines how to combine the SrcBlendAlpha and DestBlendAlpha operations.

 

RenderTargetWriteMask

Type: UINT8

A write mask.

建立好ID3D11BlendState接口後,經過OMSetBlendState函數來設置爲指定的狀態,原型以下:

void OMSetBlendState(
  [in]       ID3D10BlendState *pBlendState,
  [in] const FLOAT            BlendFactor[4],
  [in]       UINT             SampleMask
);

    其中第二個參數,爲手動指定的混合因子,若是在剛纔指定混合因子時使用D3D11_BLEND_BLEND_FACTOR或D3D11_BLEND_INV_BLEND_FACTOR,則使用第二個參數做爲混合因子。

    第三個參數爲採樣點掩碼。在d3d11中最多能夠支持32重採樣,經過該參數來指定使用哪些採樣點,參數類型爲UINT32位,每位1和0表明使用或丟棄該採樣點,若是咱們想使用全部採樣點,則能夠設該參數爲0xffffffff。

 

    下面是demo中使用混合的部分代碼:

    首先在類中定義了渲染狀態接口:

ID3D11BlendState*        m_pBlendState;    //混合狀態

    而後自定義了一個函數用於建立渲染狀態:

bool BlendDemo::BuildBlendState()
{
    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;
    
    if (FAILED(m_pd3dDevice->CreateBlendState(&blendStateDescription, &m_pBlendState)))
    {
        MessageBox(NULL, L"Create 'Transparent' blend state failed!", L"Error", MB_OK);
        return false;
    }

    return true;
}

       咱們利用混合,實現水面的透明效果。當繪製的圖形中有透明物體時,繪製的前後順序就顯得尤其重要,通常咱們遵循如下原則:首先繪製非透明物體。而後,根據透明物體與攝像機之間的距離進行排序,按照從後向前的順序繪製透明物體。之因此要按照從後向前的順序進行繪製,是爲了讓前面的物體和後面的物體進行混合。若是一個物體是透明的,那麼咱們就會透過這個物體看到它後面的其餘物體。因此,必須將透明物體後面的全部物體先繪製出來,而後才能將透明的源像素和後臺緩衝區中的目標像素進行混合。

 

       在demo中,咱們一共有3個物體,箱子、地面還有水面。所以咱們先繪製箱子和地面,最後在繪製水面的時候開啓混合,繪製完畢再關閉混合。

       //繪製箱子...
       //繪製地面...    
       //繪製水面
        //開啓建立好的blend狀態  效果爲透明
        float blendFactor[] = { 0.f,0.f,0.f,0.f };
        m_pImmediateContext->OMSetBlendState(m_pBlendState, blendFactor, 0xffffffff);
        Effects::ms_pBasicEffect->m_pFxWorld->SetMatrix(reinterpret_cast<const float*>(&m_worldWater));
        Effects::ms_pBasicEffect->m_pFxWorldViewProj->SetMatrix(reinterpret_cast<const float*>(&m_worldViewProjWater));
        Effects::ms_pBasicEffect->m_pFxWorldInvTranspose->SetMatrix(reinterpret_cast<const float*>(&m_worldInvTransposeWater));
        Effects::ms_pBasicEffect->m_pFxMaterial->SetRawValue(&m_materialWater, 0, sizeof(m_materialWater));
        Effects::ms_pBasicEffect->m_pFxTexTrans->SetMatrix(reinterpret_cast<const float*>(&m_texTransWater));
        Effects::ms_pBasicEffect->m_pFxSR->SetResource(m_pSRVWater);
        tech->GetPassByIndex(i)->Apply(0, m_pImmediateContext);
        m_pImmediateContext->DrawIndexed(m_water.indices.size(), m_waterIStart, m_waterVStart);
        //恢復狀態
        m_pImmediateContext->OMSetBlendState(0, 0, 0xffffffff);

 

5.示例程序

5.1運行效果

     因爲水面是靜態的,截圖看的話效果不是很好/(ㄒoㄒ)/~~

image

5.2源碼下載

     地址:http://files.cnblogs.com/files/zhangbaochong/BlendDemo.zip

     因爲源碼上傳在了博客園的文件管理中,提供的空間很小,所以就不上傳整個工程了,只是把代碼文件上傳了,要想運行的話配置一下用vs從新編譯吧O(∩_∩)O~

     ps:以前代碼中,建立頂點索引緩衝、加載shader、加載圖片等我全都給放在一個函數中實現了,隨着代碼愈來愈多,感受易讀性很是差。因而就參考龍書的架構,重構了下代碼,顯得條理了很多…

相關文章
相關標籤/搜索