OpenGL-ES 学习(3)---- StencilTest

本文详细介绍了OpenGL中模板测试的概念,包括模版缓冲区的作用、更新过程、模板测试的步骤以及编程方法。特别强调了模板测试在绘制物体轮廓中的应用,通过控制模板值实现边缘检测。
摘要由CSDN通过智能技术生成

模版测试

模版测试的主要作用是利用模版缓冲区(Stencil Buffer)所保存的模版值决定当前的片段是否丢弃的过程,模版测试发生在深度测试之前。

模板缓冲区是一个逐像素掩码,也就是每个Pixel 都会和模板缓冲区的值比较,决定是否要绘制,模板缓冲区保存的是每个像素是否要被更新的标志位。
StenCilTest 说明
模板缓冲区的使用分为两步:

  • 用逐像素掩码更新缓冲区,可以通过渲染几何形状并且指定模板缓冲区的更新方式的方法完成(比如使用 GL_ALWAYS,就是先渲染,并且指定模版缓冲区的更新方式);
  • 使用这些值控制后续像素的渲染;

模板测试的一般步骤:

  • 启用模版测试,开启模版缓冲区写入 glStencilMask(0xFF);
  • 执行渲染操作,更新模版缓冲区
  • 关闭模版缓冲区写入 glStencilMask(0x00);
  • 执行渲染操作,利用模板缓冲区所保存的模版值确定是否丢弃特定片段

编程方法

  • 启用模板测试 glEnable(GL_STENCIL_TEST),
    清空模板缓冲区 glClear( GL_STENCIL_BUFFER_BIT);

  • 模版缓冲区的更新Mask(注意和参数的操作是按位与)
    用于控制当前模版缓冲区是否可写

// 模板值与其按位与的运算结果是模板值,模板缓冲区可写
glStencilMask(0xFF); 

// 模板值与其按位与的运算结果是0,模板缓冲区不可写
glStencilMask(0x00); 
  • 模板缓冲区的配置函数 glStencilFunc 和 glStencilOp
void glStencilFunc(GLenum func, GLint ref, GLuint mask);

// 参数说明:
// func: 设置模板测试操作,这个操作应用到已经存储模板值和 glStencilFunc 的 ref 值上,可用的选项包括:

#define GL_LESS                           0x0201
#edfine GL_EQUAL                          0x0202
#define GL_LEQUAL                         0x0203
#define GL_GREATER                        0x0204
#define GL_NOTEQUAL                       0x0205
#define GL_GEQUAL                         0x0206
#define GL_ALWAYS                         0x0207
#define GL_KEEP                           0x1E00

ref: 指定模板测试的引用值,模板缓冲区的模板值会和这个值进行对比
mask:指定一个遮罩,在模板测试对比引用值和存储的模板值前,对它们进行按位与的操作,初始值设置为 1
  • glStencilOp 主要用于控制更新模板缓冲区的方式。
void glStencilOp(GLenum sfail, GLenum dpfail, GLenum dppass);

参数说明: s:stencil dp: depth

sfail:如果模板测试失败将如何更新模板值;

dpfail:如果模板测试通过,但是深度测试失败时将如何更新模板值;

dppass:如果深度测试和模板测试都通过,将如何更新模板值

参数的可选操作:

操作描述
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按位反转当前模板缓冲区的值

编程实例

绘制物体轮廓是模板测试的常见应用,其步骤一般如下:

  • 启动深度测试和模版测试,清空模板缓冲区和深度缓冲区
  • 绘制物体前,用 第一次绘制 更新物体将要被渲染片段对应的模板值
  • 渲染物体,写入模版缓冲区
  • 关闭模板写入和深度测试
  • 将物体放大一定比例
  • 使用一个不同的片段着色器用来输出一个纯颜色(物体轮廓颜色)
  • 再次绘制物体,当片段的模板值不为 1 时,片段通过测试进行渲染;
  • 开启模板写入和深度测试

实际原理就是用实际物体的大小作为模版缓冲区,略微放大一下物体,此时比原物体大的部分作为后面的轮廓,再使用模版测试,将模版值不为 1 的地方进行渲染,就可以得到物体的轮廓。

实际代码如下:

//启动深度测试和模板测试,清空模板和深度缓冲
glClear(GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glEnable(GL_STENCIL_TEST);

glStencilFunc(GL_ALWAYS, 1, 0xFF); //所有片段都要写入模板缓冲
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);//若模板测试和深度测试都通过了,将片段对应的模板值替换为1
// 开启模版缓冲区写入
glStencilMask(0xFF);

//绘制物体
glBindVertexArray(m_VaoId);
glUseProgram(m_ProgramObj);
glUniform3f(m_ViewPosLoc, 0.0f, 0.0f, 3.0f);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_TextureId);
glUniform1i(m_SamplerLoc, 0);
UpdateMatrix(m_MVPMatrix, m_ModelMatrix, m_AngleX, m_AngleY , 1.0, glm::vec3(0.0f,  0.0f,  0.0f), ratio);
glUniformMatrix4fv(m_MVPMatLoc, 1, GL_FALSE, &m_MVPMatrix[0][0]);
glUniformMatrix4fv(m_ModelMatrixLoc, 1, GL_FALSE, &m_ModelMatrix[0][0]);
glDrawArrays(GL_TRIANGLES, 0, 36);
glBindVertexArray(0);

glStencilFunc(GL_NOTEQUAL, 1, 0xFF);//当片段的模板值不为 1 时,片段通过测试进行渲染

//禁用模板写入和深度测试
glStencilMask(0x00);
glDisable(GL_DEPTH_TEST);

//绘制物体轮廓
glBindVertexArray(m_VaoId);
glUseProgram(m_OutlineProgramObj);
//放大 1.05 倍
UpdateMatrix(m_MVPMatrix, m_ModelMatrix, m_AngleX, m_AngleY, 1.05, glm::vec3(0.0f,  0.0f,  0.0f), ratio);
glUniformMatrix4fv(m_MVPMatLoc, 1, GL_FALSE, &m_MVPMatrix[0][0]);
glUniformMatrix4fv(m_ModelMatrixLoc, 1, GL_FALSE, &m_ModelMatrix[0][0]);
glDrawArrays(GL_TRIANGLES, 0, 36);
glBindVertexArray(0);

//开启模板写入和深度测试
glStencilMask(0xFF);
glEnable(GL_DEPTH_TEST);
glDisable(GL_STENCIL_TEST);
  • 25
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值