zoukankan      html  css  js  c++  java
  • 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);

    程序最终的效果如下:

    image

    完整的代码请参考:

    工程文件myTutorialD3D11_43

    代码下载:

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

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

  • 相关阅读:
    Samba 4.0 RC3 发布
    SymmetricDS 3.1.7 发布,数据同步和复制
    Express.js 3.0 发布,Node.js 的高性能封装
    GIFLIB 5.0.1 发布,C语言的GIF处理库
    jQuery UI 1.9.1 发布
    SVN Access Manager 0.5.5.14 发布 SVN 管理工具
    DynamicReports 3.0.3 发布 Java 报表工具
    HttpComponents HttpClient 4.2.2 GA 发布
    AppCan 2.0 正式发布,推移动应用云服务
    Ruby 2.0 的新功能已经冻结
  • 原文地址:https://www.cnblogs.com/mikewolf2002/p/2502149.html
Copyright © 2011-2022 走看看