本文正在参加「金石计划」

** 什么是模板测验**

模板测验和深度测验作用相似,模板测验主要是经过比照模板缓冲区来决定是否需要对片段进行丢掉。

在渲染时更新模板缓冲区能够获取很多有趣的作用。

一个模板缓冲区通常运用8位来表明,因此一个像素能够有256中表明办法。

下面是一个简略的模板缓冲区图示(来源):

【安卓OpenGLES】 开发入门(六):模板测试

上面图示中:先运用0来清空模板缓冲区,然后再制作一个新的长方形,此刻咱们将1写入模板缓冲区,制作出来的图形只会显现模板缓冲区为1的像素图形。

模板缓冲区答应咱们运用指定的值去设置缓冲区,经过改动模板缓冲区的值实现一些特殊场景,这个一般步骤如下:

  • 1.先敞开模板测验
  • 2.制作源物体并改动模板缓冲区的值
  • 3.制止模板缓冲区写入。
  • 4.制作其他物体,此刻能够运用对应的战略:如制作的时分,丢掉和源物体重合的部分。

模板测验api

OpenGL相关的模板测验api包含以下几种:

  • 1.发动模板测验:
glEnable(GL_STENCIL_TEST);  

发动模板测验之后,记住清空模板缓冲区。

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
  • 2.敞开/制止模板缓冲区写入
glStencilMask(0xFF); // each bit is written to the stencil buffer as is
glStencilMask(0x00); // each bit ends up as 0 in the stencil buffer (disabling writes)

将模板缓冲区掩码设置为0之后,表明当时模板缓冲区不可写,其他的值表明可写、

  • 3.模板测验战略函数

和深度测验相似,模板测验也有对应的api函数来设置模板测验的战略,如测验失利或者成功的状况下怎么处理模板缓冲区。

模板测验提供了两个函数:glStencilFunc and glStencilOp.

glStencilFunc函数原型:

The glStencilFunc(GLenum func, GLint ref, GLuint mask)

三个参数意义:

  • func:设置模板测验成功与否的战略。包含下面几种状况:

    func战略 描述
    GL_NEVER 每次模板测验都失利
    GL_LESS 比参考值更小就经过测验
    GL_LEQUAL 小余或等于参考值就经过测验
    GL_GREATER 比参考值更大就经过测验
    GL_GEQUAL 大于或等于参考值就经过测验
    GL_EQUAL 缓冲区的值和参数值ref持平
    GL_NOTEQUAL 缓冲区的值和参数值ref不持平
    GL_ALWAYS 每次模板测验都成功
  • ref:参考值,这个值会用来和模板缓冲区中的值进行比较,来判别是否丢掉片段。

  • mask:设置一个掩码,在模板缓冲区和ref参考值进行比较值钱,会运用mask做一个按位与的操作,初始化当时值,一般是在为0xFF即可,保留原值。

glStencilOp函数原型

glStencilOp(GLenum sfail, GLenum dpfail, GLenum dppass)
  • sfail:表明模板测验失利怎么更新缓冲区的值
func战略 描述
GL_KEEP 坚持现有的模板值
GL_ZERO 将模板值置为 0
GL_REPLACE 将模板值设置为用 glStencilFunc 函数设置的ref值
GL_INCR 假如模板值不是最大值就将模板值 +1
GL_INCR_WRAP 与 GL_INCR 相同将模板值 +1 ,假如模板值现已是最大值则设为 0
GL_DECR 假如模板值不是最小值就将模板值 -1
GL_DECR_WRAP 与 GL_DECR 相同将模板值 -1 ,假如模板值现已是最小值则设为最大值
GL_INVERT 按位回转当时模板缓冲区的值
  • dpfail:表明模板测验成功,可是深度测验失利怎么更新模板缓冲区。
  • dppass:表明模板测验和深度测验都成功怎么更新模板缓冲区的值。

下面是对应的一切的战略:

func战略 描述
GL_KEEP 坚持现有的模板值
GL_ZERO 将模板值置为 0
GL_REPLACE 将模板值设置为用 glStencilFunc 函数设置的ref值
GL_INCR 假如模板值不是最大值就将模板值 +1
GL_INCR_WRAP 与 GL_INCR 相同将模板值 +1 ,假如模板值现已是最大值则设为 0
GL_DECR 假如模板值不是最小值就将模板值 -1
GL_DECR_WRAP 与 GL_DECR 相同将模板值 -1 ,假如模板值现已是最小值则设为最大值
GL_INVERT 按位回转当时模板缓冲区的值

如设置:

glStencilOp(GL_KEEP,GL_KEEP,GL_REPLACE);

则表明模板测验失利时,坚持原有模板值,模板测验成功可是深度测验失利时坚持原有模板值,两种都成功,则更新模板值为参考值。

下面咱们运用一个案例来剖析模板测验

物体概括制作

假如你对上面的基础知识都现已把握的差不多了,下面的demo对咱们应该不会太难:

【安卓OpenGLES】 开发入门(六):模板测试

制作物体概括的一般步骤如下:

  • 1.首要敞开模板测验,清空模板缓冲区,敞开模板缓冲区写入
  • 2.在制作源物体之前设置模板测验操作为GL_ALWAYS,设置参考值为1,掩码为0xFF,这样能够在每次制作的时分都能够将模板缓冲区写入1。
  • 3.制作源物体
  • 4.制止模板缓冲区写入并制止深度测验。
  • 5.将源物体放大一点。
  • 6.运用一个纯色彩的片段着色器对源物体进行制作。
  • 7.制作源物体,可是此刻运用GL_NOTEQUAL 的方式进行模板缓冲区制作战略
  • 8.重新敞开深度缓冲区和模板可写入操作。

代码如下:

void MyGLRenderContext::OnDrawFrame() {
   isDrawing = true;
   beforeDraw();
   if(programObj == 0){
     return;
   }
   //清除buffer
   glEnable(GL_DEPTH_TEST);
   glEnable(GL_STENCIL_TEST);
   glStencilOp(GL_KEEP,GL_KEEP,GL_REPLACE);
   glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
   glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
​
​
   glStencilFunc(GL_ALWAYS,1,0xff);
   glStencilMask(0xff);
​
   //运用程序着色器对象
   glUseProgram(programObj);
   //绑定VAO
   glBindVertexArray(VAO);
   //观察者位置setCordder(model);
   //开始制作
   glDrawArrays(GL_TRIANGLES,0,36);
   //解绑VAO
   glBindVertexArray(GL_NONE);
​
   glStencilFunc(GL_NOTEQUAL,1,0xff);
   glStencilMask(0x00);
   glDisable(GL_DEPTH_TEST);
​
   glUseProgram(singleColorShader);
   glBindVertexArray(VAO);
   GLfloat scale = 1.1f;
   if(isFirstDraw){
     modelScale = glm::scale(modelScale, glm::vec3(scale, scale, scale));
     isFirstDraw = false;
   }
   setCordder(modelScale);
​
   glDrawArrays(GL_TRIANGLES,0,36);
​
   glStencilMask(0xFF);
   glStencilFunc(GL_ALWAYS, 0, 0xFF);
   glEnable(GL_DEPTH_TEST);
   glBindVertexArray(GL_NONE);
   //解绑程序着色器对象
   glUseProgram(GL_NONE);
   isDrawing = false;
}

概括的片段着色器代码:

"#version 300 es \n"
"precision mediump float;\n"
"out vec4 outColor;\n"
 "void main()"
 "{ \n"
 "  outColor = vec4(0.23f, 0.35f, 0.2f, 1.0f); \n"
 "} \n";

作用如下:

【安卓OpenGLES】 开发入门(六):模板测试

完整代码现已贴到github上了,大家能够自行下载检查。我是小余,咱们下期见》》》