模板测试

模板测试简介

在几何着色器之后,渲染管线便来到了模板测试,这是一个在深度测试之前的测试。和深度测试一样,模板测试也是根据某个值将像素点剔除,只不过深度测试是通过深度值也就是Z轴值来剔除罢了。

深度测试通过深度缓冲来进行,那么模板测试便是通过模板缓冲。模板缓冲已经通过GLFW库自动创建,所以我们无需再自己创建模板缓冲。每个像素都会有一个八位的模板值,所以我们可以设置一共256种不同的模板值,当某个片段等于(或者大于、小于、不等于等等,这取决于模板测试函数)某个特定值的时候,便保留下该片段然后继续送入深度测试。

模板函数

openGL提供了两个参数可以来操作模板值,分别是glStencilFuncglStencilOp,前者可以规定如何操作模板值,后者则规定测试过后模板值的变化。

  • glStencilFunc:函数原型glStencilFunc(GLenum func, GLint ref, GLuint mask),其中func表示模板测试函数,改函数一共有八个值语义和深度测试函数相同:GL_NEVER(永远不通过)GL_LESS(小于)GL_LEQUAL(小于等于)GL_GREATER(大于)GL_GEQUAL(大于等于)GL_EQUAL(等于)GL_NOTEQUAL(不等于)GL_ALWAYS(一直通过)ref表示要与模板值进行比较的值。mask表示掩码,即模板值会与掩码进行按位与的操作,一般都设置为0xFF即对原模板值无影响。
  • glStencilOp:函数原型glStencilOp(GLenum sfail, GLenum dpfail, GLenum dppass),其中参数分别表示“当模板测试失败时”、“当模板测试通过深度测试失败时”以及当“模板测试和深度测试都通过时”对模板值的操作,这里的操作也有八种:GL_KEEP(保持当前储存的模板值)GL_ZERO(将模板值设置为0)GL_REPLACE(将模板值设置为glStencilFunc函数设置的ref值)GL_INCR(如果模板值小于最大值则将模板值加1)GL_INCR_WRAP(与GL_INCR一样,但是如果模板值超过了最大值则归零)GL_DECR(如果模板值大于最小值则模板值减1)GL_DECR_WRAP(与GL_DECR一样,但如果模板值小于0则将其设置为最大值)GL_INVERT(按位翻转当前的模板缓冲值)

物体轮廓

模板测试一个很有用的应用便是物体轮廓,这在有些游戏中或者是3D编辑器中用处很广,当用户点击某个物体后物体外层会出现一圈高亮的轮廓。
操作思路也很简单,可以先将物体最外面那一层(就是摄像机可以看到的)的模板值全部设定为1,然后此时将模板值锁死,并将模板函数设定成不等于1时通过,然后再在原来物体的位置绘制一个体积稍大的物体,并将其片段着色器设置为某种纯色,原来位置的模板缓存已经设定为1,而且此时模板值锁死不再接受输入,所以也就是说是有物体外面那一圈的模板值不是1,然后再绘制新的物体,这时候新物体会因为中间模板测试不通过而只被绘制出外围一圈,从而也便达到了高亮物体轮廓的目的。当然再绘制完轮廓后还要记得将模板值解锁,这样下一个循环物体才能绘制成功。具体的代码如下所示:

1
2
3
4
5
6
7
8
9
glStencilFunc(GL_NOTEQUAL,1,0xFF);
glDisable(GL_DEPTH_TEST);
glStencilMask(0x00);//锁住模板值

//外围物体绘制...

glEnable(GL_DEPTH_TEST);
glStencilMask(0xFF);//结束后将模板值解锁
glStencilFunc(GL_ALWAYS,1,0xFF);

最后的效果就会是这样: