Stencil的中文翻译是模板或者蒙板,并不是非常容易理解的一个词。在了解stencil test之前,先来了解一下stencil buffer。在OpenGLES中,有三个可以绘制的buffer(缓存),color buffer(颜色缓存), depth buffer(深度缓存)和stencil buffer(模板缓存)。对于color buffer和depth buffer来说,buffer里面存储的一般都是浮点数,然而对于stencil buffer,buffer存储的是无符号整数,确切的说,0或者1。在OpenGLES中,stencil buffer一般最大有8位,这就意味着stencil buffer的最大值就是0xFF。首先要建立起来的观念就是stencil buffer的操作并不是加减乘除等算术运算,而是位操作运算。这对理解stencil test有很大的帮助。
下面这张图是stencil test在graphics pipeline里面的位置,
Stencil test是per-fragment operations的一种,这就意味着它处于fragment shader (片段着色器)之后,stencil test的主要作用就是根据stencil buffer的内容,来丢弃不需要的fragments。
Stencil test需要的三个基本元素就是
OpenGLES提供了三个stencil test相关的函数,
简单讲一下这三个函数,
可以看到stencil test提供了相当多的功能用于比较,下面的章节会详细描述下比较的算法。
在描述算法之前让我们先设定好一些变量,
用伪代码来表示算法,
// stencil test比较的时候需要mask status = stencilfunc.func((stencilbuf[x,y] & stencilfunc.mask), (stencilfunc.ref & stencilfunc.mask)); status |= depth_test_result; if (status == stencil_test_fail) stencilop = sfailop; else if (status == stencil_test_pass & depth_test_fail) stencilop = dpfailop; else if (status == stencil_test_pass & depth_test_pass) stencilop = dppassop; // stencil test结束后的操作不需要mask stencil_new_value = stencilop(stencilbuf[x,y]); // 写入stencil buffer的时候需要另一个mask stencilbuf[x,y] = (stencil_new_value & stencilmask.mask) | (stencilbuf[x,y] & (~stencilmask.mask));
以上就是stencil test的全过程,其实只要能搞清楚不同的mask在stencil test中所起的作用应该就能完全理解这个略显复杂的算法了。
对于应用程序来讲,由于各家厂商的硬件行为可能都不一致,很难写出适配所有硬件的优化好的应用程序。但是对于stencil test来讲,这里有一个小小的技巧可以借鉴。
大家可以留意下stencil test的七个操作,其中有一个操作是GL_KEEP。大家可以想象下硬件里的流水线,
通常替换就意味着一个“写”的操作,从优化的角度来讲,如果新值和旧值是一样的,就可以直接跳过不写了。所以这里就带来了一个可以在应用程序端优化的方向
glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); glStencilFunc(GL_ALWAYS, ref, mask);
glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE); glStencilFunc(GL_NOTEQUAL, ref, mask);
希望这可以给大家带来一些启发,从而写出更好的OpenGL ES程序。