作者:Nin+.Lee
(红色部分为自己修改)
与颜色缓冲区和深度缓冲区类似,模板缓冲区可以为屏幕上的每个像素点保存一个无符号整数值。这个值的具体意义视程序的具体应用而定。在渲染的过程中,可以用这个值与一个预先设定的参考值相比较,根据比较的结果来决定是否更新相应的像素点的颜色值。这个比较的过程被称为模板测试。模板测试发生在透明度测试(alpha test)之后,深度测试(depth test)之前。如果模板测试通过,则相应的像素点更新,否则不更新。图形渲染管线中,基于单个像素的测试操作的顺序如下图。
在模板测试的过程中,可以先使用一个比较用掩码(comparison mask)与模板缓冲区中的值进行位与运算,再与参考值进行比较,从而实现对模板缓冲区中的值的某一位上的置位状态的判断。这样,模板缓冲区中的值不仅可以作为一个独立的整体使用,还可以作为一个比特集合使用。
在OpenGL中,可以通过调用glStencilFunc()函数来设定,比较条件(comparison function)、参考值(reference value)以及比较用掩码(comparison mask)。例如,
glStencilFunc(GL_EQUAL, // 比较条件
0x1, // 参考值
0xff); // 比较用掩码
比较条件的种类如下:
方法 |
参考值与模板值之间的比较结果 |
GL_NEVER |
总是失败 |
GL_ALWAYS |
总是通过测试 |
GL_LESS |
当参考值小于模板值时,通过测试 |
GL_LEQUAL |
当参考值小于等于模板值时,通过测试 |
GL_EQUAL |
当参考值等于模板值时,通过测试 |
GL_GEQUAL |
当参考值大于等于模板值时,通过测试 |
GL_GREATER |
当参考值大于模板值时,通过测试 |
GL_NOTEQUAL |
当参考值不等于模板值时,通过测试 |
具体情况是:
GL_NEVER Always fails.
GL_LESS Passes if ( ref & mask ) < ( stencil & mask).
GL_LEQUAL Passes if ( ref & mask ) <= ( stencil & mask).
GL_GREATER Passes if ( ref & mask ) > ( stencil & mask).
GL_GEQUAL Passes if ( ref & mask ) >= ( stencil & mask).
GL_EQUAL Passes if ( ref & mask ) = ( stencil & mask).
GL_NOTEQUAL Passes if ( ref & mask ) != ( stencil & mask).
GL_ALWAYS Always passes.
除了比较参考值与模板值之外,我们还需要使用一些操作来更新模板缓冲区中的值,这些操作被称为模板操作(stencil operation)。模板缓冲区的更新与模板测试的结果以及深度测试的结果有着密切的联系。模板操作可以为下述三种情况,分别指定相应的更新方法。
1. 模板测试失败。
2. 模板测试通过,但深度测试失败。
3. 模板测试通过,且深度测试通过。
当上述情况中的一个发生时,就会执行预先设定的更新操作。在OpenGL中,可以使用glStencilOp()函数来为上述三种情况分别设置更新方法。例如,
glStencilOp(GL_KEEP, // 第一种情况更新方法
GL_DECR, // 第二种情况的更新方法
GL_INCR); // 第三种情况的更新方法
可是设置的更新方法如下:
更新方法 |
描述 |
GL_KEEP |
保持当前的模板值不变 |
GL_ZERO |
将当前的模板值设为0 |
GL_REPLAC |
用glStencilFunc函数所指定的参考值替换蒙板参数值 |
GL_INCR |
在当前的模板值上加1 |
GL_DECR |
在当前的模板值上减1 |
GL_INVERT |
对当前的模板值进行按位取反操作 |
我们可以通过写入掩码(write mask)来更新模板值指定比特位上的置位状态。OpenGL中,提供了glStencilMask()函数来设置写入掩码。例如,
glStencilMask(0xff);
默认情况下,模板测试功能是禁用的。在OpenGL中可以通过
glEnable(GL_STENCIL_TEST);
glDisable(GL_STENCIL_TEST);
来启用和禁用模板测试。
通常,在渲染开始之前,需要对模板缓冲区执行清理操作,将模板缓冲区的值初始化为某个指定的值。在OpenGL中,可以通过
glClearStencil()函数来设置这个指定的初始值。例如,
glClearStencil(0); // 初始为0
然后,用
glClear(GL_STENCIL_BUFFER_BIT);
执行实际的清理操作。注意,在使用OpenGL清理模板缓冲区的时候,OpenGL会清理的过程中应用写入掩码。如果你想保留模板值某些位上的置位状态,这个功能显然是非常有用的。但是,如果你希望将所有的模板值都初始化为某个指定的初始值时,这同样也可能会造成一些迷惑。
为了功能的完整性,OpenGL还提供了读写、复制模板值的操作。把glReadPixels()、glDrawPixels()、glCopyPixels()的格式参数设置为GL_STENCIL之后,就可以对模板缓冲区进行读写、复制操作了。
参考文献
1. David Blythe, The Stencil Buffer,
http://www.opengl.org/resources/code/samples/sig99/advanced99/notes/node117.html
2. Mark J. Kilgard, Improving Shadows and Reflections via the Stencil Buffer