zoukankan      html  css  js  c++  java
  • 在DirectX12中使用stencil buffer

    stencil buffer通常在实现一些特殊的效果时使用的,这里我们以实现一个object的shadow为例,来看看具体怎么使用它。

    首先需要创建一个和要实现shadow的object一样的object,作为shadow object。然后对其应用shadow matrix变换:

    	XMMATRIX world = XMLoadFloat4x4(&object->mWorldMatrix);
    	XMVECTOR shadowPlane = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f); // xz plane
    	XMVECTOR toMainLight = XMVectorSet(-0.57735f, 0.57735f, -0.57735f, 0.0f);
    	XMMATRIX shadow = XMMatrixShadow(shadowPlane, toMainLight);
    	XMMATRIX shadowOffsetY = XMMatrixTranslation(0.0f, 0.001f, 0.0f);
    	XMStoreFloat4x4(&object->mWorldMatrix, world * shadow * shadowOffsetY);
    

    这里的shadowOffsetY是用来避免阴影本身和接收阴影的平面重合导致z-fighting而设置的。接下来,讲道理我们只需要直接绘制阴影,让其与接收阴影的平面blend即可,但是这样可能会出现double blending的现象,即一个像素可能是由多个阴影像素同时blend而成,这样会导致绘制出的阴影颜色不均,有的地方深有的地方浅。

    因此,为了阻止double blending,需要引入模板缓存,思路其实很简单,就是绘制过阴影像素的地方做下标记,后面如果还有阴影像素要在此处绘制,直接返回失败。启用模板缓存,模板测试相关的设置都在D3D12_GRAPHICS_PIPELINE_STATE_DESC数据结构中,我们只需要设置好,创建相应的pipelineStateObject即可:

    		D3D12_DEPTH_STENCIL_DESC stencilDesc;
    		stencilDesc.BackFace.StencilDepthFailOp = D3D12_STENCIL_OP_KEEP;
    		stencilDesc.BackFace.StencilFailOp = D3D12_STENCIL_OP_KEEP;
    		stencilDesc.BackFace.StencilFunc = D3D12_COMPARISON_FUNC_EQUAL;
    		stencilDesc.BackFace.StencilPassOp = D3D12_STENCIL_OP_INCR;
    		stencilDesc.DepthEnable = true;
    		stencilDesc.DepthFunc = D3D12_COMPARISON_FUNC_LESS;
    		stencilDesc.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL;
    		stencilDesc.FrontFace.StencilDepthFailOp = D3D12_STENCIL_OP_KEEP;
    		stencilDesc.FrontFace.StencilFailOp = D3D12_STENCIL_OP_KEEP;
    		stencilDesc.FrontFace.StencilFunc = D3D12_COMPARISON_FUNC_EQUAL;
    		stencilDesc.FrontFace.StencilPassOp = D3D12_STENCIL_OP_INCR;
    		stencilDesc.StencilEnable = true;
    		stencilDesc.StencilReadMask = 0xff;
    		stencilDesc.StencilWriteMask = 0xff;
    		psoDesc.DepthStencilState = stencilDesc;
    

    每次绘制前,我们都会清空深度缓存和模板缓存,并把模板参考值设置为0:

    mCommandList->ClearDepthStencilView(dsv, D3D12_CLEAR_FLAG_DEPTH | D3D12_CLEAR_FLAG_STENCIL, 1.0f, 0, 0,
    		nullptr);
    mCommandList->OMSetStencilRef(0);
    

    这样就能保证阴影像素第一次写入时,模板测试是通过的;然后模板缓存里的值就会+1,这样后续再有阴影像素写入相同位置时,因为参考值(0)与此时模板缓存里的值(1)不相等,导致模板测试失败,进而无法写入像素,也就达到了我们的预期。运行效果如下:

    如果你觉得我的文章有帮助,欢迎关注我的微信公众号(大龄社畜的游戏开发之路-

  • 相关阅读:
    堆栈学习
    需要阅读的书籍
    Rust Book Lang Ch.19 Fully Qualified Syntax, Supertraits, Newtype Pattern, type aliases, never type, dynamic sized type
    Rust Lang Book Ch.19 Placeholder type, Default generic type parameter, operator overloading
    Rust Lang Book Ch.19 Unsafe
    Rust Lang Book Ch.18 Patterns and Matching
    Rust Lang Book Ch.17 OOP
    Rust Lang Book Ch.16 Concurrency
    Rust Lang Book Ch.15 Smart Pointers
    HDU3966-Aragorn's Story-树链剖分-点权
  • 原文地址:https://www.cnblogs.com/back-to-the-past/p/14546982.html
Copyright © 2011-2022 走看看