1. 程式人生 > >Directx11教程(49) stencil的應用-鏡面反射

Directx11教程(49) stencil的應用-鏡面反射

targe item scrip tex mod mirror esc ike 鏡面反射

原文:Directx11教程(49) stencil的應用-鏡面反射

     本教程中,我們利用stencil來實現一個鏡面反射效果。

1、首先我們要在D3DClass中增加幾個成員變量及函數。

ID3D11DepthStencilState* m_depthStencilStateMirror;
ID3D11DepthStencilState* m_depthStencilStateReflect;

m_depthStencilStateMirror是渲染鏡子時候,使用的depth stencil 狀態,我們設置stencil 函數為D3D11_COMPARISON_ALWAYS,這樣,stencil測試總能pass,然後pass的操作為D3D11_STENCIL_OP_REPLACE,這樣,會用設置的ref值

填充stencil buffer。

depthStencilDesc.DepthEnable = true;
depthStencilDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL

depthStencilDesc.DepthFunc = D3D11_COMPARISON_LESS;

depthStencilDesc.StencilEnable = true;
depthStencilDesc.StencilReadMask = 0xFF;
depthStencilDesc.StencilWriteMask = 0xFF;

// 對於front face 像素使用的模版操作操作.
depthStencilDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
depthStencilDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP;
depthStencilDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_REPLACE;
depthStencilDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;

// 對於back face像素使用的模版操作模式.
depthStencilDesc.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
depthStencilDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_DECR;
depthStencilDesc.BackFace.StencilPassOp = D3D11_STENCIL_OP_REPLACE;
depthStencilDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS;

// 創建深度模版狀態,使其生效
result = m_device->CreateDepthStencilState(&depthStencilDesc, &m_depthStencilStateMirror);
if(FAILED(result))
    {
    HR(result);
    return false;

    }

m_depthStencilStateReflect用來渲染鏡子中反射的物體,此時禁止depth test,使depth test總是pass,stencil函數用等於比較,及當前的stencil ref值和stencil buffer中的值比較,等於則pass stencil test。

// 設置reflect object深度模版狀態描述.
depthStencilDesc.DepthEnable = true;
depthStencilDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO;//D3D11_DEPTH_WRITE_MASK_ZERO禁止寫深度緩沖
depthStencilDesc.DepthFunc = D3D11_COMPARISON_ALWAYS;

// 對於front face 像素使用的模版操作操作.
depthStencilDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
depthStencilDesc.FrontFace.StencilFunc = D3D11_COMPARISON_EQUAL;

// 創建深度模版狀態,使其生效
result = m_device->CreateDepthStencilState(&depthStencilDesc, &m_depthStencilStateReflect);
if(FAILED(result))
    {
    HR(result);
    return false;

    }

m_alphaEnableBlendingState狀態變量創建一個alpha blend狀態,這個狀態主要在渲染鏡子中物體時候使用,因為我們的鏡面是一個紋理表示,alpha blend會把鏡面紋理和渲染物體進行混合操作。

// 創建一個alpha blend狀態.
blendStateDescription.RenderTarget[0].BlendEnable = TRUE;
//blendStateDescription.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE;
blendStateDescription.RenderTarget[0].SrcBlend = D3D11_BLEND_BLEND_FACTOR;
blendStateDescription.RenderTarget[0].DestBlend = D3D11_BLEND_INV_BLEND_FACTOR;
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;
    }

另外還有一個函數ChangeBackCullMode(bool b),用來改變渲染狀態,設置front face 為順時針渲染。因為在渲染鏡子中物體時候,鏡子中物體正面其實對應物體的反面,這是需要改變渲染次序。

下面的幾個函數用來改變這幾個新增加的狀態。

void TurnOnAlphaBlending();
void TurnOffAlphaBlending();
void ChangeBackCullMode(bool b);

void EnableDefaultDepthStencil();
void EnableMirrorDepthStencil();
void EnableReflectDepthStencil();

2、D3Dclass中的BeginSence函數小改動,每幀渲染之前清除stencil值為0

void D3DClass::BeginScene(float red, float green, float blue, float alpha)
    {

    //清除深度緩沖.
    m_deviceContext->ClearDepthStencilView(m_depthStencilView, D3D11_CLEAR_DEPTH|D3D11_CLEAR_STENCIL, 1.0f, 0);


    return;
    }

3、增加了一個MirrorModelClass類用來表示鏡子的mesh。

4、在graphicsClass類中依次渲染物體

    首先渲染地面,墻以及box

    m_D3D->EnableMirrorDepthStencil();

    渲染鏡子

     m_D3D->EnableDefaultDepthStencil();

     定義鏡子反射平面,計算反射矩陣,註意D3DXMatrixReflect計算反射矩陣時候,對平面進行了歸一化,所以我加了一個平移操作。

D3DXPLANE mirrorPlane(0.0, 0.0, 10.99, 0.0);
D3DXMATRIX R;
//得到基於mirrorPlane平面的反射矩陣
D3DXMatrixReflect(&R, &mirrorPlane);
//box在原點位置,沒有變化,它的世界坐標矩陣為worldMatrix
D3DXMATRIX W = worldMatrix * R;
D3DXMatrixTranslation(&worldMatrix1, 0.0, 0.0, -18.0);
W = worldMatrix1*W;

     接下來,設置狀態

m_D3D->EnableReflectDepthStencil();
m_D3D->TurnOnAlphaBlending();
m_D3D->ChangeBackCullMode(true);

渲染鏡子中box

m_D3D->EnableDefaultDepthStencil();
m_D3D->TurnOffAlphaBlending();
m_D3D->ChangeBackCullMode(false);

程序最終的效果如下:

技術分享圖片

完整的代碼請參考:

工程文件myTutorialD3D11_43

代碼下載:

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

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

Directx11教程(49) stencil的應用-鏡面反射