OpenGL的模板缓冲
注意看,利用OpenGL的模板缓冲,可以轻松实现很多酷炫的效果。当然,它用起来也很简单。下面就跟着博主小编,一起来看看吧!
模板缓冲的使用
假设有个大小为800x600的窗口,那么模板缓冲也是一个800x600的数组,每个值为一个字节,可以保存0x00~0xFF内的值,这就是模板缓冲的全部啦。
之前介绍过深度测试,有了模板缓冲后,就可以启用模板测试。启用后,对于每一个待处理的点,只有通过模板测试后,才能绘制到窗口上。
使用前,需要先启用模板测试:
glEnable(GL_STENCIL_TEST);
对于模板缓冲,最基本的操作是将其全部清零:
glClear(GL_STENCIL_BUFFER_BIT);
启用模板测试后,绘制物体到窗口的同时会写入模板缓冲。我们可以将某个值写入模板缓冲,但是这个值在写入前会与一个掩码进行逐位and运算,这个掩码的值可通过以下函数设置:
glStencilMask(GLuint mask);
最常用的掩码值是0x00和0xFF, 掩码的默认值为0xFF, 学过位运算的朋友都知道,0xFF不改变写入的值。
写入模板的操作主要是通过以下函数指定:
glStencilFunc(GLenum func, GLint ref, GLuint mask);
模板缓冲中的值会与参考值ref执行某种运算,运算通过参数func指定,例如大于(GL_GREATER)、等于(GL_EQUAL)等等。如果比较的结果是true,则“通过了模板测试”。mask是一个掩码,用法和上面提到的基本相同。对于参数func,除了上面这些比较运算,还有两个另类的操作GL_ALWAYS和GL_NEVER,从名字就可以看出,前者总是通过模板测试,后者总是无法通过模板测试。
模板缓冲的写入还受到另一个函数的影响:
glStencilOp(GLenum sfail, GLenum dpfail, GLenum dppass);
sfail表示没有通过模板测试后应该做什么;
dpfail表示模板测试通过,但深度测试没通过应该做什么;
dppass表示模板和深度测试都通过后应该做什么。
以上描述中的“应该做什么”,其实是一个枚举值,常见的有GL_KEEP(保存当前值)、GL_REPLACE(替换为glStencilFunc中的参数ref)等等。这三个参数默认都是GL_KEEP, 即不修改模板缓冲的值。因此,如果想要写入模板缓冲,至少需要设置其中的某个参数。
以上函数中,深度测试与缓冲测试同时出现。我不太清楚这样设计的动机,不过从下面的两个例子可以看出,使用模板测试时,经常需要考虑深度缓冲。
上面这些可能看上去还是让人云里雾里,下面来看两个使用模板测试的例子吧。
遮罩效果
遮罩是一种常见的动画效果,例如射击游戏中的望远镜视角。下图展示了一红一绿两个正方形,其中绿色正方形在红色正方形的后面:

现在我想以红色正方形作为遮罩层,也就是说,只能看到被红色正方形遮挡的那一部分。
启用模板测试后,确保模板测试可以写入模板缓冲:
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
这里设置为:只有模板和深度测试都通过后,才向模板缓冲写入值ref,所以最后一个参数设置为GL_REPLACE.
初始时清空模板缓冲:
glClear(GL_STENCIL_BUFFER_BIT);
在绘制红色正方形前,设置写入模板缓冲的条件:
glStencilFunc(GL_ALWAYS, 66, 0xFF);
这里,我们使用的是GL_ALWAYS, 即总是通过模板测试。因此,红色正方形在模板缓冲中的相应位置都会写入值66. (66是我随便设置的数字,我觉得这个数字还不错)。
在绘制绿色正方形之前,先清空深度缓冲,否则这些被遮挡的绿色部分无法通过深度测试。
glClear(GL_DEPTH_BUFFER_BIT);
现在,我们就可以根据模板缓冲来绘制啦!当前的模板缓冲中,红色正方形对应的位置被写入了66,我们只绘制模板缓冲中值为66的这部分区域:
glStencilFunc(GL_EQUAL, 66, 0xFF);
此函数表示,“在模板缓冲中对应位置为66”的像素点才能通过模板测试,最终被画出来。
完成后,效果应该是下面这个样子:

可以看到,只有通过红色正方形可以看到的部分被绘制出来。如果不希望出现左下角的红色部分,我能想到的简单解决方案是,在绘制红色正方形完成后,清空下颜色缓冲。
边缘绘制
这是Learn OpenGL教程中的一个例子,用于绘制物体被选中时的的效果。
首先启用模板缓冲,在绘制物体前,设置为“总是写入模板缓冲”,然后写入某个值,比如说写入1. 现在我们画一个机器人:

机器人画好后,机器人所占的这块区域在模板缓冲的对应位置都会写入1.
最精彩的部分来了:我们把这个机器人稍微放大一些,然后仅在模板缓冲取值不为1的那些地方绘制像素点,写一个着色器,将这些点画成绿色。最后的效果如下:

上图的绿色部分就是模板缓冲中取值不为1的区域,里面的机器人所在的区域也就是模板缓冲中取值为1的区域。
小结
模板缓冲其实很简单,可能我写得不是太清楚。就是这么简单的东西,能做出各种酷炫的视觉效果。如果有什么写得不对的地方,欢迎在评论区批评指正。我们下次,不见不散!
OpenGL的模板缓冲的更多相关文章
- windows API下的模板缓冲(stencil buffer)
在windows API搭建的OpenGL窗口中使用模板缓冲,需要在像素格式描述表中设置stencil buffer位宽为8,这样窗口会自动生成stencil buffer,然后可以在opengl环境 ...
- Shader 模板缓冲和模板测试
http://blog.sina.com.cn/s/blog_6e159df70102xa67.html 模板缓冲的概念 Unity官方的Shader文档根本没有提到这个玩意,这个概念也是看到了UGU ...
- 进一步使用 模板缓冲(stencil)
最近做课题的时候需要计算一个 view(就是一次渲染得到的帧) 下的重叠像素个数(两个物体或更多的物体重叠). 最开始我的想法是渲染一个物体输出一张纹理,这样对比物体之间的纹理就知道重叠了.但是这样当 ...
- WebGL学习笔记(十五):模板缓冲
可以用来干啥? 模板缓冲一般用来实现一些地面反射投影和类似镜子的特殊效果,如下: 开启模板缓冲 默认情况下,模板缓冲是关闭的,模板缓冲如果处于关闭状态,运行模板相关的代码不会报错,但是不会出现预期的效 ...
- 简单的opengl步骤模板
以下内容整理自:https://learnopengl-cn.github.io/01%20Getting%20started/03%20Hello%20Window/ 一.初始化 glfw 并设置相 ...
- OpenGL利用模板测试实现不规则裁剪
本文是原创文章,如需转载,请注明文章出处 在游戏开发中,经常会有这样的需求:给定一张64x64的卡牌素材,要求只显示以图片中心为圆点.直径为64的圆形区域,这就要用到模板测试来进行不规则裁剪. 实现不 ...
- webgl 模板缓冲
先思考个问题, 想实现遮罩怎么办? <!doctype html> <html> <head> <meta charset="utf-8" ...
- OpenGL ES 中的模板测试
模板测试的主要功能是丢弃一部分片元,相对于深度检测来说,模板测试提出的片元数量相对较少.模板测试发生在剪裁测试之后,深度测试之前. 使用模板测试时很重要的代码提示: 1.glClear( GL_STE ...
- OpenGL核心技术之帧缓冲
笔者介绍:姜雪伟.IT公司技术合伙人,IT高级讲师.CSDN社区专家.特邀编辑.畅销书作者,国家专利发明人;已出版书籍:<手把手教你架构3D游戏引擎>电子工业出版社和<Unity3D ...
- OpenGL(十四) 模板测试
启用模板测试时,OpenGL会在内存中开辟一块空间作为模板缓冲区,里边保存了每个像素的"模板值",模板测试的过程就是把每一个像素的模板值与一个设定的模板参考值进行比较,符合设定条件 ...
随机推荐
- Windows环境下,解决无法使用ping命令
众所周知,ping命令是个非常实用的网络命令:有时,我们会发现在电脑中无法使用ping命令,一般来说,是由于电脑的环境变量出了问题,本文将介绍如何解决这个问题. 1.一般出现ping命令无法使用的情况 ...
- P1802-DP【橙】
1.又是一道因为写了异常剪枝而调了好久的题,以后再也不写异常剪枝了,异常情况压根不该出现,所以针对出现的异常情况进行补救的异常剪枝是一种很容易出错的行为,做为两手准备也就罢了,但第一次写成的代码必须能 ...
- 如何使用Markdown编写笔记
Markdown是什么? Markdown 是一种轻量级标记语言,创始人为约翰·格鲁伯(John Gruber). 它允许人们使用易读易写的纯文本格式编写文档,然后转换成有效的 XHTML(或者HTM ...
- Spring Boot Actuator 使用和常用配置
转载请注明出处: Spring Boot Actuator是Spring Boot提供的一个非常强大的工具,它可以帮助我们监控和管理我们的Spring Boot应用.Actuator提供了一系列的端点 ...
- 使用docker compose 编排微服务发布
本文为博主原创,未经允许不得转载: 目录: 1. compose 简介 2. compose 安装 3. 编写 docker-compose.yml 实现微服务发布 4. docker-compose ...
- wireshark 抓包使用
本文为博主原创,转载请注明出处: 在项目开发过程当中,尤其在联调和测试功能的使用,经常会用到抓包,用抓包进行问题的定位. 所以记录一下wireshark的使用,如何抓包,分析,保存等. wiresha ...
- 09-Verilog-并发线程
Verilog-线程 并发线程 verilog和C语言有一个最大的不同就是并发性 并发--同时进行的过程 module tb_test; int a; initial begin a = 1; a = ...
- .NET开源的简单、快速、强大的前后端分离后台权限管理系统
前言 今天分享一款前端基于Vue3,后端基于.NET8开源的免费(MIT license).简单.快速.强大的前后端分离后台权限管理系统:中台Admin(Admin.Core). 项目官方介绍 中台A ...
- [转帖]find排除一个或多个目录的方法
find排除一个或多个目录的方法 百度就是垃圾,搜索结果千篇一律,错抄错.google一下,总结find排除某个目录的方法: How to exclude a directory in find . ...
- [转帖]kubelet 原理解析六: 垃圾回收
https://segmentfault.com/a/1190000022163856 概述 在k8s中节点会通过docker pull机制获取外部的镜像,那么什么时候清除镜像呢?k8s运行的容器又是 ...