NDK OpenGL ES 3.0 开发(十一):模板测试-阿里云开发者社区

开发者社区> 视频云小助手> 正文

NDK OpenGL ES 3.0 开发(十一):模板测试

简介: 模板测试与深度测试类似,主要作用是利用模板缓冲区(Stencil Buffer)所保存的模板值决定当前片段是否被丢弃,且发生于深度测试之前。
+关注继续查看

作者:字节流动

来源:https://blog.csdn.net/Kennethdroid/article/details/102533260


OpenGL ES 模板测试

image.png

模板测试与深度测试类似,主要作用是利用模板缓冲区(Stencil Buffer)所保存的模板值决定当前片段是否被丢弃,且发生于深度测试之前。

图片来源:https://learnopengl.com/Advanced-OpenGL/Stencil-testing

模板测试一般步骤:

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

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

控制模板缓冲区是否可以进行写入:

// 0xFF == 0b11111111
// 模板值与它进行按位与运算结果是模板值,模板缓冲可写
glStencilMask(0xFF); 

// 0x00 == 0b00000000 == 0
// 模板值与它进行按位与运算结果是0,模板缓冲不可写
glStencilMask(0x00); 

模板测试的配置函数 glStencilFuncglStencilOp

void glStencilFunc(GLenum func, GLint ref, GLuint mask);
  • func:设置模板测试操作。这个测试操作应用到已经储存的模板值和 glStencilFunc的 ref 值上,可用的选项是:
    GL_NEVER、GL_LEQUAL、GL_GREATER、GL_GEQUAL、GL_EQUAL、GL_NOTEQUAL、GL_ALWAYS ;
  • ref:指定模板测试的引用值。模板缓冲区中的模板值会与这个值对比;
  • mask:指定一个遮罩,在模板测试对比引用值和储存的模板值前,对它们进行按位与(and)操作,初始设置为 1 。
glStencilFunc(GL_EQUAL, 1, 0xFF);
// 表示当一个片段模板值等于(GL_EQUAL)引用值1,片段就能通过测试被绘制了,否则就会被丢弃。

glStencilFunc(GL_ALWAYS, 1, 0xFF);
// 表示所有片段模板测试总是通过。

glStencilOp 主要用于控制更新模板缓冲区的方式。

void 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 一样将模板值 +1 ,如果模板值已经是最大值则设为 0
GL_DECR如果模板值不是最小值就将模板值 -1
GL_DECR_WRAP与 GL_DECR 一样将模板值 -1 ,如果模板值已经是最小值则设为最大值
GL_INVERT按位反转当前模板缓冲区的值

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

  • 启动深度测试和模板测试,清空模板缓冲和深度缓冲;
  • 在绘制物体前,设置 glStencilFunc(GL_ALWAYS, 1, 0xFF);,用 1 更新物体将被渲染的片段对应的模板值;
  • 渲染物体,写入模板缓冲区;
  • 关闭模板写入和深度测试;
  • 将物体放大一定比例;
  • 使用一个不同的片段着色器用来输出一个纯颜色(物体轮廓颜色);
  • 再次绘制物体,设置 glStencilFunc(GL_NOTEQUAL, 1, 0xFF) 当片段的模板值不为 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);

另外需要注意,在使用 GLSurfaceView 时,新的 API 默认没有配置模板缓冲区,需要使用 setEGLConfigChooser 配置模板缓冲区。

public MyGLSurfaceView(Context context, AttributeSet attrs) {
    super(context, attrs);
    this.setEGLContextClientVersion(2);
    mGLRender = new MyGLRender();
    /*If no setEGLConfigChooser method is called,
    then by default the view will choose an RGB_888 surface with a depth buffer depth of at least 16 bits.*/
    setEGLConfigChooser(8, 8, 8, 8, 16, 16);//最后 2 个参数表示分别配置 16 位的深度缓冲区和模板缓冲区
    setRenderer(mGLRender);
    setRenderMode(RENDERMODE_WHEN_DIRTY);

}

利用模板测试绘制物体轮廓效果图

联系与交流

技术交流/获取源码可以添加我的微信:Byte-Flow


视频云技术」你最值得关注的音视频技术公众号,每周推送来自阿里云一线的实践技术文章,在这里与音视频领域一流工程师交流切磋。

阿里云社区.png

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
07.Android Studio下Ndk开发(使用fmod播放声音)
(创建于2017/12/28) 已实现 注意几点: 1.main下cpp文件夹放置c文件和相关头文件 2.main下JniLibs文件夹放置第三方so文件 3.
1092 0
03.Eclipse下Ndk开发(以文件加密为例模拟一下开发过程)
(创建于2017/12/2) 1.编写native方法 package com.example.ndk_file_encrpty; public class Cryptor { static{ System.
887 0
04.Eclipse下Ndk开发(以文件拆分合并为例模拟一下开发过程,参考文件加密的过程)
(创建于2017/12/6) 1.工具类PatchUtils package com.ren.ndk_file_patch; public class PatchUtils { static{ System.
825 0
NDK OpenGL ES 3.0 开发(十二):混合
OpenGL ES 混合本质上是将 2 个片元的颜色进行调和,产生一个新的颜色。OpenGL ES 混合发生在片元通过各项测试之后,准备进入帧缓冲区的片元和原有的片元按照特定比例加权计算出最终片元的颜色值,不再是新(源)片元直接覆盖缓冲区中的(目标)片元。
89 0
10.Eclipse下Ndk开发(ffmpeg native 方式播放视频,万能解码(SurfaceView, 播放音频,)
(创建于2018/1/26) 遇到的问题 遇到一个很棘手的问题,在Eclipse上引入两个头文件报错 #include #include 右键->Porperties->C/C++General->Paths and Symbols中可以看到 987671.
1137 0
NDK OpenGL ES 3.0 开发(十一):模板测试
模板测试与深度测试类似,主要作用是利用模板缓冲区(Stencil Buffer)所保存的模板值决定当前片段是否被丢弃,且发生于深度测试之前。
48 0
Mac下Android Studio 3.x的NDK开发环境搭建
目录 前言 CMake 用CMake向已有AS项目添加C/C++代码 ndk-build 最后 前言 mac上安装软件真的很简单, 一路下一步就可以安装好android studio. 这里有一篇旧文-Mac下安装配置Android Studio 2.
2049 0
10.Eclipse下Ndk开发(ffmpeg解码)
(创建于2018/1/7) ffmpeg库简介: 4113515.png 解码流程图: 4062671.png 解码过程涉及到的函数 4191421.
883 0
OPENGL学习【一】VS2008开发OPENGL程序开发环境搭建
版权声明:本文为博主原创文章,未经博主允许不得转载。更多学习资料请访问我爱科技论坛:www.52tech.tech https://blog.csdn.net/m0_37981569/article/details/79241439 1.VS2008工具自行在网上下载安装,现只提供VS2008开发工具中配置OPENGL环境的详细步骤。
1015 0
228
文章
0
问答
来源圈子
更多
+ 订阅
文章排行榜
最热
最新
相关电子书
更多
《2021云上架构与运维峰会演讲合集》
立即下载
《零基础CSS入门教程》
立即下载
《零基础HTML入门教程》
立即下载