模板测试

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

一个模板缓冲中,(通常)每个模板值(Stencil Value)是8位的。所以每个像素/片段一共能有256种不同的模板值。我们可以将这些模板值设置为我们想要的值,然后当某一个片段有某一个模板值的时候,我们就可以选择丢弃或者保留这个片段了。

每个窗口库都需要为你配置一个模板缓冲。GLFW自动做了这件事,所以我们不需要告诉GLFW来创建一个,但其它的窗口库可能不会默认给你创建一个模板库,所以记得要查看库的文档。

模板缓冲首先会被清除为0,之后在模板缓冲中使用1填充了一个空心矩形。场景中的片段将会只在片段的模板值为1的时候会被渲染(其它的都被丢弃了)。

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

  • 启用模板缓冲的写入。 渲染物体,更新模板缓冲的内容。
  • 禁用模板缓冲的写入。
  • 渲染(其它)物体,这次根据模板缓冲的内容丢弃特定的片段。

所以,通过使用模板缓冲,我们可以根据场景中已绘制的其它物体的片段,来决定是否丢弃特定的片段。

我们可以使用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)一共包含三个参数:

  • func:设置模板测试函数(Stencil Test
    Function)。这个测试函数将会应用到已储存的模板值上和glStencilFunc函数的ref值上。可用的选项有:GL_NEVER、GL_LESS、GL_LEQUAL、GL_GREATER、GL_GEQUAL、GL_EQUAL、GL_NOTEQUAL和GL_ALWAYS。它们的语义和深度缓冲的函数类似。
  • ref:设置了模板测试的参考值(Reference Value)。模板缓冲的内容将会与这个值进行比较。
  • mask:设置一个掩码,它将会与参考值和储存的模板值在测试比较它们之前进行与(AND)运算。初始情况下所有位都为1。
 //在一开始的那个简单的模板例子中,函数被设置为:glStencilFunc(GL_EQUAL, 1, 0xFF)//这会告诉OpenGL,只要一个片段的模板值等于(GL_EQUAL)参考值1,片段将会通过测试并被绘制,否则会被丢弃。

但是glStencilFunc仅仅描述了OpenGL应该对模板缓冲内容做什么,而不是我们应该如何更新缓冲。这就需要glStencilOp这个函数了。
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一样,但如果模板值超过了最大值则归零
GL_DECR 如果模板值大于最小值则将模板值减1
GL_DECR_WRAP 与GL_DECR一样,但如果模板值小于0则将其设置为最大值
GL_INVERT 按位翻转当前的模板缓冲值

默认情况下glStencilOp是设置为(GL_KEEP, GL_KEEP, GL_KEEP)的,所以不论任何测试的结果是如何,模板缓冲都会保留它的值。默认的行为不会更新模板缓冲,所以如果你想写入模板缓冲的话,你需要至少对其中一个选项设置不同的值。
所以,通过使用glStencilFunc和glStencilOp,我们可以精确地指定更新模板缓冲的时机与行为了,我们也可以指定什么时候该让模板缓冲通过,即什么时候片段需要被丢弃。

物体轮廓

物体轮廓所能做的事情正如它名字所描述的那样。我们将会为每个(或者一个)物体在它的周围创建一个很小的有色边框。当你想要在策略游戏中选中一个单位进行操作的,想要告诉玩家选中的是哪个单位的时候,这个效果就非常有用了。为物体创建轮廓的步骤如下:
1.在绘制(需要添加轮廓的)物体之前,将模板函数设置为GL_ALWAYS,每当物体的片段被渲染时,将模板缓冲更新为1
2.渲染物体
3.禁用模板写入以及深度测试
4.将每个物体缩放一点点
5.使用一个不同的片段着色器,输出一个单独的(边框)颜色
6.再次绘制物体,但只在它们片段的模板值不等于1时才绘制
7.再次启用模板写入和深测试

模板边框着色器:

void main()
{FragColor = vec4(0.04, 0.28, 0.26, 1.0);
}

先启用模板测试,并设置失败时的操作:

glEnable(GL_STENCIL_TEST);
//如果模板测试和深度测试都通过 模板值设置为glStencilFunc函数设置的ref值
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
//清除颜色,模板缓存,深度缓存,这个时候所有数值为0,颜色缓存中设置的是glClearColors设置的颜色
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
//通过使用GL_ALWAYS模板测试函数,我们保证了箱子的每个片段都会将模板缓冲的模板值更新为1。因为片段永远会通过模板测试
glStencilFunc(GL_ALWAYS, 1, 0xFF); // 所有的片段都应该更新模板缓冲
glStencilMask(0xFF); // 启用模板缓冲写入

以上步骤结束后,我们模板中的数据应该箱子像素所在位置的模板值为1.

绘制放大的箱子:
禁用深度缓存的意义在于不让地板遮挡放大的箱子轮廓

//我们将模板函数设置为GL_NOTEQUAL,它会保证我们只绘制箱子上模板值不为1的部分,即只绘制箱子在之前绘制的箱子之外的部分
glStencilFunc(GL_NOTEQUAL, 1, 0xFF);
glStencilMask(0x00); // 禁止模板缓冲的写入
glDisable(GL_DEPTH_TEST);
shaderSingleColor.use();
DrawTwoScaledUpContainers();

整体绘制思路:

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();// 绘制箱子,并写入箱子位置的模板为1
glStencilFunc(GL_ALWAYS, 1, 0xFF);
glStencilMask(0xFF);
DrawTwoContainers();// 绘制箱子边框,条件是不为1的部分绘制,且这个箱子是放大过后的。同时禁止深度缓存,避免地板遮挡边框,这个时候不写入模板
glStencilFunc(GL_NOTEQUAL, 1, 0xFF);
glStencilMask(0x00);
glDisable(GL_DEPTH_TEST);
shaderSingleColor.use();
DrawTwoScaledUpContainers();
glStencilMask(0xFF);
glEnable(GL_DEPTH_TEST);

https://learnopengl-cn.github.io/04%20Advanced%20OpenGL/02%20Stencil%20testing/#_3

LearnOpenGL学习笔记——模板测试相关推荐

  1. LearnOpenGL学习笔记—入门03:Hello Triangle

    LearnOpenGL学习笔记-入门03:Hello Triangle 0 前言 1 图形渲染管线 2 顶点输入 3 VAO,VBO 3.1 VAO建立 3.2 VBO建立 4 shader 5 绘制 ...

  2. 设计模式学习笔记——模板(Template)模式

    设计模式学习笔记--模板(Template)模式 @(设计模式)[设计模式, 模板模式, template, 模板方法] 设计模式学习笔记模板Template模式 基本介绍 模板案例 类图 实现代码 ...

  3. LearnOpenGL学习笔记—高级光照 09:SSAO

    LearnOpenGL学习笔记-高级光照 09:SSAO 1 原理引入 2 样本缓冲 3 法向半球 4 随机核心转动 5 SSAO着色器 6 环境遮蔽模糊 7 应用环境遮蔽 8 动手试试 8.0 个人 ...

  4. 图论01.最短路专题_学习笔记+模板

    图论01.最短路专题_学习笔记+模板 一.定义与性质 ● 需要的前导知识点 路径 最短路 有向图中的最短路.无向图中的最短路 单源最短路.每对结点之间的最短路 ● 最短路的性质 对于边权为正的图,任意 ...

  5. LearnOpenGL学习笔记—PBR:IBL

    LearnOpenGL学习笔记-PBR:IBL 0 引入 1 渲染方程的求解 2 hdr文件转成cubemap 3 预计算漫反射积分 4 预计算镜面反射积分 4.1 预滤波HDR环境贴图 4.1.1 ...

  6. C++学习笔记:模板

    C++学习笔记:模板 1.函数模板 2.类模板 2.1类模板注意事项 2.2类模板中函数的创建时机 2.3类模板对象作函数参数时 2.4类模板与继承 2.5类模板分文件编写 2.6类模板友元 2.6. ...

  7. image是否有disabled属性_Vue学习笔记 模板语法、计算属性

    点击上方"蓝字"关注我们吧! vue学习笔记 官网:https://cn.vuejs.org/v2/guide/ 1.vue体验 demo示例: image.png 示例代码: & ...

  8. 32位汇编语言学习笔记(45)--测试简单文件操作接口(完)

     这是<Assembly Language step by step programming with linux>书中的最后一个程序,也是全书中的最复杂的一个程序. 首先看一下这个程 ...

  9. C++模板学习笔记——模板实参

    对于函数模板,编译器通过隐式推断模板实参.其中,从函数实参来确定模板实参的过程被称为模板实参推断.在模板实参推断过程中,编译器使用函数调用中的实参类型来寻找模板实参,用这些模板实参生成的函数版本与给定 ...

最新文章

  1. 执行spring boot应用三种方式
  2. MybatisPlus提示 Could not set property 'id' of '***' with value
  3. UE4学习-4.25版本Possess无法继承、UNavigationSystem命名空间找不到的解决方法
  4. 系统学习NLP(二十七)--EMLo
  5. WEB标准布局(DIV+CSS)学习笔记(二)--DIV的布局基础
  6. 阶段1 语言基础+高级_1-3-Java语言高级_08-JDK8新特性_第3节 两种获取Stream流的方式_4_Stream流的特点_只能使用一次...
  7. 【信息系统项目管理师】第十三章 项目合同管理思维导图
  8. python输入直角三角形两条直角边、输出斜边长_用C++输入直角三角形的两条直角边长,调用平方根函数sqrt来求斜边的长度。...
  9. 如何快速学习flex
  10. 使用计算机求解问题首先要,基于计算机的问题求解,首先要完成的是( )
  11. 【C++】手把手教你写出自己的Stack和Queue类
  12. 欧洲服务器与美国服务器哪个比较好呢?
  13. 数据库之Timestamp 的用法
  14. 特斯拉超级工厂监控遭入侵?天懋信息来支招
  15. 关于connet by的学习
  16. [iOS]Objective-C中使用for循环打印输出九九乘法表
  17. AmbiguityVis: Visualization of Ambiguity in Graph Layouts
  18. 红旗linux上网本,红旗Linux系统下肿么改装windows系统 笔记本是sony
  19. 基于PPT的三维光路结构示意图绘制实例演示-技术细节
  20. 【代码】javascript - (异步/非异步) - 进度条

热门文章

  1. 百度地图开发者账号申请
  2. c4d语言包怎么安装方法,Maxon Cinema 4D R23(C4D R23)中英文安装及设置详细教程(附下载)...
  3. 各种电磁仿真软件优缺点
  4. java pdm 解析_GitHub - resgain/PDMParser: PDMParser是一个用来解析Powerdesigner pdm文件的一个简单工具...
  5. 逃离迷宫 ( BFS /DFS)
  6. 辽宁省高考成绩查询时间2021,2021年辽宁高考成绩什么时候出来,今天几点钟出成绩可以查询...
  7. 常见的web攻击方式之服务器端模板注入
  8. 想学点东西,可是心静不下去。纠结中。。。
  9. 【电商数仓】数仓即席查询之Kylin Cube构建原理和构建优化
  10. 软考高级 真题 2011年上半年 信息系统项目管理师 论文