模板测试
模板测试简介
在几何着色器之后,渲染管线便来到了模板测试,这是一个在深度测试之前的测试。和深度测试一样,模板测试也是根据某个值将像素点剔除,只不过深度测试是通过深度值也就是Z轴值来剔除罢了。
深度测试通过深度缓冲来进行,那么模板测试便是通过模板缓冲。模板缓冲已经通过GLFW库自动创建,所以我们无需再自己创建模板缓冲。每个像素都会有一个八位的模板值,所以我们可以设置一共256种不同的模板值,当某个片段等于(或者大于、小于、不等于等等,这取决于模板测试函数)某个特定值的时候,便保留下该片段然后继续送入深度测试。
模板函数
openGL提供了两个参数可以来操作模板值,分别是glStencilFunc
和glStencilOp
,前者可以规定如何操作模板值,后者则规定测试过后模板值的变化。
- 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 | glStencilFunc(GL_NOTEQUAL,1,0xFF); |
最后的效果就会是这样: