启用模板测试时,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中try-catch异常逃逸

    有时候一些小的细节,确实比较纠结,对于try-catch-finally代码块中代码依次执行,当try中有exception抛出时,将会有catch拦截并执行,如果没有catch区块,那么except ...

  2. [Docker] Download and Remove Docker Images

    Learn the basics of downloading and pulling Docker images from Docker Hub. Learn the difference betw ...

  3. 修改Linux中的用户名 分类: B3_LINUX 2014-07-24 11:40 440人阅读 评论(0) 收藏

    需要修改2个文件: /etc/hosts /etc/sysconfig/network 然后重启 1.修改/etc/sysconfig/network NETWORKING=yes HOSTNAME= ...

  4. Android MediaScanner使用简单介绍

    1. 运行扫描 仅仅有系统开机的时候才会运行MediaScanner,其他情景下须要手动运行扫描(拍摄,下载等). 手动运行扫描的方法是发送MediaScanner广播: 1.1 扫描指定文件: In ...

  5. [GraphQL] Create an Input Object Type for Complex Mutations

    When we have certain mutations that require more complex input parameters, we can leverage the Input ...

  6. js课程 1-2 js概念

    js课程 1-2  js概念 一.总结 一句话总结:js标签元素也是js对象,有属性和方法,方法就是事件,属性就是标签属性,可以直接调用. 1.js中如何获取标签对象? getElement获取的是标 ...

  7. js动态获取地址栏后的参数

    原文链接:https://blog.csdn.net/qq_37936542/article/details/78866651 需求:js动态的获取地址栏后面的参数 js代码: alert(GetQu ...

  8. 【u110】灾后重建

    Time Limit: 1 second Memory Limit: 128 MB [问题描述] B地区在地震过后,所有村庄都造成了一定的损毁,而这场地震却没对公路造成什么影响.但是在村庄重建好之前, ...

  9. Facial keypoints detection Kaggle 竞赛系列

    3.2# Facial keypoints detection 作者:Stu. Rui QQ: 1026163725 原文链接:http://blog.csdn.net/i_love_home/art ...

  10. 使用apidoc 生成Restful web Api文档

    在项目开发过程中,总会牵扯到接口文档的设计与编写,之前使用的都是office工具,写一个文档,总也是不够漂亮和直观.好在git上的开源大神提供了生成文档的工具,so来介绍一下! 该工具是Nodejs的 ...