1、模板缓冲app
与模板缓冲相关的操做有两种——比较操做和更新操做。spa
1. 比较操做对象
Stencil Test 比较的是Reference和Stencil Buffer中的值,公式以下:blog
(Stencil Ref \ &mask ) op (Stencil Buffer \ &mask ) // 左右顺序不可颠倒ip
相应的DX和OpenGL中的命令为:ci
glStencil(cmp_fun, ref, mask) 和 device->SetRenderState(D3DRS_STENCILFUNC, cmp_fun)element
其中的cmp_fun就是上式中的“op”,实际为 “〉”、“〈”、“〉=”、“〈=”等比较运算。所谓的Stencil Test就是进行op运算。op运算的结果是与Stencil Test的状态相对应的(Stencil Test只有pass、fail两种状态),其对应关系以下:get
op的运算结果 Stencil Testit
true passio
false fail
当op被设为always(DX:D3DCMP_ALWAYS | OPENGL:GL_ALWAYS)运算时,不管Stencil Ref和Stencil Buffer的当前值如何,Stencil Test永远为pass。
2. 更新操做
Stencil Test有pass/fail两种结果,Z-Buffer Test也有pass/fail两种结果。Stencil Buffer中的值的更新,须要同时指明是在何种状态(其实是由Stencil Test和Z-Buffer Test运算结果两两组合而成的一共四种状态)下进行的何种更新。更新操做命令格式以下:
DX: device->SetRenderState(state, op)
OpenGL: glstencilOp(op1, op2, op3)
OpenGL DX(state值)
Stencil Test pass 参数op3 D3DRS_STENCILPASS
Stencil Test fail 参数op1 D3DRS_STENCILFAIL
Z Buffer Test fail 参数op2 D3DRS_STENCILZFAIL
OpenGL(op1/op2/op3的值) DX(op的值)
GL_KEEP D3DSTENCILOP_KEEP
GL_ZERO D3DSTENCILOP_ZERO
GL_REPLACE D3DSTENCILOP_REPLACE //用reference值替换模板缓冲中相应位置的值
GL_INCR D3DSTENCILOP_INCRSAT
GL_DECR D3DSTENCILOP_DECRSAT
GL_INCR_WRAP D3DSTENCILOP_INCR
GL_DECR_WRAP D3DSTENCILOP_DECR
要注意加以区分的两个概念——“stencil test经过后对颜色缓冲值的更新”和“stencil test经过后对模板缓冲值的更新”。
3. Stencil Reference
Stencil Reference主要有两个做用:
一是,在比较操做中用做进行比较的一个值;二是,在更新操做中用来替换模板缓冲中的相应数据(GL_REPLACE/D3DSTENCILOP_REPLACE)。
4. Z-Buffer Test 与 Stencil Test 的前后顺序
在OpenGL中Depth Test(Z-Buffer Test)是在Stencil Test以后,参见。
而在DirectX中Z-Buffer Test 是在Stencil Test以前,参见。 // 这里是DX9的资料,DX11后渲染管线有较大变化,不知道这一顺序是否有变。
2、阴影体(Shadow Volume)
经过阴影体来描绘物体投影的技术,在不少地方都有相关的介绍,但多不够直观。将阴影体(Shadow Volume)与Stencil Test结合来造成物体阴影的技术是其中最多见的一种方式,现结合下图做简单介绍。
假设,有一个对象OB在光源L做用下,在平面P上造成自身的阴影W,阴影在屏幕窗口S上对应的区域为W'(如上图)。此时光源L与OB相交的边沿光照方 向的延长线,和OB的背光面一块儿将造成一个棱台VL。Shadow Volume的基本思想是这样的:先生成一个VL的实体并将其投影到S上,但并不真的把它画出来(也就是说,在将VL投影到S上时,并不真正地更新相应的 颜色缓冲),而只是借此操做来设置S上的W'区域所对应的模板缓冲的值,同时使W'所对应的模板缓冲中的值与其它区域所对应的模板缓冲中的值区别开来。这 样就能够在接下来的过程当中,借助模板缓冲将S上的W'区域涂黑,造成最终的阴影。
经过VL的投影过程来造成W'区域与其它区域的Stenclil Buffer值的差异,是基于这样一种思想:假设有一条视线V1与VL正面(面对观察者或摄像机)相交于点b,而后又与VL背面(背对观察者或摄像机)相交于点c,那么说明V1所通过的区域没有其它的物体,因此VL就不会在此处有阴影投射,也就是说V1与S的交点a上的颜色,将由场景中的其它对象来决定;假设有另外一条视线V2与VL正面相交于点e,在与VL背面相交以前先与平面P相交于点f,这就说明点f必处于OB的阴影中,那么V2与S的交点d上的颜色必然要带上阴影色。如下的技术手段是对这一原理的实现。
先将VL的正面(面向观察者或摄像机)在S上做一次投影(不更新颜色缓冲值),同时使S上与其相应的区域(在上图中没有画出)所对应的模板缓冲值加一;而后,再将VL的背面(背向观察者或摄像机)在S上再做一次投影(不更新颜色缓冲值),同时使S上与其相应的区域(在上图中没有画出)所对应的模板缓冲值减一。固然,在此过程当中场景里全部其它对象也要渲染到S上。
在 渲染平面P时,Z-Buffer的Test和Write功能正常开启,在对VL的正、背面进行投影时,Z-Buffer的Test功能开启,而Write 功能关闭。这样就使得在VL正面投影到S上时,不会更新Z-Buffer中的值,而平面P在渲染时会更新Z-Buffer的值。在V2所 通过的路径上,因为平面P处于构成VL背面的诸三角形以前,所以,在Z-Buffer Test阶段,构成VL背面的诸三角形在光栅化阶段将被丢弃,因此,VL背面投影操做所附带的对相应区域的模板缓冲值的减一操做也就自动取消了,最终使得 f点所对应的模板缓冲值,在加一操做(进行VL正面投影时进行)后就一直不变了;而在V1所通过的路径上,因为没有其它的物体的阻隔,对模板缓冲区的加1、减一操做都会按预期进行。这样一来,W'区域与其它区域相应的模板缓冲值就被区别开来了。
(注意,DX与OpenGL虽然在Stencil Test和Z-Buffer Test的前后顺序上有所不一样,但二者对Stencil Buffer值的设置都是在Z-Buffer Test和Stencil Test都完成以后才进行的。)