镜面,深度模板缓冲区

先上图

 

镜面涉及到了深度模板缓冲区。即模板运算和深度值运算都要进行

大体来说:

模板运算其实是个位运算,通过者写入模板缓存。(深度也要通过)

是谁的运算呢?

A:模板参考值&掩码

B:模板缓冲区的值&掩码

是什么样子的运算呢?

比大小,比函数,或者直接返回个bool变量

结果是什么呢?

结果,模板缓冲区的值可能不变,也可能各种变化。

模板缓冲区在哪里呢?

和深度缓冲区共享内存,第(i,j)个像素相互对应.

 

上面说了个大概,下一步再详细探讨下。

一、创建深度模板缓冲区

(1)深度设置:

是否启用深度测试?是否启用深度写入?测试深度的函数(一般是取最小值)?

(2)模板设置:

是否启用模版测试?读掩码?写掩码?模板缓冲区如何处理朝前的三角形和朝后的三角形?像素模版测试失败时,如何更新模板缓冲区?模版测试成功但是深度测试失败时,如何更新模板缓冲区?模版测试和深度测试成功时,如何更新模板缓冲区?模版测试使用什么比较函数?

(3)初始化时,创建深度模板状态
    ID3D10DepthStencilState* mDrawMirrorDSS;
    md3dDevice->CreateDepthStencilState(&dsDesc, &mDrawMirrorDSS);
    ID3D10DepthStencilState* mDrawReflectionDSS;
    md3dDevice->CreateDepthStencilState(&dsDesc, &mDrawReflectionDSS);

 

二、每帧:

1,清除深度模板缓存区
    md3dDevice->ClearDepthStencilView(mDepthStencilView, D3D10_CLEAR_DEPTH|D3D10_CLEAR_STENCIL, 1.0f, 0);

2,绑定模板深度缓存状态到管线,结束时恢复

绘制镜面


        md3dDevice->OMSetDepthStencilState(mDrawMirrorDSS, 1);
        drawMirror(pass);
        md3dDevice->OMSetDepthStencilState(0, 0);
 

绘制箱子的倒影


        md3dDevice->OMSetDepthStencilState(mDrawReflectionDSS, 1);
        mCrateMesh.draw();

        md3dDevice->OMSetDepthStencilState(0, 0);

 

三、对于镜面来说

1,不修改模板缓冲区,把地板,墙壁,镜子和板条箱渲染到后台缓冲区

 

2,将模板缓冲区清0

3,把镜子渲染到模板缓冲区,成功时,模板缓冲区元素替代为1,即1是镜子区域的标志位


    dsDesc.DepthEnable = true;
    dsDesc.DepthWriteMask = D3D10_DEPTH_WRITE_MASK_ALL;
    dsDesc.DepthFunc = D3D10_COMPARISON_LESS;
    dsDesc.StencilEnable = true;
    dsDesc.StencilReadMask = 0xff;
    dsDesc.StencilWriteMask = 0xff;

    dsDesc.FrontFace.StencilFailOp = D3D10_STENCIL_OP_KEEP;
    dsDesc.FrontFace.StencilDepthFailOp = D3D10_STENCIL_OP_KEEP;
    dsDesc.FrontFace.StencilPassOp = D3D10_STENCIL_OP_REPLACE;
    dsDesc.FrontFace.StencilFunc = D3D10_COMPARISON_ALWAYS;

4,将板条箱影像渲染到后台缓冲区和模板缓冲区,这里有1才渲染,也就是在镜子区域才渲染。因为板条箱影像在墙壁后,所以深度测试函数要设定为始终成功,且要禁用深度写入,避免板条箱映像的深度值来更新深度缓冲区


    dsDesc.DepthEnable = true;
    dsDesc.DepthWriteMask = D3D10_DEPTH_WRITE_MASK_ZERO;
    dsDesc.DepthFunc = D3D10_COMPARISON_ALWAYS;
    dsDesc.FrontFace.StencilPassOp = D3D10_STENCIL_OP_KEEP;
    dsDesc.FrontFace.StencilFunc = D3D10_COMPARISON_EQUAL;

 

5,对映像于镜子进行混合,颜色加权平均值作为最终颜色。


    D3D10_BLEND_DESC blendDesc = { 0 };
    blendDesc.AlphaToCoverageEnable = false;
    blendDesc.BlendEnable[0] = true;
    blendDesc.SrcBlend = D3D10_BLEND_BLEND_FACTOR;
    blendDesc.DestBlend = D3D10_BLEND_INV_BLEND_FACTOR;
    blendDesc.BlendOp = D3D10_BLEND_OP_ADD;
    blendDesc.SrcBlendAlpha = D3D10_BLEND_ONE;
    blendDesc.DestBlendAlpha = D3D10_BLEND_ZERO;
    blendDesc.BlendOpAlpha = D3D10_BLEND_OP_ADD;
    blendDesc.RenderTargetWriteMask[0] = D3D10_COLOR_WRITE_ENABLE_ALL;

    md3dDevice->CreateBlendState(&blendDesc, &mDrawReflectionBS);

 

6,对j板条箱映像的三角形环绕顺序和平面法线反转。

(1)创建

    D3D10_RASTERIZER_DESC rsDesc;
    ZeroMemory(&rsDesc, sizeof(D3D10_RASTERIZER_DESC));
    rsDesc.FillMode = D3D10_FILL_SOLID;
    rsDesc.CullMode = D3D10_CULL_BACK;
    rsDesc.FrontCounterClockwise = true;

    md3dDevice->CreateRasterizerState(&rsDesc, &mCullCWRS);
(2)每帧渲染:

    md3dDevice->RSSetState(mCullCWRS);
        float blendf[] = { 0.65f, 0.65f, 0.65f, 1.0f };
        md3dDevice->OMSetBlendState(mDrawReflectionBS, blendf, 0xffffffff);
        md3dDevice->OMSetDepthStencilState(mDrawReflectionDSS, 1);
        mCrateMesh.draw();

7,当绘制板条箱映像时,为了使影像中的光照显得真实,需要在镜子平面反射光源

    D3DXPLANE mirrorPlane(0.0f, 0.0f, 1.0f, 0.0f);
        D3DXMATRIX R;
        D3DXMatrixReflect(&R, &mirrorPlane);

    D3DXVECTOR3 oldDir = mParallelLight.dir;
        D3DXVec3TransformNormal(&mParallelLight.dir, &mParallelLight.dir, &R);
        mfxLightVar->SetRawValue(&mParallelLight, 0, sizeof(Light));

8,在每帧的最后,不要忘记恢复状态


        md3dDevice->OMSetDepthStencilState(0, 0);
        md3dDevice->OMSetBlendState(0, blendf, 0xffffffff);
        md3dDevice->RSSetState(0);
        mParallelLight.dir = oldDir;

注意的是,这个例子并没有在shader里更改深度模板状态。

 

 

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值