我們知道,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因子
這兒還有一些其它的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
代碼下載:





