模板测试

模板测试概要


言归正传,stencil与颜色缓冲区和深度缓冲区类似,模板缓冲区可以为屏幕上的每个像素点保存一个无符号整数值(通常的话是个8位整数)。这个值的具体意义视程序的具体应用而定。在渲染的过程中,可以用这个值与一个预先设定的参考值相比较,根据比较的结果来决定是否更新相应的像素点的颜色值。这个比较的过程被称为模板测试。模板测试发生在透明度测试(alpha test)之后,深度测试(depth test)之前。如果模板测试通过,则相应的像素点更新,否则不更新。图形渲染管线中,基于单个像素的测试操作的顺序如下图





模板测试语法


一般来说,stencil完整语法格式如下:

  1. stencil{  
  2.     Ref referenceValue  
  3.     ReadMask  readMask  
  4.     WriteMask writeMask  
  5.     Comp comparisonFunction  
  6.     Pass stencilOperation  
  7.     Fail stencilOperation  
  8.     ZFail stencilOperation  
  9. }  
stencil{
	Ref referenceValue
	ReadMask  readMask
	WriteMask writeMask
	Comp comparisonFunction
	Pass stencilOperation
	Fail stencilOperation
	ZFail stencilOperation
}


Ref

  1. Ref referenceValue  
Ref referenceValue

Ref用来设定参考值referenceValue,这个值将用来与模板缓冲中的值进行比较。referenceValue是一个取值范围位0-255的整数。


ReadMask

  1. ReadMask  readMask  
ReadMask  readMask

ReadMask 从字面意思的理解就是读遮罩,readMask将和referenceValue以及stencilBufferValue进行按位与(&)操作,readMask取值范围也是0-255的整数,默认值为255,二进制位11111111,即读取的时候不对referenceValue和stencilBufferValue产生效果,读取的还是原始值。


WriteMask

  1. WriteMask writeMask  
WriteMask writeMask

WriteMask是当写入模板缓冲时进行掩码操作(按位与【&】),writeMask取值范围是0-255的整数,默认值也是255,即当修改stencilBufferValue值时,写入的仍然是原始值。


Comp

  1. Comp comparisonFunction  
Comp comparisonFunction

Comp是定义参考值(referenceValue)与缓冲值(stencilBufferValue)比较的操作函数,默认值:always 


Pass

  1. Pass stencilOperation  
Pass stencilOperation

Pass是定义当模板测试(和深度测试)通过时,则根据(stencilOperation值)对模板缓冲值(stencilBufferValue)进行处理,默认值:keep


Fail

  1. Fail stencilOperation  
Fail stencilOperation


Fail是定义当模板测试(和深度测试)失败时,则根据(stencilOperation值)对模板缓冲值(stencilBufferValue)进行处理,默认值:keep


ZFail

ZFail是定义当模板测试通过而深度测试失败时,则根据(stencilOperation值)对模板缓冲值(stencilBufferValue)进行处理,默认值:keep


Comp,Pass,Fail 和ZFail将会应用给背面消隐的几何体(只渲染前面的几何体),除非Cull Front被指定,在这种情况下就是正面消隐的几何体(只渲染背面的几何体)。你也可以精确的指定双面的模板状态通过定义CompFront,PassFront,FailFront,ZFailFront(当模型为front-facing geometry使用)和ComBack,PassBack,FailBack,ZFailBack(当模型为back-facing geometry使用)



模板测试判断依据


和深度测试一样,在unity中,每个像素的模板测试也有它自己一套独立的依据,具体公式如下:


if(referenceValue&readMask comparisonFunction stencilBufferValue&readMask

通过像素

else

抛弃像素


在这个公式中,主要分comparisonFunction的左边部分和右边部分


referenceValue是有Ref来定义的,这个是由程序员来定义的,readMask是模板值读取掩码,它和referenceValue进行按位与(&)操作作为公式左边的结果,默认值为255,即按位与(&)的结果就是referenceValue本身。


stencilBufferValue是对应位置当前模板缓冲区的值,同样与readMask做按位掩码与操作,结果做为右边的部分。


comparisonFunction比较操作通过Comp命令定义,公式左右两边的结果将通过它进行判断,其取值及其意义如下面列表所示。


   
Greater

相当于“>”操作,即仅当左边>右边,模板测试通过,渲染像素

GEqual

相当于“>=”操作,即仅左边>=右边,模板测试通过,渲染像素

Less

相当于“<”操作,即仅当左边<右边,模板测试通过,渲染像素

LEqual

相当于“<=”操作,即仅当左边<=右边,模板测试通过,渲染像素

Equal

相当于“=”操作,即仅当左边=右边,模板测试通过,渲染像素

NotEqual

相当于“!=”操作,即仅当左边!=右边,模板测试通过,渲染像素

Always 不管公式两边为何值,模板测试总是通过,渲染像素

Never 不敢公式两边为何值,模板测试总是失败 ,像素被抛弃


模板缓冲值的更新


在上一步的模板测试之后,无论模板测试通过与否,都要对模板进行相应的更新。具体到怎么更新,则由程序员自己定义。上面关于模板缓冲语法中,Pass,Fail,ZFail等命令就是根据不同判断条件对模板缓冲区的值(stencilBufferValue)进行更新的操作,这些命令取值(stencilOperation)的类型及意义如下面列表所示:


   
Keep
保留当前缓冲中的内容,即stencilBufferValue不变。
Zero
将0写入缓冲,stencilBufferValue值变为0。
Replace 将参考值写入缓冲,即将referenceValue赋值给stencilBufferValue。

IncrSat
stencilBufferValue加1,如果stencilBufferValue超过255了,那么保留为255,即不大于255。
DecrSat
stencilBufferValue减1,如果stencilBufferValue超过为0,那么保留为0,即不小于0。
Invert
将当前模板缓冲值(stencilBufferValue)按位取反
IncrWrap
当前缓冲的值加1,如果缓冲值超过255了,那么变成0,(然后继续自增)。
DecrWrap
当前缓冲的值减1,如果缓冲值已经为0,那么变成255,(然后继续自减)  


在更新模板缓冲值的时候,也有writeMask进行掩码操作,用来对特定的位进行写入和屏蔽,默认值为255(11111111),即所有位数全部写入,不进行屏蔽操作。


举个如下的例子:

  1. stencil{  
  2.     Ref 2  
  3.     Comp always  
  4.     Pass replace  
  5. }  
stencil{
	Ref 2
	Comp always
	Pass replace
}


在上面的代码中,第一行Ref 2这行将referenceValue定义为2;

第二行中,Comp命令后的参数是always,此时我们不管stencilBufferValue为多少,模板测试都是成功通过的;

而第三行中,Pass replace的意思是,当模板测试通过则将referenceValue替换给stencilBufferValue,此时

stencilBufferValue值为2,因此上面的例子功能相当于将stencilBufferValue刷新为2;


小结

上面说了这么多,主要的重点如下

  • 使用模板缓冲区最重要的两个值:当前模板缓冲值(stencilBufferValue)和模板参考值(referenceValue
  • 模板测试主要就是对这个两个值使用特定的比较操作:Never,Always,Less ,LEqual,Greater,Equal等等。
  • 模板测试之后要对模板缓冲区的值(stencilBufferValue)进行更新操作,更新操作包括:Keep,Zero,Replace,IncrSat,DecrSat,Invert等等。
  • 模板测试之后可以根据结果对模板缓冲区做不同的更新操作,比如模板测试成功操作Pass,模板测试失败操作Fail,深度测试失败操作ZFail,还有正对正面和背面精确更新操作PassBack,PassFront,FailBack等等。




模板测试是所有OpenGL测试中比较复杂的一种。

首先,模板测试需要一个模板缓冲区,这个缓冲区是在初始化OpenGL时指定的。如果使用GLUT工具包,可以在调用glutInitDisplayMode函数时在参数中加上GLUT_STENCIL,例如:

glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_STENCIL);


在Windows操作系统中,即使没有明确要求使用模板缓冲区,有时候也会分配模板缓冲区。但为了保证程序的通用性,最好还是明确指定使用模板缓冲区。如果确实没有分配模板缓冲区,则所有进行模板测试的像素全部都会通过测试。

通过glEnable/glDisable可以启用或禁用模板测试。



OpenGL在模板缓冲区中为每个像素保存了一个“模板值”,当像素需要进行模板测试时,将设定的模板参考值与该像素的“模板值”进行比较,符合条件的通过测试,不符合条件的则被丢弃,不进行绘制。
条件的设置与Alpha测试中的条件设置相似。但注意Alpha测试中是用浮点数来进行比较,而模板测试则是用整数来进行比较。比较也有八种情况:始终通过、始终不通过、大于则通过、小于则通过、大于等于则通过、小于等于则通过、等于则通过、不等于则通过。

glStencilFunc(GL_LESS, 3, mask);


这段代码设置模板测试的条件为:“小于3则通过”。glStencilFunc的前两个参数意义与glAlphaFunc的两个参数类似,第三个参数的意义为:如果进行比较,则只比较mask中二进制为1的位。例如,某个像素模板值为5(二进制101),而mask的二进制值为00000011,因为只比较最后两位,5的最后两位为01,其实是小于3的,因此会通过测试。

如何设置像素的“模板值”呢?glClear函数可以将所有像素的模板值复位。代码如下:

glClear(GL_STENCIL_BUFFER_BIT);


可以同时复位颜色值和模板值:

glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);


正如可以使用glClearColor函数来指定清空屏幕后的颜色那样,也可以使用glClearStencil函数来指定复位后的“模板值”。

每个像素的“模板值”会根据模板测试的结果和深度测试的结果而进行改变。

glStencilOp(fail, zfail, zpass);


该函数指定了三种情况下“模板值”该如何变化。第一个参数表示模板测试未通过时该如何变化;第二个参数表示模板测试通过,但深度测试未通过时该如何变化;第三个参数表示模板测试和深度测试均通过时该如何变化。如果没有起用模板测试,则认为模板测试总是通过;如果没有启用深度测试,则认为深度测试总是通过)
变化可以是:
GL_KEEP(不改变,这也是默认值),
GL_ZERO(回零),
GL_REPLACE(使用测试条件中的设定值来代替当前模板值),
GL_INCR(增加1,但如果已经是最大值,则保持不变),
GL_INCR_WRAP(增加1,但如果已经是最大值,则从零重新开始),
GL_DECR(减少1,但如果已经是零,则保持不变),
GL_DECR_WRAP(减少1,但如果已经是零,则重新设置为最大值),
GL_INVERT(按位取反)。


从前面所讲可以知道,使用剪裁测试可以把绘制区域限制在一个矩形的区域内。但如果需要把绘制区域限制在一个不规则的区域内,则需要使用模板测试。
例如:绘制一个湖泊,以及周围的树木,然后绘制树木在湖泊中的倒影。为了保证倒影被正确的限制在湖泊表面,可以使用模板测试。具体的步骤如下:
(1) 关闭模板测试,绘制地面和树木。
(2) 开启模板测试,使用glClear设置所有像素的模板值为0。
(3) 设置glStencilFunc(GL_ALWAYS, 1, 1); glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);绘制湖泊水面。这样一来,湖泊水面的像素的“模板值”为1,而其它地方像素的“模板值”为0。
(4) 设置glStencilFunc(GL_EQUAL, 1, 1); glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);绘制倒影。这样一来,只有“模板值”为1的像素才会被绘制,因此只有“水面”的像素才有可能被倒影的像素替换,而其它像素则保持不变。


补充:

(ref & mask) ComparisonOperation (value & mask)

左操作数:(ref & mask),改值由 程序定义的模板值参考值(ref) 与 模板掩码值(mask) 通过按 位与 运算得到。

右操作书:(value & mask),改值由 当前进行 测试的像素的模板缓冲中的数值(value) 与  模板掩码值(mask) 通过按 位与 运算得到。


参考:

http://blog.csdn.net/pizi0475/article/details/6121343

http://blog.csdn.net/u011047171/article/details/46928463




  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值