【DirectX11】【学习笔记(10)】混合
今天我們學習一下如何給圖元增加一點混合效果,這樣看起來會更透明。
混合等式
D3D中的混合效果和把render target上的像素與在它之前的透明圖元用混合等式執行像素融合
(FC) - Final Color (SP) - Source Pixel (DP) - Destination Pixel (SBF) - Source Blend Factor (DBF) - Destination Blend Factor (FA) - Final Alpha (SA) - Source Alpha (DA) - Destination Alpha (+) - Binaray Operator described below (X) - Cross Multiply MatricesD3D主要使用兩種不同的等式,一個是針對顏色,一個是針對透明度(alpha),我們可以同時處理這兩個不同的等式實現效果。
(FC) = (SP) (X) (SBF) (+) (DP) (X) (DPF)(FA) = (SA)(SBF) (+) (DA)(DBF)The binary (+) operator can be one of the following:
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;SBF和DBF混合因子是D3D11_BLEND枚舉值類型。
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;D3D11_BLEND_ZERO - 數據是黑色
D3D11_BLEND_ONE - 數據是白色
D3D11_BLEND_SRC_COLOR - 數據來源于PS著色器中的RGB(PS中的數據,就是混合等式中被添加的部分)
D3D11_BLEND_INV_SRC_COLOR -?數據來源于PS著色器中的RGB,但是有預處理,結果為1-RGB
D3D11_BLEND_SRC_ALPHA - 數據為PS中的A值
D3D11_BLEND_INV_SRC_ALPHA - PS中的1-A值
D3D11_BLEND_DEST_ALPHA - 數據來自已經存在render target上的A值
D3D11_BLEND_INV_DEST_ALPHA -?數據來自已經存在render target上的1-A值
D3D11_BLEND_DEST_COLOR ?-?數據來自已經存在render target上的RGB值
D3D11_BLEND_INV_DEST_COLOR -??數據來自已經存在render target上的1- RGB值
D3D11_BLEND_SRC_ALPHA_SAT? - 數據來自源于PS著色器中的A,但是blend操作會把數據縮小到1及以下
D3D11_BLEND_BLEND_FACTOR - 數據來源于ID3D10Device::OMSetBlendState函數中設置的belnd factor
D3D11_BLEND_INV_BLEND_FACTOR -同上,結果為1-factor
D3D11_BLEND_SRC1_COLOR - 兩個數據都是由PS產生,這個操作支持兩個源數據顏色混合,而不是把一個PS上的數據與rendertarget混合
D3D11_BLEND_INV_SRC1_COLOR - 同上,結果為1-RGB
D3D11_BLEND_SRC1_ALPHA - 同上結果為A
D3D11_BLEND_INV_SRC1_ALPHA - 同上,結果為1-A
了解了混合等式之后,我們就要創建我們的混合描述信息了
typedef struct D3D11_BLEND_DESC {BOOL AlphaToCoverageEnable;BOOL IndependentBlendEnable;D3D11_RENDER_TARGET_BLEND_DESC RenderTarget[8]; } D3D11_BLEND_DESC;AlphaToCoverageEnable ?- 多重采樣在這里很有用,現在只是將它設為true
IndependentBlendEnable - 我們能夠一次和多個render target進行混合,最多為8個,設為false默認與第一個進行混合
RenderTarget[8] - 數組中的每一個結構體都是一個對render target 的blending描述
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;BlendEnable - 是否能進行混合
SrcBlend? - 等式中的SBF,可以設為D3D11_BLEND 中的一個
DestBlend - DBF,同上
BlendOp -?D3D11_BLEND_OP 枚舉值
SrcBlendAlpha - SBF(alpha channel),D3D11_BLEND 枚舉值
DestBlendAlpha - DBF,同上
BlendOpAlpha? - 這里我們設為D3D10_BLEND_OP 枚舉值
RenderTargetWriteMask - 指定要混合的channel
typedef enum D3D11_COLOR_WRITE_ENABLE {D3D11_COLOR_WRITE_ENABLE_RED = 1,D3D11_COLOR_WRITE_ENABLE_GREEN = 2,D3D11_COLOR_WRITE_ENABLE_BLUE = 4,D3D11_COLOR_WRITE_ENABLE_ALPHA = 8,D3D11_COLOR_WRITE_ENABLE_ALL = ( D3D11_COLOR_WRITE_ENABLE_RED | D3D11_COLOR_WRITE_ENABLE_GREEN | D3D11_COLOR_WRITE_ENABLE_BLUE | D3D11_COLOR_WRITE_ENABLE_ALPHA ) } D3D11_COLOR_WRITE_ENABLE;Transparent Object's Depth Order.
當我們想要看到一個透明物體的背面的時候,我們可能會遇到一點問題。
當我們執行blend的時候,我們先假設此時render target上已經存在像素(被渲染好的物體)了。
先渲染不透明的物體,再渲染透明的物體,這一點很重要,下面就是我們的問題
eg:當我們第一次渲染框時,繞第二個盒子運行的第一個盒子開始于第二個盒子之后,并在代碼中首先渲染。因此,當渲染第二個盒子時,它能夠與第一個盒子混合,因為第一個盒子已經在渲染目標上。但是,當第一個盒子圍繞第二個盒子旋轉,并且位于第二個盒子的前面時,它將不會與第二個盒子混合
為了解決這個問題,我們需要每幀都計算物體到相機的距離,來決定先渲染哪個物體
除此之外,我們還有一些其他的問題,D3D是默認裁剪掉逆時針的平面,也就是說,當一個三角形面對攝像機是逆時針繪制的,即不可見。所以我們一般看不到背面,所以當繪制了Box的前面的時候,就不能和背面進行混合,因為背面其實看不到。
如果我們更改裁剪順序,也不能滿足我們的問題,此外,如果同一個box的一個距離相機更近的面先被繪制,他們就不能和其他面進行混合。所以一個box的面有時候不透明,有時候不可見
為了解決上面這個問題,我們需要繪制box兩次,這樣我們就能看的到背面,并且繪制前面的時候,背面已經在render target上了
首先我們要創建兩個render states,一個順時針,一個逆時針。
然后我們先用逆時針繪制一遍,因為我們的面試順時針的,這樣就能把box內部的面繪制出來(從里面看是逆時針的)
上述問題搞定了之后,我們開始寫本節的代碼
Global Declarations
ID3D11BlendState* Transparency; ID3D11RasterizerState* CCWcullMode; ID3D11RasterizerState* CWcullMode;Clean Up
別忘了刪除指針
Transparency->Release();CCWcullMode->Release();CWcullMode->Release();The Blending Equation
首先我們要創建render target blending desc,然后創建blend desc(結構太多,要看仔細,不然容易搞混)
D3D11_BLEND_DESC blendDesc; ZeroMemory( &blendDesc, sizeof(blendDesc) );D3D11_RENDER_TARGET_BLEND_DESC rtbd; ZeroMemory( &rtbd, sizeof(rtbd) );rtbd.BlendEnable = true; rtbd.SrcBlend = D3D11_BLEND_SRC_COLOR; rtbd.DestBlend = D3D11_BLEND_BLEND_FACTOR; rtbd.BlendOp = D3D11_BLEND_OP_ADD; rtbd.SrcBlendAlpha = D3D11_BLEND_ONE; rtbd.DestBlendAlpha = D3D11_BLEND_ZERO; rtbd.BlendOpAlpha = D3D11_BLEND_OP_ADD; rtbd.RenderTargetWriteMask = D3D10_COLOR_WRITE_ENABLE_ALL;blendDesc.AlphaToCoverageEnable = false; blendDesc.RenderTarget[0] = rtbd;d3d11Device->CreateBlendState(&blendDesc, &Transparency);CW & CCW Culling
為了繪制兩遍,我們要創建兩個RSstate
這部分的內容我們之前已經講過一些
D3D11_RASTERIZER_DESC cmdesc; ZeroMemory(&cmdesc, sizeof(D3D11_RASTERIZER_DESC));cmdesc.FillMode = D3D11_FILL_SOLID; cmdesc.CullMode = D3D11_CULL_BACK;cmdesc.FrontCounterClockwise = true; hr = d3d11Device->CreateRasterizerState(&cmdesc, &CCWcullMode);cmdesc.FrontCounterClockwise = false; hr = d3d11Device->CreateRasterizerState(&cmdesc, &CWcullMode);DrawScene() Function
最后就是利用blend等式和創建好的RS state來進行繪制啦,別忘了實時計算物體到相機的位置
void DrawScene() {//Clear our backbufferfloat bgColor[4] = {(0.0f, 0.0f, 0.0f, 0.0f)};d3d11DevCon->ClearRenderTargetView(renderTargetView, bgColor);//Refresh the Depth/Stencil viewd3d11DevCon->ClearDepthStencilView(depthStencilView, D3D11_CLEAR_DEPTH|D3D11_CLEAR_STENCIL, 1.0f, 0);///**************new**************//"fine-tune" the blending equationfloat blendFactor[] = {0.75f, 0.75f, 0.75f, 1.0f};//Set the default blend state (no blending) for opaque objectsd3d11DevCon->OMSetBlendState(0, 0, 0xffffffff);//Render opaque objects////Set the blend state for transparent objectsd3d11DevCon->OMSetBlendState(Transparency, blendFactor, 0xffffffff);//*****Transparency Depth Ordering*****////Find which transparent object is further from the camera//So we can render the objects in depth order to the render target//Find distance from first cube to cameraXMVECTOR cubePos = XMVectorZero();cubePos = XMVector3TransformCoord(cubePos, cube1World);float distX = XMVectorGetX(cubePos) - XMVectorGetX(camPosition);float distY = XMVectorGetY(cubePos) - XMVectorGetY(camPosition);float distZ = XMVectorGetZ(cubePos) - XMVectorGetZ(camPosition);float cube1Dist = distX*distX + distY*distY + distZ*distZ;//Find distance from second cube to cameracubePos = XMVectorZero();cubePos = XMVector3TransformCoord(cubePos, cube2World);distX = XMVectorGetX(cubePos) - XMVectorGetX(camPosition);distY = XMVectorGetY(cubePos) - XMVectorGetY(camPosition);distZ = XMVectorGetZ(cubePos) - XMVectorGetZ(camPosition);float cube2Dist = distX*distX + distY*distY + distZ*distZ;//If the first cubes distance is less than the second cubesif(cube1Dist < cube2Dist){//Switch the order in which the cubes are drawnXMMATRIX tempMatrix = cube1World;cube1World = cube2World;cube2World = tempMatrix;}///**************new**************//Set the WVP matrix and send it to the constant buffer in effect fileWVP = cube1World * camView * camProjection;cbPerObj.WVP = XMMatrixTranspose(WVP); d3d11DevCon->UpdateSubresource( cbPerObjectBuffer, 0, NULL, &cbPerObj, 0, 0 );d3d11DevCon->VSSetConstantBuffers( 0, 1, &cbPerObjectBuffer );d3d11DevCon->PSSetShaderResources( 0, 1, &CubesTexture );d3d11DevCon->PSSetSamplers( 0, 1, &CubesTexSamplerState );///**************new**************//Counter clockwise culling first because we need the back side of//the cube to be rendered first, so the front side can blend with itd3d11DevCon->RSSetState(CCWcullMode);///**************new**************//Draw the first cubed3d11DevCon->DrawIndexed( 36, 0, 0 );///**************new**************d3d11DevCon->RSSetState(CWcullMode);d3d11DevCon->DrawIndexed( 36, 0, 0 );///**************new**************WVP = cube2World * camView * camProjection;cbPerObj.WVP = XMMatrixTranspose(WVP); d3d11DevCon->UpdateSubresource( cbPerObjectBuffer, 0, NULL, &cbPerObj, 0, 0 );d3d11DevCon->VSSetConstantBuffers( 0, 1, &cbPerObjectBuffer );d3d11DevCon->PSSetShaderResources( 0, 1, &CubesTexture );d3d11DevCon->PSSetSamplers( 0, 1, &CubesTexSamplerState );///**************new**************d3d11DevCon->RSSetState(CCWcullMode);///**************new**************//Draw the second cubed3d11DevCon->DrawIndexed( 36, 0, 0 );///**************new**************d3d11DevCon->RSSetState(CWcullMode);d3d11DevCon->DrawIndexed( 36, 0, 0 );///**************new**************//Present the backbuffer to the screenSwapChain->Present(0, 0); }本節內容就到這里拉。
本節內容代碼可以在我的Github找到
游戲開發路途遙遠,但我相信只要堅持,總能到達彼岸!
如果我的文章對于你學習DirectX11有點幫助,歡迎評論給出建議,讓我們一起學習進步!
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?———————— 小明 2018.12.4?11.56
總結
以上是生活随笔為你收集整理的【DirectX11】【学习笔记(10)】混合的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: iOS开发中常用的方法
- 下一篇: 睡眼卫生