• 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

  • 相关阅读:
    jquery json简单例子
    使用面向对象的技术创建高级 Web 应用程序 文章来源:http://msdn.microsoft.com/zhcn/magazine/cc163419.aspx本文讨论:
    asp.net C# 下母版页使用
    SQL2005附加数据库"失败........无法更新数据库"xxx",因为数据库是只读
    转载 37个Ajax和CSS实现的Tab选项卡切换效果界面
    php substr,iconv_substr,mb_substr
    PHP的$_SERVER['HTTP_HOST']获取服务器地址功能详解,$_SERVER['HTTP_X_FORWARDED_HOST']
    js
    vue跨域处理(vue项目中baseUrl设置问题)
    从今天开始,争取每周都至少写一篇随笔
  • 原文地址:https://www.cnblogs.com/mikewolf2002/p/2502149.html
Copyright © 2020-2023  润新知