六狼论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

新浪微博账号登陆

只需一步,快速开始

搜索
查看: 313|回复: 0

Directx11教程(49) stencil的应用-镜面反射

[复制链接]

升级  91.33%

154

主题

154

主题

154

主题

举人

Rank: 3Rank: 3

积分
474
 楼主| 发表于 2012-12-12 00:27:46 | 显示全部楼层 |阅读模式
Directx11教程(49) stencil的应用-镜面反射

<div class="postbody"><div id="cnblogs_post_body">     本教程中,我们利用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
      
您需要登录后才可以回帖 登录 | 立即注册 新浪微博账号登陆

本版积分规则

快速回复 返回顶部 返回列表