模板测试是把像素存储在模板缓冲区的值与一个参考值进行比较。根据测试的结果,对模板缓冲区中得这个值进行相应的修改。
Note:模板测试只有在存在模板缓冲区的情况下才会执行,如果不存在模板缓冲区,模板测试能够通过。
模板测试最常用的用途就是屏蔽掉屏幕中的一些不规则区域,避免在这些区域中进行绘图。
模板测试过程:
(1)如果使用glut工具包(或者freeglut),要这样进行指定:

[cpp] view plaincopy
  1. glutInitDisplayMode(GL_STENCIL);

(2)启用和禁用模板测试:

[cpp] view plaincopy
  1. glEnable(GL_STENCIL_TEST);  // 启用模板测试
  2. glDisable(GL_STENCIL_TEST); // 禁用模板测试

(3)清除模板缓冲区的值

[cpp] view plaincopy
  1. glClearStencil(0);//指定清除时的值
  2. glClear(GL_STENCIL_BUFFER_BIT);//清除模板缓冲区

(4)选择特定的比较函数、参考值以及掩码

[cpp] view plaincopy
  1. void glStencilFunc( GLenum      func,
  2. GLint   ref,
  3. GLuint      mask);

func指定比较函数,其取值可以是:
GL_NEVER, 
GL_LESS, 
GL_LEQUAL, 
GL_GREATER, 
GL_GEQUAL, 
GL_EQUAL, 
GL_NOTEQUAL, 
and GL_ALWAYS.
ref指定参考值。
mask指定掩码,只在掩码为1的位上进行比较。
OpenGL2.0新增加了glStencilFuncSeparate函数,允许对多边形的正面和背面分别指定模板函数参数。

[cpp] view plaincopy
  1. void glStencilFuncSeparate( GLenum      face,
  2. GLenum      func,
  3. GLint   ref,
  4. GLuint      mask);

(5)指定当片段通过测试与否,模板缓冲区的数据如何修改

[cpp] view plaincopy
  1. void glStencilOp(   GLenum      sfail,
  2. GLenum      dpfail,
  3. GLenum      dppass);

该函数指定了三种情况下“模板值”该如何变化。第一个参数表示模板测试未通过时该如何变化;第二个参数表示模板测试通过,但深度测试未通过时该如何变化;第三个参数表示模板测试和深度测试或者未执行深度测试均通过时该如何变化。(如果没有启用模板测试,则认为模板测试总是通过;如果没有启用深度测试,则认为深度测试总是通过)
变化可以是:
GL_KEEP(不改变,这也是默认值),
GL_ZERO(回零),
GL_REPLACE(使用测试条件中的设定值来代替当前模板值),
GL_INCR(增加1,但如果已经是最大值,则保持不变),
GL_INCR_WRAP(增加1,但如果已经是最大值,则从零重新开始),
GL_DECR(减少1,但如果已经是零,则保持不变),
GL_DECR_WRAP(减少1,但如果已经是零,则重新设置为最大值),
GL_INVERT(按位取反)。

OpenGL2.0新增加了glStencilOpSeparate函数,允许对多边形的正面和背面分别指定独立的模板测试。

接下来的绘制操作就会影响所绘制区域的像素在模板缓冲中的值。

(6)模板查询

可以用glGetInteger函数获取与模板相关的参数值:

[cpp] view plaincopy
  1. glIsEnabled(GL_STENCIL_TEST);

模板测试实例:

示例程序使用了一个螺纹线模板去填充一个矩形框。可以单击鼠标右键弹出菜单选择填充的形式,也可以按键盘的UP,DOWN,LEFT,RIGHT按键旋转坐标系,可以发现模板测试与glPolygonStipple不一样,当坐标系旋转一定角度后,填充的模板也会跟着旋转。

要查询模板测试是否启用:
[cpp] view plain copy
glIsEnabled(GL_STENCIL_TEST);

[cpp] view plaincopy
  1. glIsEnabled(GL_STENCIL_TEST);

模板测试实例:

示例程序使用了一个螺纹线模板去填充一个矩形框。可以单击鼠标右键弹出菜单选择填充的形式,也可以按键盘的UP,DOWN,LEFT,RIGHT按键旋转坐标系,可以发现模板测试与glPolygonStipple不一样,当坐标系旋转一定角度后,填充的模板也会跟着旋转。

[cpp] view plaincopy
  1. glIsEnabled(GL_STENCIL_TEST);
[cpp] view plaincopy
  1. glIsEnabled(GL_STENCIL_TEST);

源代码 :
// GlutStencilDemo.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <gl/glut.h>
#include <math.h>
//圆周率宏
#define GL_PI 3.1415f
//获取屏幕的宽度
GLint SCREEN_WIDTH=0;
GLint SCREEN_HEIGHT=0;
//设置程序的窗口大小
GLint windowWidth=400;
GLint windowHeight=300;
//绕x轴旋转角度
GLfloat xRotAngle=0.0f;
//绕y轴旋转角度
GLfloat yRotAngle=0.0f;
//受支持的点大小范围
GLfloat sizes[2];
//受支持的点大小增量
GLfloat step;
GLint iMode=0;
//菜单回调函数
void processMenu(int value){
switch(value){
case 1:
iMode=0;
break;
case 2:
iMode=1;
break;
}
//重新绘制
glutPostRedisplay();
}
//显示回调函数
void renderScreen(void){
//将窗口颜色清理为黑色
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
//将模板缓冲区值全部清理为1
glClearStencil(1);
//使能模板缓冲区
glEnable(GL_STENCIL_TEST);
    //把整个窗口清理为当前清理颜色:黑色。清除深度缓冲区、模板缓冲区
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
    //将当前Matrix状态入栈
    glPushMatrix();
    //坐标系绕x轴旋转xRotAngle
    glRotatef(xRotAngle,1.0f,0.0f,0.0f);
    //坐标系绕y轴旋转yRotAngle
    glRotatef(yRotAngle,0.0f,1.0f,0.0f);
//进行平滑处理 
glEnable(GL_POINT_SMOOTH);
glHint(GL_POINT_SMOOTH,GL_NICEST);
glEnable(GL_LINE_SMOOTH);
glHint(GL_LINE_SMOOTH,GL_NICEST);
glEnable(GL_POLYGON_SMOOTH);
glHint(GL_POLYGON_SMOOTH,GL_NICEST);

//第一次模板不绘制图形,没有通过模板测试的像素对应模板缓冲区的模板值加1,这样绘制螺旋线的地方模板缓冲区值变为了0x2,没有绘制螺旋线的地方模板缓冲区值还为原来的值0x1
    glStencilFunc(GL_NEVER, 0x0, 0x0);
    glStencilOp(GL_INCR, GL_INCR, GL_INCR);

glColor3f(1.0f, 1.0f, 1.0f);
    glBegin(GL_LINE_STRIP);
GLdouble dAngle = 0;
GLdouble dRadius = 0.1;
//绘制螺旋线,但是不显示出来,仅用来修改模板缓冲区的模板值
        for(dAngle = 0; dAngle < 400.0; dAngle += 0.1)
        {
            glVertex2d(dRadius * cos(dAngle), dRadius * sin(dAngle));
            dRadius *= 1.002;
        }
    glEnd();
            
    if(1==iMode)
glStencilFunc(GL_EQUAL, 0x1, 0x3);//参考值0x1==(模板值&0x3)则绘制,即绘制的是第一次使用模板没有绘图的部分.
else
glStencilFunc(GL_EQUAL, 0x2, 0x3);//参考值0x2==(模板值&0x3)则绘制,即绘制的是第一次使用模板绘图的部分.
    glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
    glColor3f(0.0f, 1.0f, 1.0f);
    glRectf(-40.0f, -40.0f, 40.0f, 40.0f);//使用模板绘制矩形

//恢复压入栈的Matrix
    glPopMatrix();
    //交换两个缓冲区的指针
    glutSwapBuffers();
}
//设置Redering State 
void setupRederingState(void){
    //设置清理颜色为黑色
    glClearColor(0.0f,0.0,0.0,1.0f);
    //设置绘画颜色为绿色
    glColor3f(0.0f,1.0f,0.0f);
//使能深度测试
glEnable(GL_DEPTH_TEST);
//获取受支持的点大小范围
glGetFloatv(GL_POINT_SIZE_RANGE,sizes);
//获取受支持的点大小增量
glGetFloatv(GL_POINT_SIZE_GRANULARITY,&step);
printf("point size range:%f-%f\n",sizes[0],sizes[1]);
printf("point step:%f\n",step);
}
//窗口大小变化回调函数
void changSize(GLint w,GLint h){
    //横宽比率
    GLfloat ratio;
    //设置坐标系为x(-100.0f,100.0f)、y(-100.0f,100.0f)、z(-100.0f,100.0f)
    GLfloat coordinatesize=100.0f;
    //窗口宽高为零直接返回
    if((w==0)||(h==0))
        return;
    //设置视口和窗口大小一致
    glViewport(0,0,w,h);
    //对投影矩阵应用随后的矩阵操作
    glMatrixMode(GL_PROJECTION);
    //重置当前指定的矩阵为单位矩阵 
    glLoadIdentity();
    ratio=(GLfloat)w/(GLfloat)h;
    //正交投影
    if(w<h)
        glOrtho(-coordinatesize,coordinatesize,-coordinatesize/ratio,coordinatesize/ratio,-coordinatesize,coordinatesize);
    else
        glOrtho(-coordinatesize*ratio,coordinatesize*ratio,-coordinatesize,coordinatesize,-coordinatesize,coordinatesize);
    //对模型视图矩阵堆栈应用随后的矩阵操作
    glMatrixMode(GL_MODELVIEW);
    //重置当前指定的矩阵为单位矩阵 
    glLoadIdentity();
}

//按键输入处理回调函数
void specialKey(int key,int x,int y){

if(key==GLUT_KEY_UP){
        xRotAngle-=5.0f;
    }
    else if(key==GLUT_KEY_DOWN){
        xRotAngle+=5.0f;
    }
    else if(key==GLUT_KEY_LEFT){
        yRotAngle-=5.0f;
    }
    else if(key==GLUT_KEY_RIGHT){
        yRotAngle+=5.0f;
    }
    //重新绘制
    glutPostRedisplay();
}

int main(int argc, char* argv[])
{
//初始化glut 
    glutInit(&argc,argv);
    //使用双缓冲区、深度缓冲区、模板缓冲区
    glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA|GLUT_DEPTH|GLUT_STENCIL);
    //获取系统的宽像素
    SCREEN_WIDTH=glutGet(GLUT_SCREEN_WIDTH);
    //获取系统的高像素
    SCREEN_HEIGHT=glutGet(GLUT_SCREEN_HEIGHT);
//创建窗口,窗口名字为OpenGL Stencil Demo
    glutCreateWindow("OpenGL Stencil Demo");
    //设置窗口大小
    glutReshapeWindow(windowWidth,windowHeight);
    //窗口居中显示
    glutPositionWindow((SCREEN_WIDTH-windowWidth)/2,(SCREEN_HEIGHT-windowHeight)/2);
//创建菜单
glutCreateMenu(processMenu);
glutAddMenuEntry("Display Stencil",1);
glutAddMenuEntry("Don't dsplay Stencil",2);
glutAttachMenu(GLUT_RIGHT_BUTTON);
    //窗口大小变化时的处理函数
    glutReshapeFunc(changSize);
    //设置显示回调函数 
    glutDisplayFunc(renderScreen);
    //设置按键输入处理回调函数
    glutSpecialFunc(specialKey);
    //设置全局渲染参数
    setupRederingState();
    glutMainLoop();
    return 0;
}
 
本博客还有另外一个讲解模板缓冲区的例子,参见:http://blog.163.com/danshiming@126/blog/static/109412748201632895137788/

[cpp] view plaincopy
  1. glIsEnabled(GL_STENCIL_TEST);

模板测试实例:

示例程序使用了一个螺纹线模板去填充一个矩形框。可以单击鼠标右键弹出菜单选择填充的形式,也可以按键盘的UP,DOWN,LEFT,RIGHT按键旋转坐标系,可以发现模板测试与glPolygonStipple不一样,当坐标系旋转一定角度后,填充的模板也会跟着旋转。

OPenGL模板缓冲区示例程序相关推荐

  1. opengl模板缓冲区

    相信大家有些人对opengl的模板缓冲区不是很理解,包括我最开始也是,opengl的模板缓冲区其实就是采用过滤的技术来控制那些颜色可以绘制,那些不能进行绘制.这里的过滤技术也就是我们的一个控制方法,主 ...

  2. OpenGL的glScissor示例程序

    剪裁测试用于限制绘制区域.我们可以指定一个矩形的剪裁窗口,当启用剪裁测试后,只有在这个窗口之内的像素才能被绘制,其它像素则会被丢弃.换句话说,无论怎么绘制,剪裁窗口以外的像素将不会被修改.有的朋友可能 ...

  3. VS2012下基于Glut OpenGL显示一些立体图形示例程序:

    Glut下提供了一些现成的绘制立体的API,如glutWireSphere绘制球,glutWireCone绘制椎体,glutWireCube绘制立体,glutWireTorus绘制甜圈,glutWir ...

  4. VS2012下基于Glut OpenGL GL_STENCIL_TEST示例程序:

    模板测试是把像素存储在模板缓冲区的值与一个参考值进行比较.根据测试的结果,对模板缓冲区中得这个值进行相应的修改. Note:模板测试只有在存在模板缓冲区的情况下才会执行,如果不存在模板缓冲区,模板测试 ...

  5. OpenGL:显示一些立体图形示例程序(真不错)

    // GlutDemo.cpp : 定义控制台应用程序的入口点. // //#include "stdafx.h" #include <stdio.h> #includ ...

  6. VS2012下基于Glut OpenGL GL_QUADS示例程序:

    OpenGL 使用GL_QUADS绘制四边形示例程序,显示效果如下所示. GL_QUADS连续点生成四边形的规则如下图所示: 源代码如下: // GlutQuadsDemo.cpp : 定义控制台应用 ...

  7. OpenGL使用模板缓冲区和剪切平面

    OpenGL使用模板缓冲区和剪切平面 先上图,再解答. 完整主要的源代码 源代码剖析 先上图,再解答. 完整主要的源代码 #include <stdio.h> #include " ...

  8. OpenGL学习二十九:模板缓冲区与模板测试

    帧缓冲区有许多缓冲区构成,这些缓冲区大致分为: 颜色缓冲区:用于绘图的缓冲区,它包含了颜色索引或者RGBA颜色数据. 深度缓冲区:存储每个像素的深度值,当启动深度测试时,片段像素深度值和深度缓冲区深度 ...

  9. VS2012下基于Glut 矩阵变换示例程序2:

    在VS2012下基于Glut 矩阵变换示例程序:中我们在绘制甜圈或者圆柱时使用矩阵对相应的坐标进行变换后自己绘制甜圈或者圆柱.我们也可以使用glLoadMatrixf.glLoadMatrixd载入变 ...

最新文章

  1. protobuf和socket通信简单实例
  2. ping 代理_Happy专访:Ping太高不是问题 换我不会像120一样比赛
  3. 阿里内部禁用Executors创建线程池,为什么?
  4. python简单代码 春节集五福-集五福活动又来了,不过这个价值几十亿的大项目也别错过...
  5. 卷积神经网络补充—GoogleNet
  6. latex 常用小结
  7. 《统计学》学习笔记之参数估计
  8. 在.NET开发面向Oracle数据库的应用程序
  9. 如何使用spy ++ (How to use Spy ++)
  10. java实现rsa欧几里得算法求d_RSA算法中利用欧几里得算法求d详细过程
  11. 一口气说出 6 种延时队列的实现方法,面试官满意的笑了
  12. 全奖博士招生,伦敦大学学院盖茨比计算神经科学研究组
  13. 7-81 编程团体赛 (20 分)
  14. 用oledb导出数据到excel
  15. AcWing 788. 逆序对的数量
  16. redis数据类型之String
  17. SVPWM算法理解(一)——基本原理
  18. 腾讯服务器每秒有2W个QQ号同时上线,找出5min内重新登入的qq号并打印出来。
  19. matlab 图像中4像素融合一个像素,python实现两张图片的像素融合
  20. 阿里云的ACA认证到底是个啥?有用吗?

热门文章

  1. 基于verilog的洗衣机设计
  2. 流程控制_月隐学python第4课
  3. 商业逻辑12讲之管理思维的逻辑
  4. pytorch 转换onnx_新版PyTorch发布!新增TorchScript API,扩展ONNX导出
  5. android 通讯录字母排序,Android仿微信联系人字母排序效果
  6. mysql业务 日志_mysql笔记之日志篇
  7. pdf导入ps颜色太浅_PDF 文件编辑转换难?或许你需要一个扫描全能王!
  8. python中变量和函数的区别_关于python中带下划线的变量和函数 的意义
  9. css布局方式_手把手教你CSS Flex布局「真香」
  10. mvn 本地jar包 加入自己的maven仓库