D3D 模板缓存的创建过程

下面是我对模板缓存创建的理解:

1. 模板缓存是和深度缓存一起被创建的,将深度缓存的一部分作为模板缓存使用。

深度缓存和模板缓存是在Direct3D初始化时创建的,D3DPRESENT_PARAMETERS结构便包含了深度缓存和模板缓存的格式

typedef struct D3DPRESENT_PARAMETERS {
 UINT               BackBufferWidth;
 UINT               BackBufferHeight;
 D3DFORMAT          BackBufferFormat;
 UINT               BackBufferCount;
 D3DMULTISAMPLE_TYPE MultiSampleType;
 DWORD               MultiSampleQuality;
 D3DSWAPEFFECT       SwapEffect;
 HWND                hDeviceWindow;
 BOOL                Windowed;
 BOOL               EnableAutoDepthStencil;
 D3DFORMAT          AutoDepthStencilFormat;
 DWORD               Flags;
 UINT                FullScreen_RefreshRateInHz;
 UINT               PresentationInterval;
} D3DPRESENT_PARAMETERS,*LPD3DPRESENT_PARAMETERS;

D3DFORMAT          AutoDepthStencilFormat;

可以有以下取值:

D3DFMT_D24S8    创建一个32位深度/模版缓存,其中24位为深度缓存,8位为模版缓存。

D3DFMT_D24X4S4    创建一个32位深度/模版缓存,其中24位为深度缓存,4位为模版缓存,还有4位留着不用。

D3DFMT_D15S1    创建一个16位深度/模版缓存,其中15位为深度缓存,1位为模版缓存。

 

2. 使用模板缓存前需要启用模板缓存

下面是启用和关闭模板缓存代码

Device->SetRenderState(D3DRS_STENCILENABLE, true);
... // do stencil work
Device->SetRenderState(D3DRS_STENCILENABLE, false);

使用IDirect3DDevice9::Clear方法来清除模板缓存并让其拥有默认值。

Device->Clear(0, 0,
    D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER | D3DCLEAR_STENCIL,
    0xff000000, 1.0f, 0 );

此时模板缓存中的模板值(Value)已被初始化为0

 

3. 模板缓存是用来阻止像素被写入后台缓存中的,如果像素不能被写入后台缓存,那么它也不能被写入深度缓存。

阻止像素被写入是通过模板测试来决定的,表达式为:

(ref & mask) ComparisonOperation (value & mask)

模版测试是对每个像素进行的,假设模版是被允许。将有两个操作:

  • 左手边操作数(LHS=ref&mask
  • 右手边操作数(RHS=value&mask

模版测试比较LHS和RHS,通过比较运算来指定。全部的运算都得到一个布尔值(true/false)。假如测试的结果是true,那么我们把像素写入后缓存。假如测试的结果是false,我们就阻止像素被写入后缓存。
设置渲染状态:

Device->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_ALWAYS);
    Device->SetRenderState(D3DRS_STENCILREF, 0x1);
    Device->SetRenderState(D3DRS_STENCILMASK, 0xffffffff);
    Device->SetRenderState(D3DRS_STENCILWRITEMASK,0xffffffff);
    Device->SetRenderState(D3DRS_STENCILZFAIL,D3DSTENCILOP_KEEP);
    Device->SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_KEEP);
Device->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE);

设置模版比较运算为D3DCMP_ALWAYS,这就是说让所有模版测试都通过。

假如深度测试失败了,我们指定D3DSTENCILOP_KEEP,它表明不更新模版缓存入口,保存当前值。这样做的原因是假如深度测试失败了,那么就意味着像素被“模糊”了。我们不想渲染被“模糊”的反射像素。

同样假如模版测试失败了,我们也指定D3DSTENCILOP_KEEP。但是在这里这样做不是必须的,因为我们指定的是D3DCMP_ALWAYS,当然这样的测试也就永远不会失败。

假如深度测试和模版测试都通过了,我们就指定D3DSTENCILOP_REPLACE,更新模版缓存入口,设置模版参考值为0x1。

 

4. 更新模板缓存,因为测试总是通过,所以被渲染的部分替换为0x1,其他部分为0

更新模板缓存前,先阻止向深度缓存写入

 // 禁用向模板 深度(Z)缓冲区进行写   
 Device->SetRenderState(D3DRS_ZWRITEENABLE, false);   
 Device->SetRenderState(D3DRS_ALPHABLENDENABLE, true);   

将源融合因子和目标融合因子分别指定为D3DBLEND_ZERO和D3DBLEND_ONE防止对后台缓存进行更新,

    //设置 源融合因子和 目标融合因子   
    Device->SetRenderState(D3DRS_SRCBLEND,  D3DBLEND_ZERO);   
    Device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);   

将镜子写入模板缓存

Device->SetStreamSource(0, VB, 0, sizeof(Vertex));
    Device->SetFVF(Vertex::FVF);
    Device->SetMaterial(&MirrorMtrl);
    Device->SetTexture(0, MirrorTex);
    D3DXMATRIX I;
    D3DXMatrixIdentity(&I);
    Device->SetTransform(D3DTS_WORLD, &I);
    Device->DrawPrimitive(D3DPT_TRIANGLELIST, 18, 2);

在模版缓存中,符合镜子可视像素的为0x1,其他像素为0

至此,模板缓存已创建完成。

......

 

 

 

 

 

posted @ 2014-02-01 20:30  felove  阅读(1020)  评论(0编辑  收藏  举报