Chapter10 Stenciling (Introduction to 3D Game Programming with DirectX 11)笔记

Stencil buffer 和 Depth buffer同样大小,每个像素和depthBuffer, backBuffer都是一一对应的,都一样受到 ID3D11DepthStencilState 接口管理。

主要用途 使用stencil buffer阻止 往back buffer的特定区域写入。

10.1 DEPTH/STENCIL FORMATS AND CLEARING

depth和stencil buffer其实就是一张纹理,常用格式

1. DXGI_FORMAT_D32_FLOAT_S8X24_UINT: Specifies a 32-bit floating-point depth buffer, with 8-bits (unsigned integer) reserved for the stencil buffer mapped to the [0, 255] range and 24-bits not used for padding.

2. DXGI_FORMAT_D24_UNORM_S8_UINT: Specifies an unsigned 24-bit depth buffer mapped to the [0, 1] range with 8-bits (unsigned integer) reserved for the stencil buffer mapped to the [0, 255] range. 

有时需要在每帧开始reset buffer状态,调用ClearDepthStencilView。

10.2 THE STENCIL TEST

stecil test在 OM阶段执行,具体流程

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

定义StencilReadMask,定义StencilRef,两者& 和 实际 stencil buffer中value &StencilReadMask 比较

比较方式也就是中间 ⊴ 定义,D3D11_COMPARISON_FUNC

10.3 THE DEPTH/STENCIL STATE BLOCK

创建ID3D11DepthStencilState 接口 需要填充D3D11_DEPTH_STENCIL_DESC 结构体。

参数

DepthWriteMask:D3D11_DEPTH_WRITE_MASK_ZERO or D3D11_DEPTH_WRITE_MASK_ALL 禁止写入或者允许写入

StencilReadMask: 上面test时使用

StencilWriteMask: 默认0xff ,都允许写入,如果想禁止前四位,可以0x0f。

FrontFace:  用D3D11_DEPTH_STENCILOP_DESC 定义stencil 如何操作前面

BackFace:  用D3D11_DEPTH_STENCILOP_DESC 定义stencil 如何操作背面

这里面如何操作是指,比如stecil test 失败时是保留还是invert等等,同样还有 stecil test成功但depth test失败,stecil和depth都成功。

10.3.3 Creating and Binding a Depth/Stencil State

创建CreateDepthStencilState

bind到pipeline OMSetDepthStencilState,和其他state group一样,想用默认的depth stencil state,可以使用set时传入(0,0)。

10.3.4 Depth/Stencil States in Effect Files

state也可以直接定义在effect文件里面,不同就是没了一些dx前缀,比如填充DepthStencilState 结构体,然后pass里面调用SetDepthStencilState去设置。

10.4 IMPLEMENTING PLANAR MIRRORS

实现镜像,主要有两个问题需要解决,一个是如何把一个object反射到相对的平面,另一个是如何只在mirror内画,而不画到外面,这就需要用stencil标识出来可以绘制的区域。

步骤overview:

1.正常渲染wall,box等到 back buffer,但不修改stencil buffer

2.清理stencil buffer,重置为0,此时buffer状态如下,outline不表示任何数据,只表示一个对应区域,此时stencil buffer什么都没有

3.渲染mirror到stencil buffer,但是禁止 back buffer的写入

D3D11_RENDER_TARGET_BLEND_DESC::RenderTargetWriteMask = 0;

D3D11_DEPTH_STENCIL_DESC::DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO; 

把stencil test是设为 always succeed,D3D11_COMPARISON_ALWAYS

把if stencil test pass ,设为D3D11_STENCIL_OP_REPLACE 为1,把if failure,设为D3D11_STENCIL_OP_KEEP,注意这里是keep,不是置为0,因为可能有多面mirror,虽然这面mirror 失败,但可能那一面成功,设为1,因此要keep。会fail的情况发生在mirror的一部分被阻挡,比如镜子前挡住了一部分box,那这部分depth test就会失败。

另外很重要的一点是绘制mirror到stencil buffer这一步需要在 正常渲染box等等之后,这样才能在mirror在被挡住判断depth test的时候得到正确的结果,绘制mirror的时候才能知道自己depth test能不能通过,以来决定需不需要stencil test,此时buffer状态

4.skull需要被反射到镜子上,将skull轴对称过去之后,第四步渲染这个对称过去的skull搭配back buffer和stecil buffer,但是这里写入的条件是只有stencil test通过才写入,通过的条件是 StencilRef=1.

5.最后,渲染mirror到back buffer。由于需要显示反射,而对称过去的skull在镜子之后,因此mirror需要按照transparency半透明的方式blend,设定alpha=0.5,然后

mMirrorMat.Ambient = XMFLOAT4(0.5f, 0.5f, 0.5f, 1.0f); 

mMirrorMat.Diffuse = XMFLOAT4(1.0f, 1.0f, 1.0f, 0.5f);  这里最后一个component是0.5 alpha。

mMirrorMat.Specular = XMFLOAT4(0.4f, 0.4f, 0.4f, 16.0f);

These settings give the following blending equation: C = 0.5 · Csrc + 0.5 · Cdst

以上是基本流程,这其中有一个要注意的是Winding Order and Reflections

将一个triangle反射过去的时候,顶点顺序却没有,如果还是按照之前逆时针绕顶点得到face normal 的方式,会发现原本outward的normal变成了inward,因此渲染reflect 的skull时,需要告诉它改变 顶点得到face normal的方式,改为顺时针是face normal。

10.5 IMPLEMENTING PLANAR SHADOWS

渲染平面上的阴影投射,先找到被投射到的区域,然后在这个区域以半透明的方式画一个黑色的面片。

以这种方式绘制阴影,会导致一个artifact叫做“double blending”,这里可以使用stencil buffer来防止这种情况。

书中这里先计算了一个顶点p经过平行光或者点光源 cast之后的点位置,从而计算得到shadow位置,并最后给出来通用的位置计算公式,具体可以再看书。

这里重点说的是如何使用stencil来避免double blending。double blending的问题是说由于shadow的cast,同一个位置可能会多个triangle overlap到,导致一个阴影里,这个地方被blend很多次,阴影里有的地方会黑很多,如图:

解决方法是:首先一开始 所有stencil buffer被清空为0,在渲染shadow的时候,stencil test的通过条件是当前stencil值为0,才接受pixel去blend,并且这次tencil通过之后,就将stencil值设为1,从而下次就不会再通过,只会blend一次。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值