D3D提供了两个辅助函数
D3DXMatrixReflect()
和
D3DXMatrixShadow()
可以方便的构造投影矩阵和反射矩阵。
然后配合模板缓冲区的掩模处理,就可以制造出各种带有普通阴影和反射的效果了。
另外反射要有一个反射面,可以是一个区域或者 是整个一个平面。
如果我们要创造一个镜子,就要把反射面设置为一个矩形或任意形状的区域。
为了入门 D3D SDK里的 Stencil Mirror 和 Stencil Buffer两个例子是非常好的参考对象。
此外 《Introduction to 3D Game Programmming with DirectX9》里也详细介绍了,
模板缓冲区的这两种重要用途,阴影和模板。
另外注意的是,如今的 Dx9游戏 都大量使用了实时的 体积阴影。利用模板缓冲构造基本的平面阴影是容易的,顶多你再仔细看SDK和相关的鸟文就可以了。 但是 像构造实时的阴影就不那么容易了。 今后会有介绍。
m_pd3dDevice->SetRenderState( D3DRS_STENCILENABLE, TRUE );
m_pd3dDevice->SetRenderState( D3DRS_STENCILFUNC, D3DCMP_ALWAYS );
m_pd3dDevice->SetRenderState( D3DRS_STENCILREF, 0x1 );
m_pd3dDevice->SetRenderState( D3DRS_STENCILMASK, 0xffffffff );
m_pd3dDevice->SetRenderState( D3DRS_STENCILWRITEMASK,0xffffffff );
m_pd3dDevice->SetRenderState( D3DRS_STENCILZFAIL, D3DSTENCILOP_KEEP );
m_pd3dDevice->SetRenderState( D3DRS_STENCILFAIL, D3DSTENCILOP_KEEP );
m_pd3dDevice->SetRenderState( D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE );
固定渲染管线里的这几个渲染状态是经常使用用来控制 掩模的处理的,
它的工作是这样的,为了为特定的物体产生阴影或者反射体,首先要把
物体写入模板缓冲,m_pd3dDevice->SetRenderState( D3DRS_ZWRITEENABLE, TRUE ); 这个渲染状态,
首先关闭 ZBuffer,不允许向ZBuffer写入位了,然后由于ZBuffer和Stencil Buffer
的共同在一块缓存上工作,所以ZBuffer关闭了,Stencil缓冲就工作。
关闭 ZBuffer后,再调用 DrawPrimitive 或者 绘图函数等,就都写入了
模板缓冲中。 这些矩阵包括世界矩阵,视图矩阵,投影矩阵,和其他相关矩阵。 写入矩阵后,在设置模板缓冲时的测试位就是要通过的位
就是说由于先关闭了模板缓冲,在没关闭前我们在 ZBuffer里
已经绘制了一些几何体,然后我们关闭了ZBuffer,并设置让模板通过这些位了
测试,也就是说,最终的结果是,我们要让模板和ZBuffer合并。
或者说,模板缓冲中可能还有其他的位,但是我们只希望把ZBuffer里绘制的位
的那个几何体 求出它的阴影或反射,这个制造的过程中是在模板缓冲中完成的,而不是在ZBuffer中完成的,至于为什么要在Stencil Buffer完成,而不是ZBuffer, 就要知道缓冲的意义,缓冲就是为了加速处理而来,是仿照了工业生产的流水线,把工序进行分化并形成队列,当CPU GPU 处理完计算后,就马上到缓冲区去取数据,这样的例子很多,像内存的存在也是为了让CPU
能更快了存取数据,而不用再和速度较慢的外设来通信了。
图形里的各种 缓冲区也是,CPU为了和外设通信,加了内存在中间,CPU还增加了 1级 2级 3级的 缓存,但是这些都是为了硬件级别的缓存,CPU通过硬件电路或者 微码来控制。 但是 ZBuffer Stencil Buffer这类是开在内存,或者
显存里的缓存。 我们通过 CPU和 GPU的指令可以访问到。
于是,在加快处理的过程中,合理的利用缓存,把一些位绘制在缓存里,并
快速的和正在处理的结果合并,就加速了处理。卡马克一次次的利用缓存来加速了处理。