实践项目:https://github.com/JackieLong/OpenGL/tree/main/project_stencil_test
发生在逐片段操作阶段中的剪切测试之后(Scissor Test)。
点击查看【processon】
工作原理
有一个和颜色缓冲(Color Buffer)一样的模板缓冲(Stencil Buffer),每个模板值一般都是8bit,表示每个片段/像素都有个模板值,我们可以写入模板值,当某个片段有某个模板值时,可以决定是否要保留还是丢弃该片段。
开启模板测试
glEnable(GL_STENCIL_TEST); // 开启深度测试,根据库的不同,可能默认不开启。
// glStencilMask(bitMask),将要写入的模板值与bitMask(位掩码)进行and运算。
glStencilMask(0xFF); // 开启写入:每个bit都原样输出到模板缓冲,默认值。
glStencilMask(0x00); // 禁用写入:每个bit写入到模板缓冲时,都为0。
while(!glfwWindowShouldClose(window))
{
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
// 每次渲染迭代之前别忘了清除
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_TEST);
......
}
模板函数
有两个相关函数:
- glStencilFunc
- 描述了OpenGL对模板缓冲做什么操作。
- 描述了OpenGL对模板缓冲做什么操作。
- glStencilOp
- 描述了如何更新模板缓冲。 ```cpp
glStencilFunc(GLenum func, GLint ref, GLuint mask); // 描述了OpenGL对模板缓冲做什么操作。 //func: 模板测试函数,设stencilFrag:片段模板值,stencilBuffer:缓冲区对应片段模板值 // GL_ALWAYS 永远通过模板测试,后绘制的一律覆盖之前绘制的。 // GL_NEVER 永远不通过模板测试,一律保留最先绘制的。 // GL_LESS stencilFrag < stencilBuffer,通过测试,即丢弃 >= stencilBuffer的片段,默认值 // GL_EQUAL stencilFrag == stencilBuffer,通过测试 // GL_LEQUAL stencilFrag <= stencilBuffer,通过测试 // GL_GREATER stencilFrag > stencilBuffer,通过测试 // GL_NOTEQUAL stencilFrag != stencilBuffer,通过测试 // GL_GEQUAL stencilFrag >= stencilBuffer,通过测试 //ref: 模板测试参考值,模板缓冲内容与这个值进行比较。 //mask: 位掩码,compare(mask & ref, mask & stencilFrag),默认都为1,一般是0xFF,8bit。
glStencilFunc(GL_EQUAL, 1, 0xFF); // 如果stencilFrag==1,则通过模板测试并被绘制,否则会被丢弃。
```cpp
glStencilOp(GLenum sfail, GLenum dpfail, GLenum dppass); // 描述了如何更新模板缓冲。
// sfail: 模板测试失败时采取的行为。
// dpfail: 模板测试通过,但深度测试失败时采取的行为。
// 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: 按位翻转当前的模板缓冲值
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); // 默认情况,不会更新模板缓冲。