DirectX11 深度/模板状态

深度/模板状态

1. 深度/模板描述

当创建ID3D11DepthStencilState接口时,第一步是要填充一个D3D11_DEPTH_STENCIL_DESC实例:

typedef struct D3D11_DEPTH_STENCIL_DESC{
    BOOL DepthEnable;//默认True

    // 默认:D3D11_DEPTH_WRITE_MASK_ALL
    D3D11_DEPTH_WRITE_MASK DepthWriteMask;
    // 默认:D3D11_COMPARISON_LESS
    D3D11_COMPARISON_FUNC DepthFunc;

    BOOL StencilEnable;// 默认:False
    UINT8 StencilReadMask;// 默认:0xff
    UINT8 StencilWriteMask;// 默认:0xff
    D3D11_DEPTH_STENCILOP_DESC FrontFace;
    D3D11_DEPTH_STENCILOP_DESC BackFace;
}D3D11_DEPTH_STENCIL_DESC;

2. 深度设置

1.DepthEnable:当设为true时,表示启用深度测试;当设为false时,表示禁用深度测试。当禁用深度测试时,绘图顺序非常重要,因为在这种情况下障碍物后面的像素片段也会被绘制出来(回顾4.1.5节)。如果禁用深度测试,那么无论DepthWriteMask设定何值,深度缓冲区中的元素都不会被更新。

2.DepthWriteMask:可设为D3D11_DEPTH_WRITE_MASK_ZERO或D3D11_DEPTH_WRITE_MASK_ALL。这两个标志值不能同时使用。当DepthEnable设为true时,D3D11_DEPTH_WRITE_MASK_ZERO表示禁用深度缓冲区的写入功能,但深度测试依然有效。D3D11_DEPTH_WRITE_MASK_ALL表示启用深度缓冲区的写入功能;当深度/模板测试都通过时,新的深度值会被写入深度缓冲区。

3.DepthFunc:一个用于描述深度测试函数的D3D11_COMPARISON_FUNC枚举类型成员。我们一般使用D3D11_COMPARISON_LESS实现普通的深度测试,如4.1.5节所述。也就是,当像素片段的深度值比之前写入后台缓冲区的像素的深度值小时,接受该像素片段(即,将该像素片段写入后台缓冲区,将该像素片段的深度值写入深度缓冲区)。另外, Direct3D支持自定义的深度测试函数。如果有必要的话,你可以自定义深度测试函数。

3. 模板设置

1.StencilEnable:当设为true时,表示启用模板测试;当设为false时,表示禁用模板测试。

2.StencilReadMask:在模板测试时使用的掩码:

if( StencilRef & StencilReadMask  ⊴  Value &StencilReadMask)
    accept pixel
else
    reject pixel

默认掩码不屏蔽任何二进制位:

#define D3D11_DEFAULT_STENCIL_READ_MASK (0xff)

3.StencilWriteMask: 当更新模板缓冲区时,我们可以通过掩码来屏蔽某些二进制位,不让它们存入模板缓冲区。例如,当你希望屏蔽前4位数据时,可将掩码设为0x0f。默认掩码不屏蔽任何二进制位:

#define D3D11_DEFAULT_STENCIL_WRITE_MASK (0xff)

4.FrontFace:一个已填充的D3D11_DEPTH_STENCILOP_DESC结构体,它告诉模板缓冲区如何处理朝前的三角形。

typedef struct D3D11_DEPTH_STENCILOP_DESC {
    D3D11_STENCIL_OP StencilFailOp;// Default:D3D11_STENCIL_OP_KEEP
    D3D11_STENCIL_OP StencilDepthFailOp;// Default:D3D11_STENCIL_OP_KEEP
    D3D11_STENCIL_OP StencilPassOp; // Default:D3D11_STENCIL_OP_KEEP
    D3D11_COMPARISON_FUNC StencilFunc; // Default:D3D11_ COMPARISON_ALWAYS
} D3D11_DEPTH_STENCILOP_DESC;

1.StencilFailOp:D3D11_STENCIL_OP枚举类型成员,它描述了当一个像素片段的模板测试失败时,应如何更新模板缓冲区。

typedef enum D3D11_STENCIL_OP
{
    D3D11_STENCIL_OP_KEEP = 1,
    D3D11_STENCIL_OP_ZERO = 2,
    D3D11_STENCIL_OP_REPLACE = 3,
    D3D11_STENCIL_OP_INCR_SAT = 4,
    D3D11_STENCIL_OP_DECR_SAT = 5,
    D3D11_STENCIL_OP_INVERT = 6,
    D3D11_STENCIL_OP_INCR = 7,
    D3D11_STENCIL_OP_DECR = 8,
} D3D11_STENCIL_OP;

1.D3D11_STENCIL_OP_KEEP:不更新模板缓冲区;也就是,当前值保持不变。
2.D3D11_STENCIL_OP_ZERO:将模板缓冲区元素设为0。
3.D3D11_STENCIL_OP_REPLACE:以模板测试中的模板参考值(StencilRef)替换模板缓冲区元素。注意,当我们将深度/模板状态块绑定到渲染管线上时(参见10.3.3节),StencilRef值就已经被确定下来了。
4.D3D11_STENCIL_OP_INCR_SAT:递增模板缓冲区元素。如果递增之后的值大于最大值(比如,255是8位模板缓冲区的最大值),则将其舍入为最大值。
5.D3D11_STENCIL_OP_DECR_SAT:递减模板缓冲区元素。如果递减之后的值小于 0,则将其舍入为0。
6.D3D11_STENCIL_OP_INVERT:反转模板缓冲区元素的二进制位。
7.D3D11_STENCIL_OP_INCR:递增模板缓冲区元素。如果递增之后的值大于最大值(比如,255是8位模板缓冲区的最大值),则将其折反为0。
8.D3D11_STENCIL_OP_DECR:递减模板缓冲区元素。如果递减之后的值小于0,则将其折反为最大值。

2.StencilDepthFailOp:D3D11_STENCIL_OP枚举类型成员,它描述了当一个像素片段的模板测试成功而深度测试失败时,应如何更新模板缓冲区。
3.StencilPassOp:D3D11_STENCIL_OP枚举类型成员,它描述了当一个像素片段的模板测试和深度测试均成功时,应如何更新模板缓冲区。
4.StencilFunc:D3D11_COMPARISON_FUNC枚举类型成员,指定模板测试时使用的比较函数。

5.BackFace:一个已填充的D3D11_DEPTH_STENCILOP_DESC结构体,它告诉模板缓冲区如何处理朝后的三角形。

注意:我们一般不使用BackFace参数,因为当启用背面消隐时,Direct3D根本不会渲染朝后的多边形。不过,有时我们会为了实现某些绘图算法或绘制透明几何体(比如在绘制铁丝立方体时,我们希望看到铁丝网立方体的背面)而渲染朝后的多边形。在这种情况下应该使用BackFace参数。

4. DirectX11创建和绑定深度/模板状态

在填充D3D11_DEPTH_STENCIL_DESC结构体之后,我们可以调用如下方法获取一个指向ID3D11DepthStencilState接口的指针:

HRESULT ID3D11Device::CreateDepthStencilState(
    const D3D11_DEPTH_STENCIL_DESC *pDepthStencilDesc,
    ID3D11DepthStencilState **ppDepthStencilState);

1.pDepthStencilDesc:一个已填充的D3D11_DEPTH_STENCIL_DESC结构体的指针,该结构体描述了所要创建的深度/模板状态块。

2.ppDepthStencilState:返回创建后的ID3D11DepthStencilState接口的指针。

在创建ID3D11DepthStencilState接口后,我们使用如下方法将它绑定到管线的输出合并器阶段:

void ID3D11DeviceContext::OMSetDepthStencilState(
    ID3D11DepthStencilState *pDepthStencilState,
    UINT StencilRef);

1.pDepthStencilState:深度/模板状态块的指针。

2.StencilRef:模板测试使用的32位模板参考值。

与其他状态块相同,深度/模板状态也有一个默认值(它使用普通的深度测试,并禁用模板测试)。通过给OMSetDepthStencilState方法的第1个参数传递一个空值就可以将深度/模板状态恢复为默认值。

// 恢复为默认值
md3dImmediateContext->OMSetDepthStencilState(0, 0);

5. Effect文件创建和绑定深度/模板状态

在effect文件中可以直接定义和设置深度/模板状态:

DepthStencilState DSS
{
     DepthEnable = true;
     DepthWriteMask = Zero;
     StencilEnable = true;
     StencilReadMask = 0xff;
     StencilWriteMask = 0xff;
     FrontFacetencilFunc = Always;
     FrontFaceStencilPass =  Incr;
     FrontFaceStencilFail = Keep;
     BackFaceStencilFunc = Always;
     BackFaceStencilPass =  Incr;
     BackFaceStencilFail = Keep;
} ;
...
technique11 Tech
{
     pass P0
     {
         SetVertexShader(CompileShader(vs_5_0,VS()));
         SetGeometryShader(NULL);
         SetPixelShader(CompileShader(ps_5_0,PS()));
         SetDepthStencilState(DSS, 0);
     }
}

在深度/模板状态对象中指定的些值与在C++结构体中指定的值基本相同,只是省去了一些前缀。例如,我们在效果代码中指定是INCR,而不是D3D11_STENCIL_OP_INCR。顺便提一句,我们指定的状态值是不区分大小写的;例如,INCR等价于Incr。

你可能感兴趣的:(模板,深度,游戏开发,Direct3D,directx11)