游戏开发论坛

 找回密码
 立即注册
搜索
查看: 3762|回复: 7

模板缓冲的原理

[复制链接]

20

主题

84

帖子

84

积分

注册会员

Rank: 2

积分
84
发表于 2009-11-23 17:09:00 | 显示全部楼层 |阅读模式
下面是《DirectX 9.0 3D游戏开发编程基础》Stencil Mirror中的关于Stencil 的代码

void RenderMirror()
{
        //
        // Draw Mirror quad to stencil buffer ONLY.  In this way
        // only the stencil bits that correspond to the mirror will
        // be on.  Therefore, the reflected teapot can only be rendered
        // where the stencil bits are turned on, and thus on the mirror
        // only.
        //

    Device->SetRenderState(D3DRS_STENCILENABLE,    true);
    Device->SetRenderState(D3DRS_STENCILFUNC,      D3DCMP_ALWAYS);
   //为什么要设置成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);

        // disable writes to the depth and back buffers
    Device->SetRenderState(D3DRS_ZWRITEENABLE, false);//
    Device->SetRenderState(D3DRS_ALPHABLENDENABLE, true);
    Device->SetRenderState(D3DRS_SRCBLEND,  D3DBLEND_ZERO);
    Device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);

    // draw the mirror to the stencil buffer
        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);

        // re-enable depth writes
        Device->SetRenderState( D3DRS_ZWRITEENABLE, true );

        // only draw reflected teapot to the pixels where the mirror
        // was drawn to.
        Device->SetRenderState(D3DRS_STENCILFUNC,  D3DCMP_EQUAL);
          Device->SetRenderState(D3DRS_STENCILPASS,  D3DSTENCILOP_KEEP);
         ///////为什么这里STENCILPASS后,却要设成KEEP?这里是什么意思??????


        // position reflection
        D3DXMATRIX W, T, R;
        D3DXPLANE plane(0.0f, 0.0f, 1.0f, 0.0f); // xy plane
        D3DXMatrixReflect(&R, &plane);

        D3DXMatrixTranslation(&T,
                TeapotPosition.x,
                TeapotPosition.y,
                TeapotPosition.z);

        W = T * R;

        // clear depth buffer and blend the reflected teapot with the mirror
        Device->Clear(0, 0, D3DCLEAR_ZBUFFER, 0, 1.0f, 0);
        Device->SetRenderState(D3DRS_SRCBLEND,  D3DBLEND_DESTCOLOR);
    Device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ZERO);

        // Finally, draw the reflected teapot
        Device->SetTransform(D3DTS_WORLD, &W);
        Device->SetMaterial(&TeapotMtrl);
        Device->SetTexture(0, 0);

        Device->SetRenderState(D3DRS_CULLMODE, D3DCULL_CW);
        Teapot->DrawSubset(0);
       
        // Restore render states.
        Device->SetRenderState(D3DRS_ALPHABLENDENABLE, false);
        Device->SetRenderState( D3DRS_STENCILENABLE, false);
        Device->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);
}
谁能够回答下注释部分的问题????还有,对模板缓冲的原理感觉不是很理解,谁能够描述下,或给些比较好的连接?
先谢谢了!

0

主题

2

帖子

0

积分

新手上路

Rank: 1

积分
0
发表于 2009-11-25 01:34:00 | 显示全部楼层

Re:模板缓冲的原理

我来说说我的理解:
首先这个函数要实现一个镜像的效果,一个物体被映射到镜子中,镜子是一个矩形区域, 物体超出镜子的部分不会被绘上去。而模板测试的作用就是把超出镜子的部分去掉。怎么做:

1. 先理解模板缓冲:你可以认为它是一个二维数组,这个二维数组的大小与渲染目标一样,每个元素的值是一个整形。当你调用Device->Clear的时候,可以为模板缓冲的每一个元素设一个值,如:
  Device->Clear(0, 0, D3DCLEAR_STENCIL, 0, 0, 0);
  这样模板缓冲的所有元素就被设为0,当然默认情况下应该都是。

2. 再理解模板测试:当源的一个像素在绘到目标之前,会进行一次模板测试, 测试通过才可以绘到目标去,说白了,就是我提供一个参考值,用这个参考值与模板缓冲中相应的元素值做比较。
    参考值通过D3DRS_STENCILREF设定;比较函数通过D3DRS_STENCILFUNC设定,另外D3DRS_STENCILPASS指定当测试通过时,对模板缓冲的处理。

3. 来看代码:
   Device->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_ALWAYS);
   Device->SetRenderState(D3DRS_STENCILREF,       0x1);
   Device->SetRenderState(D3DRS_STENCILPASS,      D3DSTENCILOP_REPLACE);
   // D3DCMP_ALWAYS指定无论如何都可以测试通过
   // D3DRS_STENCILREF被设为1
   // D3DRS_STENCILPASS表明测试通过以后,将D3DRS_STENCILREF复制到模板缓冲的相应位置。

   Device->SetRenderState(D3DRS_SRCBLEND,  D3DBLEND_ZERO);
   Device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);
   // 这种混合方式使得源以透明的方式绘到目标去,到后面就你会理解这样做的含义

   Device->DrawPrimitive(D3DPT_TRIANGLELIST, 18, 2);
   // 绘制图元,其实就是绘制镜子的区域,那么绘之前是会进行模板测试的,按照前面的代码,测试总是会通过的,并且通过以后,这个区域的模板值被设为1.
   // 按照前面的混合方式,这个图元并不会被绘上去。
   // 到这里已经比较清晰了,上面的代码使得镜子这个区域的模板值为1

   Device->SetRenderState(D3DRS_STENCILFUNC,  D3DCMP_EQUAL);
   Device->SetRenderState(D3DRS_STENCILPASS,  D3DSTENCILOP_KEEP);
   // D3DCMP_EQUAL表示,模板值等于参考值(1)时才能通过,
   // D3DSTENCILOP_KEEP表示,通过以后模板值不变.
   // 到这里应该明白, 只有镜子那个区域的像素才能测试通过, 因为只有那个区域的模板值为1, 与参考值相等.

   Device->SetRenderState(D3DRS_SRCBLEND,  D3DBLEND_DESTCOLOR);
   Device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ZERO);
   // 这个混合方式使得源像素与目标像素的颜色进行调制.

   Teapot->DrawSubset(0);
   // 绘制物体, 按前面的说法, 茶壶映射到镜子的部分可以通过模板测试, 因此可以绘上去, 而在镜子之外的就绘不上去了.


   明白了吗!

3

主题

18

帖子

22

积分

注册会员

Rank: 2

积分
22
发表于 2009-11-25 11:05:00 | 显示全部楼层

Re: 模板缓冲的原理

画镜子之前先设置下模板值
以后在这个镜子上画其他的就可以依据模板值了
但我还是要看着参考代码才能写出来 [em6]
难道就没啥规律吗?

20

主题

84

帖子

84

积分

注册会员

Rank: 2

积分
84
 楼主| 发表于 2009-11-25 13:52:00 | 显示全部楼层

Re:模板缓冲的原理

Device->SetRenderState(D3DRS_STENCILFUNC,      D3DCMP_ALWAYS);
这里的always如果改成EQUAL就没有镜像效果了
为什么呢???
------------------
如果改成EQUAL,测试时是不会成功的,因为模板缓冲中是0,这样是不可能将镜子区域的缓冲置1的,我这样理解对不对??

20

主题

84

帖子

84

积分

注册会员

Rank: 2

积分
84
 楼主| 发表于 2009-11-25 14:02:00 | 显示全部楼层

Re: Re:模板缓冲的原理

linzhenqun: Re:模板缓冲的原理

我来说说我的理解:
首先这个函数要实现一个镜像的效果,一个物体被映射到镜子中,镜子是一个矩形区域, 物...

很感谢你的回答,感觉突然思路清晰了很多,谢谢了!
第一次D3DRS_STENCILFUNC设置成always的原因就是为了让镜子所在位置的模板缓冲都变成1 。
除了设置成always,将模板缓冲对应的像素置1外,还有别的其他方法吗?

0

主题

2

帖子

0

积分

新手上路

Rank: 1

积分
0
发表于 2009-11-25 17:12:00 | 显示全部楼层

Re:模板缓冲的原理

我觉得最好就是参考SDK,只要你理解了模板测试的原理,其他方法想一想应该就出来了。

20

主题

84

帖子

84

积分

注册会员

Rank: 2

积分
84
 楼主| 发表于 2009-11-26 00:13:00 | 显示全部楼层

Re:模板缓冲的原理

sdk有语言障碍呀。。。总是不能很明确它说的意思
D3DRS_STENCILMASK
Mask applied to the reference value and each stencil buffer entry to determine the significant bits for the stencil test. The default mask is 0xFFFFFFFF.

D3DRS_STENCILWRITEMASK
Write mask applied to values written into the stencil buffer. The default mask is 0xFFFFFFFF.

    Device->SetRenderState(D3DRS_STENCILMASK,      0xffffffff);//这个是模板掩码
    Device->SetRenderState(D3DRS_STENCILWRITEMASK, 0xffffffff);//那这个是作什么用的呢??
模板掩码大小是根据什么设置的?

1

主题

2

帖子

0

积分

新手上路

Rank: 1

积分
0
发表于 2009-11-26 23:59:00 | 显示全部楼层

Re:模板缓冲的原理

加一点想象力啊:
(模板参考值 & D3DRS_STENCILMASK) 比较类型 (模板值 & D3DRS_STENCILMASK)
比较类型就是:D3DCMP_ALWAYS这些,也就是通过D3DRS_STENCILFUNC指定的那个类型
这样来看D3DRS_STENCILMASK是不是清楚些了呢,不过就是指定一些位掩码,你一般用默认值(0xffffffff)就好了。

D3DRS_STENCILWRITEMASK也是类似的,比如我有一个值(0x1),要写入模板缓冲,假设D3DRS_STENCILWRITEMASK是0xffff0000, 那么 0x1 & 0xffff0000的结果等于0, 也就是最后写入模板缓冲的值是0.
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

作品发布|文章投稿|广告合作|关于本站|游戏开发论坛 ( 闽ICP备17032699号-3 )

GMT+8, 2025-12-17 00:53

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表