本文由zhangbaochong原創,轉載請注明出處http://www.cnblogs.com/zhangbaochong/p/5634580.html
在d3d11中是按frame來渲染物體的,在同一frame中又可能不止一種primitive,例如下圖:
gpu實際渲染時,會按幀渲染,像上圖中的一幀中含有兩個三角形 ,經過vs以后,PA(primitive assemble) block會進行體元裝配,然后進行光柵化操作,光柵化操作時候,會比較depth buffer的值,紅色三角形的z值更小,所以會將黑色三角形覆蓋一部分。
而當混合功能啟用時,決定最終的顏色方法會變得不同,當一個片段通過深度測試時,並不是直接取代后緩沖的顏色,而是通過一定的方法比例與之混合,從而顯示混合后的顏色。
1.混合方程
混合方程如下:
C是混合結果,Csrc是源顏色,也就是當前要處理的片段顏色,而Cdst是目標顏色,也就是后緩沖區的顏色。F則是對應的混合因子,等會兒會詳細說明。這里的可以看作是分量相乘,即顏色中的R、G、B值分別相乘。
則是混合操作,和四則運算操作類似。
2.混合操作
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中解釋如下:
- D3D11_BLEND_OP_ADD
-
Add source 1 and source 2.
- D3D11_BLEND_OP_SUBTRACT
-
Subtract source 1 from source 2.
- 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ㄒ)/~~
5.2源碼下載
地址:http://files.cnblogs.com/files/zhangbaochong/BlendDemo.zip
由於源碼上傳在了博客園的文件管理中,提供的空間很小,因此就不上傳整個工程了,只是把代碼文件上傳了,要想運行的話配置一下用vs重新編譯吧O(∩_∩)O~
ps:之前代碼中,創建頂點索引緩沖、加載shader、加載圖片等我全都給放在一個函數中實現了,隨着代碼越來越多,感覺易讀性非常差。於是就參考龍書的架構,重構了下代碼,顯得條理了不少…