0x1 总体介绍
下图是Stencil Test在在post fragment pipeline中的位置。
Stencil Test的作用可以把绘制限定在特定的区域,这点和scissor test类似,但是stencil test支持不规则的区域,而scissor test做不到这一点。
Stencil Test是通过stencil buffer中记录的模板信息来完成的,stencil buffer中保存着每个位置的fragment对应的mask值,当graphics pipeline执行stencil test的时候,把通过api设定的模板参考值与相应位置的fragment对应的mask值进行比较,如果不符合条件则被丢弃,反之则进行绘制。
Stencil Test的使用可以看成两步操作,第一步是生成stencil buffer,通过渲染几何体并指定stencil buffer的更新方式来实现。第二步是使用stencil buffer中的内容来控制最终颜色缓存区的渲染。
0x2 从GPU硬件的角度理解Stencil test
下面介绍Stencil test是如何在gpu hardware pipeline中执行的。
下图是broadcom v3d system block图。
v3d是tile buffer rendering的gpu,其渲染分成两个阶段,第一阶段是计算出每个tile中有哪些triangle需要绘制,第二阶段是遍历所有的tile,对每个tile执行真正的绘制工作。
如下图所示,stencil buffer是gpu hardware中tile buffer的一部分,这是gpu硬件中单独的一块buffer,用来保存当前渲染过程中使用到的stencil值。
在每个tile的绘制过程中,都需要根据tile坐标取得stencil buffer中对应的stencil mask, 然后执行stencil test, 执行完了以后,如果必要,还需要更新stencil buffer中对应的stencil值。
0x3 Stencil test测试程序
这个Stencil test测试程序分成两步操作。
第一步只是生成stencil buffer的内容,该过程不输出color,只更新stencil buffer的内容。
更新stencil buffer的策略通过下面的api来控制。
glStencilOp(GL_KEEP, GL_INCR, GL_INCR);
第一个参数是stencil test fail的时候更新stencil buffer的操作,这里的GL_KEEP表明stencil test fail时不对stencil buffer进行更新。
第二个参数表明stencil test pass但depth test fail的时候更新stencil buffer的操作,这里的GL_INCR表明此时对stencil buffer的相应位加1.
第三个参数表明stencil test pass而且depth test pass的时候更新stencil buffer的操作,这里的GL_INCR表明此时对stencil buffer的相应位加1.
以上的设置表明只要stencil test pass的话就对stencil buffer的相应位加1,不管depth test是pass或者fail.
绘制triangle1的代码
绘制triangle2的代码
第二步是根据stencil buffer中的内容为mask来绘制triangle1和triangle2的重叠区域,这个时候发送给opengles的绘制区域可以设置成整个屏幕的大小,但是只有相应的位符合stencil buffer中的条件才能使stencil test通过,这个时候才能输出color。
这个控制相应的位符合stencil buffer中条件的代码如下所示,也就是说stencil buffer相应的位的值需要为0x02,也就是说这个点绘制过两次(triangle1和triangle2都绘制过)。
glStencilFunc(GL_NOTEQUAL, 0, 0xf8 | 0x02);
|
|
0x4 程序运行效果
triangle1单独绘制的效果
triangle2单独绘制的效果
triangle1和triangle2同时绘制的效果
triangle1和triangle2同时绘制但不更新color buffer, 然后根据stencil buffer绘制triangle1和triangle2相交区域的效果