模版测试

2023-09-14  本文已影响0人  不决书

当片段着色器处理完一个片段之后,模板测试(Stencil Test)会开始执行,和深度测试一样,它也可能会丢弃片段。接下来,被保留的片段会进入深度测试,它可能会丢弃更多的片段。模板测试是根据又一个缓冲来进行的,它叫做模板缓冲(Stencil Buffer),我们可以在渲染的时候更新它来获得一些很有意思的效果

模板缓冲操作允许我们在渲染片段时将模板缓冲设定为一个特定的值。通过在渲染时修改模板缓冲的内容,我们写入了模板缓冲。在同一个(或者接下来的)渲染迭代中,我们可以读取这些值,来决定丢弃还是保留某个片段。使用模板缓冲的时候你可以尽情发挥,但大体的步骤如下:

启用GL_STENCIL_TEST来启用模板测试

  glEnable(GL_STENCIL_TEST);

清除模板缓冲

  // 清除 颜色 深度 模版 缓存
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

和深度测试的glDepthMask函数一样,模板缓冲也有一个类似的函数。glStencilMask允许我们设置一个位掩码(Bitmask),它会与将要写入缓冲的模板值进行与(AND)运算。默认情况下设置的位掩码所有位都为1,不影响输出,但如果我们将它设置为0x00,写入缓冲的所有模板值最后都会变成0.这与深度测试中的glDepthMask(GL_FALSE)是等价的。

  glStencilMask(0xFF); // 每一位写入模板缓冲时都保持原样
  glStencilMask(0x00); // 每一位在写入模板缓冲时都会变成0(禁用写入)

模板函数

和深度测试一样,我们对模板缓冲应该通过还是失败,以及它应该如何影响模板缓冲,也是有一定控制的。一共有两个函数能够用来配置模板测试:glStencilFunc和glStencilOp。

glStencilFunc(GLenum func, GLint ref, GLuint mask) 一共包含三个参数:

     glStencilFunc(GL_EQUAL, 1, 0xFF)

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 按位翻转当前的模板缓冲值

默认情况下glStencilOp是设置为(GL_KEEP, GL_KEEP, GL_KEEP)的,所以不论任何测试的结果是如何,模板缓冲都会保留它的值。默认的行为不会更新模板缓冲,所以如果你想写入模板缓冲的话,你需要至少对其中一个选项设置不同的值。

   glEnable(GL_DEPTH_TEST);
   glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);  

   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); 

   glStencilMask(0x00); // 记得保证我们在绘制地板的时候不会更新模板缓冲
   normalShader.use();
   DrawFloor()  

  glStencilFunc(GL_ALWAYS, 1, 0xFF); 
  glStencilMask(0xFF); 
  DrawTwoContainers();

  glStencilFunc(GL_NOTEQUAL, 1, 0xFF);
  glStencilMask(0x00); 
  glDisable(GL_DEPTH_TEST);
  shaderSingleColor.use(); 
  DrawTwoScaledUpContainers();
  glStencilMask(0xFF);
  glEnable(GL_DEPTH_TEST);  
image.png
上一篇 下一篇

猜你喜欢

热点阅读