启用模板测试时,OpenGL会在内存中开辟一块空间作为模板缓冲区,里边保存了每个像素的“模板值”,模板测试的过程就是把每一个像素的模板值与一个设定的模板参考值进行比较,符合设定条件的通过测试,不符合条件的则不会绘制。

glClearStencil函数用来指定模板值复位后的初始值,跟使用glClearColor函数指定复位后画板的颜色一样。

glStencilFunc函数用来设置模板测试条件。第一个是模板测试条件,第二个是指定的当前模板的测试值,程序会使用改值与参考模板值进行比较,第三个是mask位,设置后,只会比较mask中二进制位位1的位。

glStencilOp (GLenum fail, GLenum zfail, GLenum zpass)用来设置模板值根据模板测试结果和深度测试结果的结果如何变化。

第一个参数表示模板测试未通过时该如何变化,第二个参数表示模板测试通过,但深度测试未通过时该如何变化,第三个参数表示模板测试和深度测试均通过时该如何变化。这种模板的变换可以是:

  • GL_KEEP(不改变,这也是默认值)
  • GL_ZERO(回零)
  • GL_REPLACE(使用测试条件中的设定值来代替当前模板值)
  • GL_INCR(增加1,但如果已经是最大值,则保持不变)
  • GL_INCR_WRAP(增加1,但如果已经是最大值,则从零重新开始)
  • GL_DECR(减少1,但如果已经是零,则保持不变)
  • GL_DECR_WRAP(减少1,但如果已经是零,则重新设置为最大值)
  • GL_INVERT(按位取反)

另外程序中用到了glPushMatrix和glPopMatrix两个函数,glPushMatrix函数将当前矩阵压入堆栈,使得之后的操作不受之前矩阵变换的影响,都是相对于原始的世界坐标系进行操作。
glPopMatrix将与之最近的一个glPushMatrix压入堆栈的矩阵取出,使得之前的矩阵变换对其后的运算有效。这两个函数的配合使用可以使得两者之间的矩阵操作不受之前生成的变换矩阵的影响,并且两者之间的矩阵操作也不会对主体的矩阵变换产生影响。

以下是使用模板测试功能,实现平面镜功能,镜子之外的物体不会绘制:

#define WindowWidth   400
#define WindowHeight 400
#define WindowTitle "OpenGL模板测试"
#include <gl/glut.h> GLfloat angle = 0.0f; void draw_sphere()
{
// 设置光源
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
{
GLfloat
pos[] = {5.0f, 5.0f, 0.0f, 1.0f},
ambient[] = {0.0f, 0.0f, 1.0f, 1.0f};
glLightfv(GL_LIGHT0, GL_POSITION, pos);
glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
} // 绘制一个球体
glPushMatrix();
glTranslatef(0, 0, 2);
glutSolidSphere(0.8, 20, 20);
glPopMatrix();
} void display(void)
{
// 清除屏幕
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // 设置观察点
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60, 1, 5, 25);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(5, 0, 6.5, 0, 0, 0, 0, 1, 0); glRotatef(angle,0,1,0); glEnable(GL_DEPTH_TEST); // 绘制球体
glDisable(GL_STENCIL_TEST);
draw_sphere(); // 绘制一个平面镜。在绘制的同时注意设置模板缓冲。
// 另外,为了保证平面镜之后的镜像能够正确绘制,在绘制平面镜时需要将深度缓冲区设置为只读的。
// 在绘制时暂时关闭光照效果
glClearStencil(0);
glClear(GL_STENCIL_BUFFER_BIT);
glStencilFunc(GL_ALWAYS, 1, 0xFF);
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
glEnable(GL_STENCIL_TEST); glDisable(GL_LIGHTING);
glColor3f(0.5f, 0.5f, 0.5f);
glDepthMask(GL_FALSE);
glRectf(-2.0f, -2.0f, 1.6f, 1.6f);
glDepthMask(GL_TRUE); // 绘制一个与先前球体关于平面镜对称的球体,注意光源的位置也要发生对称改变
// 因为平面镜是在X轴和Y轴所确定的平面,所以只要Z坐标取反即可实现对称
// 为了保证球体的绘制范围被限制在平面镜内部,使用模板测试
glStencilFunc(GL_EQUAL, 1, 0xFF);
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
glScalef(1.0f, 1.0f, -1.0f);
draw_sphere(); // 交换缓冲
glutSwapBuffers();
} void myIdle(void)
{
angle+=0.1f;
if( angle >= 360.0f )
angle = 0.0f;
display();
} int main(int argc, char* argv[])
{
// GLUT初始化
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowPosition(100, 100);
glutInitWindowSize(WindowWidth, WindowHeight);
glutCreateWindow(WindowTitle);
glutDisplayFunc(&display);
glutIdleFunc(&myIdle);
// 开始显示
glutMainLoop();
return 0;
}

运行截图:
    

  

OpenGL(十四) 模板测试的更多相关文章

  1. opengl学习-利用模板测试勾画物体轮廓中出现的一个问题

    我在学习OpenGL模板测试勾画物体轮廓的时候,出现了这个问题: 这个出现的原因就是,改变摄像机的时候,每次绘制,上次绘制中模板缓冲区的数据没有清除的原因.也就是在while循环开始的时候,glCle ...

  2. NeHe OpenGL教程 第四十四课:3D光晕

    转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...

  3. NeHe OpenGL教程 第二十四课:扩展

    转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...

  4. Android OpenGL ES(十四)gl10方法解析

    Android 支持 OpenGL 列表 1.GL 2.GL 10 3.GL 10 EXT 4.GL 11 5.GL 11 EXT 6.GL 11 ExtensionPack 我们将使用 GL10 这 ...

  5. OpenGL ES 中的模板测试

    模板测试的主要功能是丢弃一部分片元,相对于深度检测来说,模板测试提出的片元数量相对较少.模板测试发生在剪裁测试之后,深度测试之前. 使用模板测试时很重要的代码提示: 1.glClear( GL_STE ...

  6. Kali Linux Web 渗透测试视频教程—第十四课-arp欺骗、嗅探、dns欺骗、session劫持

    Kali Linux Web 渗透测试视频教程—第十四课-arp欺骗.嗅探.dns欺骗.session劫持 文/玄魂 目录 Kali Linux Web 渗透测试—第十四课-arp欺骗.嗅探.dns欺 ...

  7. NeHe OpenGL教程 第三十四课:地形

    转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...

  8. NeHe OpenGL教程 第十四课:图形字体

    转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...

  9. OpenGL利用模板测试实现不规则裁剪

    本文是原创文章,如需转载,请注明文章出处 在游戏开发中,经常会有这样的需求:给定一张64x64的卡牌素材,要求只显示以图片中心为圆点.直径为64的圆形区域,这就要用到模板测试来进行不规则裁剪. 实现不 ...

随机推荐

  1. JAVA: Socket和ServerSocket网络编程

    面是本次学习的笔记.主要分异常类型.交互原理.Socket.ServerSocket.多线程这几个方面阐述. 异常类型 在了解Socket的内容之前,先要了解一下涉及到的一些异常类型.以下四种类型都是 ...

  2. iconv简介(1、字符串|文件字符转换:iconv用于将一种已知的字符集文件转换成另一种已知的字符集文件)(2、编程语言函数功能的相似性:iconv不仅再php中有用,而且c语言中也有用,还有linux等)

    iconv简介(1.字符串|文件字符转换:iconv用于将一种已知的字符集文件转换成另一种已知的字符集文件)(2.编程语言函数功能的相似性:iconv不仅再php中有用,而且c语言中也有用,还有lin ...

  3. docker nginx实现一个主机部署多个站点

    原文:docker nginx实现一个主机部署多个站点 在某站租赁的虚拟机快到期了,续费得花200多,想到在阿里云新买的服务器,不如把这个也转移过去.域名我就用真实的吧,大家别黑我网站就好了,谢谢各位 ...

  4. Android图文具体解释属性动画

    Android中的动画分为视图动画(View Animation).属性动画(Property Animation)以及Drawable动画.从Android 3.0(API Level 11)開始. ...

  5. IT增值服务实践心得体会:企业客户的钱比个人客户好赚得多

    友情提示 本人喜欢直言不讳,不喜欢拐弯抹角.喜欢从客观和主观.自身和他人等多种角度去探讨问题.如有不当之处,欢迎吐槽. 若干心得体会1.企业客户的钱更好赚,个人客户的钱很难.  为什么这么说呢? a. ...

  6. 西方教育骗局,终于明白精英和普通人的残酷差别!(该校流传着一个数字——4。即“4小时睡眠、4杯咖啡、GPA4.0”——要想获得满分为4分的成绩,每天只睡4个小时,困了就喝4大杯咖啡)

    2018-02-14 00:00英国/私立学校 你不知道的是:西方教育通过一个宽松的过程,偷偷完成了社会分层. 1 “中国学生真是太苦了!”我的同学李女士总是发出这样的感慨. 李女士是我中学同学,在一 ...

  7. HDU 1501 - dp

    传送门 题目大意: 问两个词能不能加错拼成一个第三个词. 题目分析: dp方程还是很好想:dp[i][j]表示第一个词前i个和第二个词前j个能不能拼成第三个词的前i+j个. 初始化如果s1[1] == ...

  8. spark cogroup算子

    java /** *cogroup与join算子不同的是如果rdd中的一个key,对应多个value,则返回<Iterable<key>,Iterable<value>& ...

  9. 在JS中var、let和const的区别

    var有变量提升 x = 4; // 变量 x 设置为 4 console.log(x)  //输出 4 var x; // 声明 x 上面代码相当于下面的 var x; // 声明 xx = 4;  ...

  10. numpy 下的数据结构与数据类型的转换(np.array vs. np.asarray)

    1. np.asarray -- numpy 风格的类型转换 从已有多维数组创建新的多维数组,数据类型可重新设置 >> B = np.asarray(A, dtype='int32') 2 ...