Opengl学习之——模板测试
2017-08-26 18:48
288 查看
模板测试介绍
上一篇介绍了深度测试,实际上深度测试执行是在模板测试之后进行的,只有通过了模板测试之后的片段才会进行深度测试。在片段着色器执行完之后,需要经过一系列的测试,如下过程:在Opengl 3.0 以后Alpha测试已剔除,最后的逻辑操作一般也不使用。模板测试类似于深度测试,也有一个缓冲区,来存储模板值,叫做模板缓冲(Stencil Buffer)。模板缓冲中的模板支通常是8位的,所以每个片段共有256种不同的模板值。可以在模板缓冲中设置我们所需要的模板值,然后在做模板测试时就可以根据这个值决定片段的保留与丢弃。
模板测试实例
举一个模板测试的例子来演示模板测试的作用,如下图。通过模板测试可以选择哪些地方可以显示出来,就像通过窗户看外面的风景一样。该过程一般经过如下步骤:
- 开启模板测试
- 绘制模板,写入模板缓冲
- 关闭模板缓冲
- 渲染其他物体,基于该模板进行模板测试
模板测试中使用的函数
通过GL_STENCIL_TEST来开启模板测试glEnable(GL_STENCIL_TEST);
每次循环中也要清除模板缓冲区:
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
同深度测试一样glDepthMask函数一样,模板缓冲也有一个相似函数。glStencilMask允许我们给模板值设置一个位遮罩(Bitmask),它与模板值进行按位与(AND)运算决定缓冲是否可写入。
//此时,模板缓冲可写 glStencilMask(0xFF); //此时,模板缓冲不可写 glStencilMask(0x00);
模板测试时如何进行比较呢,*glStencilFun*c 函数提供了比较的操作。
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);
这个函数意思是,对遮罩0xFF按位与,然后模板中的值等于引用值1时就通过测试,否则不通过。
上面的函数告诉了怎么进行模板测试,但是如何更新模板缓冲呢?需要glStencilOp来设定。
void glStencilOp(GLenum sfail, GLenum dpfail, GLenum dppass)
sfail: 如果模板测试失败将采取的动作。
dpfail: 如果模板测试通过,但是深度测试失败时采取的动作。
dppass: 如果深度测试和模板测试都通过,将采取的动作。
这里 pass 操作涉及到了深度测试,三种操作的关系如下[流程图]
(http://www.cnblogs.com/mikewolf2002/archive/2012/05/15/2500867.html):
glStencilOp(GL_KEEP,GL_KEEP,GL_KEEP);
该函数表明任何测试,无论失败或通过,均保留现有模板缓冲的值
glStencilOp(GL_KEEP,GL_KEEP,GL_REPLACE);
将第三个参数改为GL_REPLACE后,如果模板测试和深度测试都通过后,将更新模板缓冲的值,即glStencilFunc函数的ref值。
该例子中实现的效果如下,就像从一个窗口中看物体。
主要代码设置如下:
glEnable(GL_DEPTH_TEST); glEnable(GL_STENCIL_TEST); //清除缓冲区 glClearColor(0.16f, 0.05f, 0.15f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); glStencilFunc(GL_ALWAYS, 1, 0xFF); glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); glStencilMask(0xFF); //数据不写入颜色缓冲区,只是使用矩形来作为模板测试 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); //深度缓冲区禁止写入,不影响后面的绘制操作 glDepthMask(GL_FALSE); //绘制矩形模板 ... ---------------------------------------------- glDepthMask(GL_TRUE); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); glStencilFunc(GL_EQUAL, 1, 0xFF); glStencilMask(0x00);//设定为只读状态 //绘制物体 --------------------------------------------------- //绘制结束后需要设定可写入状态,因为还要清除模板缓冲 glStencilMask(0xFF);
高级效果——物体轮廓绘制
轮廓的绘制可以将一个物体展示的更显眼,游戏中常使用该方法将一个物体或人物作为选中对象,先来看一下效果:主要思路如下:
1. 在绘制箱子时,将模板设定可更新,并更新为1。
2. 将箱子通过scale变换,放大箱子。
3. 绘制时使用纯色来绘制边缘,并设定模板值不等于1时通过测试,即只保留边框部分,注意此时不更新模板缓冲的值。
//开启深度测试和模板测试 glEnable(GL_DEPTH_TEST); glEnable(GL_STENCIL_TEST); /*绘制正常的两个立方体*/ glStencilFunc(GL_ALWAYS, 1, 0xFF); glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); glStencilMask(0xFF); //绘制箱子 .... //----------------------------------------------- //绘制放大的物体 glStencilFunc(GL_NOTEQUAL, 1, 0xFF); glStencilMask(0x00); glDisable(GL_DEPTH_TEST);//关闭深度缓冲,防止轮廓被遮挡 //矩阵变换,放大箱子 model = glm::scale(model, glm::vec3(1.1f, 1.1f, 1.1f)); //绘制放大的箱子 abc9 ... //-------------------------------- 注意绘制后开启深度测试和模板写入权限 glStencilMask(0xFF); glDisable(GL_DEPTH_TEST);
更高级的特效
通过模板测试可以实现很多特效,如Planar reflections(镜面反射),有兴趣的可以自己尝试下。参考资料
1.http://learnopengl-cn.readthedocs.io/zh/latest/04%20Advanced%20OpenGL/02%20Stencil%20testing/2.https://open.gl/depthstencils
3.http://blog.csdn.net/wangdingqiaoit/article/details/52143197
相关文章推荐
- OpenGL学习:Per-fragment operation(1)-模板测试(stencil test)
- OpenGL学习二十九:模板缓冲区与模板测试
- opengl学习-利用模板测试勾画物体轮廓中出现的一个问题
- OpenGL学习脚印:模板测试(stencil testing)
- cocos2D-X源码分析之从cocos2D-X学习OpenGL(13)----模板测试
- OpenGL学习问题记录
- OpenGL学习笔记1:环境配置和基本流程
- OpenGL学习日记-2014.12.2--颜色
- OpenGL 学习
- OpenGL学习之glBegin
- OpenGL-----深度测试,剪裁测试、Alpha测试和模板测试
- OpenGl 学习笔记 01
- OpenGL学习:VAO和VBO以及几种顶点绘图方式比较
- Android OpenGL学习笔记(一)
- 在学习opengl前
- opengl学习
- NVIDIA Jetson TK1学习与开发(八):图文详解OpenGL在Jetson TK1上的安装和使用
- OpenGL入门学习[二] 绘制简单的几何图形
- OpenGL入门学习——第十五课 从“绘制一个立方体”来看OpenGL的进化过程
- OpenGL学习日记0_OpenGL,环境搭建