这节教程可以作为我的那节 “”D3D11教程十九之平面反射(planar reflect)“”的补充,那节教程的反射镜像是利用RenderToTexture技术生成的反射纹理形成的,而这节教程的镜像是基于stencilBuffer和DepthBuffer技术形成的.
首先给出这节教程的结构:
bool GraphicsClass::RenderNormalScene()
{
//三个变换矩阵
XMMATRIX WorldMatrix, ViewMatrix, ProjMatrix;
bool result;
/********************第一,进行立方体的渲染****************************/
//清除缓存开始绘制场景
mD3D->BeginScene(0.3f, 0.2f, 0.f, 1.0f);
//(更新)获取ViewMatrix(根据CameraClass的mPostion和mRotation来生成的)
mCamera->Render();
//获取三个变换矩阵(WorldMatrix和ProjMatrix来自mD3D类,ViewMatrix来自CameraClass)
WorldMatrix = mD3D->GetWorldMatrix();
ProjMatrix = mD3D->GetProjMatrix();
ViewMatrix = mCamera->GetViewMatrix();
//将立方体的顶点数据和索引数据放入3D渲染流水线
mCubeModel->Render(mD3D->GetDeviceContext());
//绘制立方体
result = mColorShader->Render(mD3D->GetDeviceContext(), mCubeModel->GetIndexCount(), WorldMatrix, ViewMatrix, ProjMatrix, mCubeModel->GetTexture(), mLight->GetDiffuseColor(), mLight->GetLightDirection());
if (!result)
{
MessageBox(NULL, L"ColorShader Render failure", NULL, MB_OK);
return false;
}
/********************第二,进行地面的渲染****************************/
//将世界变换矩阵绕X轴顺时针旋转90度 XMMATRIXROATATION 得从 XYZ正轴看才是顺时针
//重新获取世界变换矩阵
WorldMatrix = mD3D->GetWorldMatrix();
WorldMatrix = WorldMatrix*XMMatrixTranslation(0, -2.0f, 0);
//将地面的顶点数据和索引数据放入3D渲染流水线
mFloorModel->Render(mD3D->GetDeviceContext());
//绘制地面
result = mColorShader->Render(mD3D->GetDeviceContext(), mFloorModel->GetIndexCount(), WorldMatrix, ViewMatrix, ProjMatrix, mFloorModel->GetTexture(), mLight->GetDiffuseColor(), mLight->GetLightDirection());
if (!result)
{
MessageBox(NULL, L"ColorShader Render failure", NULL, MB_OK);
return false;
}
/********************第三,进行墙面的渲染****************************/
//重新获取世界变换矩阵
WorldMatrix = mD3D->GetWorldMatrix();
WorldMatrix = WorldMatrix *XMMatrixRotationX(-3.14f/2.0f)*XMMatrixTranslation(0, 0.0f, 5.0f);
//将墙面的顶点数据和索引数据放入3D渲染流水线
mWallModel->Render(mD3D->GetDeviceContext());
//绘制墙面
result = mColorShader->Render(mD3D->GetDeviceContext(), mWallModel->GetIndexCount(), WorldMatrix, ViewMatrix, ProjMatrix, mWallModel->GetTexture(), mLight->GetDiffuseColor(), mLight->GetLightDirection());
if (!result)
{
MessageBox(NULL, L"ColorShader Render failure", NULL, MB_OK);
return false;
}
return true;
}
ID3D11DepthStencilState* md3dMarkMirrorDSS; //给镜面部分写入遮掩码的深度(模板)缓存状态
ZeroMemory(&DSDESC, sizeof(DSDESC));
DSDESC.DepthEnable = true; //深度测试开启
DSDESC.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO; //深度写无效
DSDESC.DepthFunc = D3D11_COMPARISON_LESS; //在墙面之前
DSDESC.StencilEnable = true; //模板测试开启
DSDESC.StencilReadMask = 0xff;
DSDESC.StencilWriteMask = 0xff;
//前面设定
DSDESC.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; //stencil失败 怎么更新stencil buffer
DSDESC.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP;// stencil通过,但depth失败
DSDESC.FrontFace.StencilPassOp = D3D11_STENCIL_OP_REPLACE; //stencil通过 depth通过
DSDESC.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS; //总是能通过StencilTest
//背面设定,在光栅化状态剔除背面时这个设定没用,但是依然要设定,不然无法创建深度(模板)状态
DSDESC.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
DSDESC.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP;
DSDESC.BackFace.StencilPassOp = D3D11_STENCIL_OP_REPLACE;
DSDESC.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
HR(md3dDevice->CreateDepthStencilState(&DSDESC, &md3dMarkMirrorDSS));
4,DSDESC.FrontFace.StencilPassOp = D3D11_STENCIL_OP_REPLACE;
当stencilTest成功,并且depthTest成功时,相应位置的stencilBuffer的值被 StencilRef所代替
md3dImmediateContext->OMSetDepthStencilState(md3dMarkMirrorDSS,1);
看上面函数的第二个参数1就是StencilRef
//清除深度缓存和模板缓存,设置每帧初始值
md3dImmediateContext->ClearDepthStencilView(md3dDepthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);
像上面这条函数,最后一个参数为StencilBuffer中每个位置的初始值,倒数第二个参数为DepthBuffer每个位置的初始值.
ZeroMemory(&DSDESC, sizeof(DSDESC));
DSDESC.DepthEnable = true; //深度测试开启
DSDESC.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO; //深度写
DSDESC.DepthFunc = D3D11_COMPARISON_ALWAYS; //总能通过Z缓存测试
DSDESC.StencilEnable = true; //模板测试开启
DSDESC.StencilReadMask = 0xff;
DSDESC.StencilWriteMask = 0xff;
//前面设定
DSDESC.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; //stencil失败 怎么更新stencil buffer
DSDESC.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP;// stencil通过,但depth失败
DSDESC.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP; //stencil通过 depth通过
DSDESC.FrontFace.StencilFunc = D3D11_COMPARISON_EQUAL; //总是能通过StencilTest
//背面设定,在光栅化状态剔除背面时这个设定没用,但是依然要设定,不然无法创建深度(模板)状态
DSDESC.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
DSDESC.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP;
DSDESC.BackFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
DSDESC.BackFace.StencilFunc = D3D11_COMPARISON_EQUAL;
HR(md3dDevice->CreateDepthStencilState(&DSDESC, &md3dDrawReflectionDSS));
DSDESC.StencilEnable = true;
md3dImmediateContext->OMSetDepthStencilState(md3dDrawReflectionDSS, 1);
ID3D11RasterizerState* md3dCounterClockRasterizerState; //逆时针的D3D的光栅化状态
rasterDesc.AntialiasedLineEnable = false;
rasterDesc.CullMode = D3D11_CULL_BACK; //背面剔除
rasterDesc.DepthBias = 0;
rasterDesc.DepthBiasClamp = 0.0f;
rasterDesc.DepthClipEnable = true; //深度裁剪开启
rasterDesc.FillMode = D3D11_FILL_SOLID; //实体渲染
rasterDesc.FrontCounterClockwise = true; //逆时针绕线方向
rasterDesc.MultisampleEnable = false;
rasterDesc.ScissorEnable = false;
rasterDesc.SlopeScaledDepthBias = 0.0f;
/*******************第二,绘制立方体反射的镜像的镜像,遮掩码为1的地方才能看到镜像*******************************/
//重新获取世界变换矩阵
WorldMatrix = mD3D->GetWorldMatrix();
//设置逆时针的光栅化状态,改变绕线方向
mD3D->SetCounterClockRasterizerState();
//设置绘制反射镜像的深度状态
mD3D->SetDrawReflectionMarkDepthStencilState();
//求出反射矩阵
XMVECTOR ReflectPlane = XMVectorSet(0.0f, 0.0f, 1.0f, -4.9f);
XMMATRIX ReflecMatrix = XMMatrixReflect(ReflectPlane);
WorldMatrix = WorldMatrix*ReflecMatrix;
//把立方体的数据放进3D渲染流水线
mCubeModel->Render(mD3D->GetDeviceContext());
//第五,绘制立方体
result = mColorShader->Render(mD3D->GetDeviceContext(), mCubeModel->GetIndexCount(), WorldMatrix, ViewMatrix, ProjMatrix, mCubeModel->GetTexture(), mLight->GetDiffuseColor(), mLight->GetLightDirection());
if (!result)
{
MessageBox(NULL, L"ColorShader Render failure", NULL, MB_OK);
return false;
}
//重新获取世界变换矩阵
WorldMatrix = mD3D->GetWorldMatrix();
WorldMatrix = WorldMatrix *XMMatrixRotationX(-XM_PI / 2.0f)*XMMatrixScaling(0.6f, 1.0f, 1.0f)*XMMatrixTranslation(0, 0.0f, 4.9f);
//最后一步,光栅化状态,深度缓存状态恢复为默认状态
mD3D->SetDefaultDepthStencilState();
mD3D->SetDefaultRasterizerState();
//设置混合状态,使得镜像能和镜面混合
mD3D->TurnOnBaseAlphaBlend();
//将镜面的顶点数据和索引数据放入3D渲染流水线
mMirrorModel->Render(mD3D->GetDeviceContext());
//绘制镜面
result = mColorShader->Render(mD3D->GetDeviceContext(), mMirrorModel->GetIndexCount(), WorldMatrix, ViewMatrix, ProjMatrix, mMirrorModel->GetTexture(), mLight->GetDiffuseColor(), mLight->GetLightDirection());
if (!result)
{
MessageBox(NULL, L"ColorShader Render failure", NULL, MB_OK);
return false;
}
//关闭混合状态
mD3D->TurnOffAlphaBlend();