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

glutInitDisplayMode(GL_STENCIL);  

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

glEnable(GL_STENCIL_TEST);  // 启用模板测试
glDisable(GL_STENCIL_TEST); // 禁用模板测试

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

glClearStencil(0);//指定清除时的值
glClear(GL_STENCIL_BUFFER_BIT);//清除模板缓冲区  

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

void glStencilFunc( GLenum      func,  GLint   ref,  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函数,允许对多边形的正面和背面分别指定模板函数参数。

void glStencilFuncSeparate( GLenum      face,  GLenum      func,  GLint   ref,  GLuint      mask);

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

void glStencilOp(   GLenum      sfail,  GLenum      dpfail,  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函数获取与模板相关的参数值:

要查询模板测试是否启用:

glIsEnabled(GL_STENCIL_TEST);

模板测试实例:

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





源代码 :

// 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);//将模板缓冲区值全部清理为1glClearStencil(1);//使能模板缓冲区glEnable(GL_STENCIL_TEST);//把整个窗口清理为当前清理颜色:黑色。清除深度缓冲区、模板缓冲区glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);//将当前Matrix状态入栈glPushMatrix();//坐标系绕x轴旋转xRotAngleglRotatef(xRotAngle,1.0f,0.0f,0.0f);//坐标系绕y轴旋转yRotAngleglRotatef(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,没有绘制螺旋线的地方模板缓冲区值还为原来的值0x1glStencilFunc(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)则绘制,即绘制的是第一次使用模板没有绘图的部分.elseglStencilFunc(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);//使用模板绘制矩形//恢复压入栈的MatrixglPopMatrix();//交换两个缓冲区的指针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);elseglOrtho(-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 DemoglutCreateWindow("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;
}

VS2012下基于Glut OpenGL GL_STENCIL_TEST示例程序:相关推荐

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

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

  2. VS2012下基于Glut OpenGL GL_POLYGON示例程序:

    很多书介绍GL_POLYGON连续点生成多边形时这下点必须是凸多边形的,规则如下图所示.写个Demo验证了下似乎不是凸多边形的也可以. Demo的正面与背面显示效果: 源代码如下所示: // Glut ...

  3. VS2012下基于Glut OpenGL glScissor示例程序:

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

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

    glDepthMask (GLboolean flag)函数可以决定将他之后的数据不写入深度缓冲区.当flag为GL_TRUE时之后的数据不写入深度缓冲区,即使启用了深度缓冲区测试功能. 使用上一个D ...

  5. VS2012下基于Glut OpenGL glEdgeFlag示例程序:

    glEdgeFlag (GLboolean flag)表示一个顶点是否应该被认为是多边形的一条边界边的起点.flag为GL_TRUE后面的点都被认为是边界上的点,flag为GL_FALSE则之后的点不 ...

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

    直线可以被画成虚线,而多边形则可以进行镂空. 首先,使用glEnable(GL_POLYGON_STIPPLE);来启动镂空模式(使用glDisable(GL_POLYGON_STIPPLE)可以关闭 ...

  7. VS2012下基于Glut OpenGL GL_QUAD_STRIP示例程序:

    OpenGL连续点通过GL_QUAD_STRIP生成四边形规则如下图所示: 演示程序效果如下图所示: 源代码如下所示: // GlutQuadStripDemo.cpp : 定义控制台应用程序的入口点 ...

  8. VS2012下基于Glut glRotatef glTranslatef示例程序:

    Demo使用glRotatef ,glTranslatef来实现一个太阳.地球.月亮运动的3D图形. 1.glTranslatef() --模型变换函数移动 voidglTranslatef(GLfl ...

  9. VS2012下基于Glut 绘制立方体示例程序:

    使用glBegin(GL_QUADS)绘制六个侧面来组成一个立方体:并使用glFrontFace(GL_CW).glFrontFace(GL_CCW)来设置每个面的正面:使用glColor3ub来设置 ...

最新文章

  1. explorer.exe应用程序错误说明 0X000000该内存不能为read的解决方法
  2. 干货!一文读懂人工智能和机器学习有什么关系
  3. jenkins 入门教程(下)
  4. 测试类异常Manual close is not allowed over a Spring managed SqlSession
  5. jquery-validation插件
  6. c++ fork 进程时 共享内存_linux共享内存mmap
  7. NYOJ5056_黑色帽子(水题)
  8. 怎样检查python环境是否安装好_如何搭建pytorch环境的方法步骤
  9. Error -26612: HTTP Status-Code=500 (Internal Server Error) ...
  10. android jenkins 配置NDK环境变量
  11. Android实例-手机安全卫士(三十六)-根据Service是否开启确定CheckBox选中状态
  12. 计算机怎样用计算法绘制圆弧,计算机图形学圆弧生成算法具体程序实现
  13. String、StringBuffer、StringBuilder之间的区别 简明介绍
  14. Centos查看进程命令
  15. 34 模板方法模式(模板方法设计模式)详解
  16. 【有限元分析】ANSYS workbench CFX风力机外流场计算
  17. 用链表写的一个通讯录
  18. 电脑端微信多开操作方法
  19. DevJoy 展商大名单+活动剧透!逛开发者游园会,体验沉浸式打 Bug!
  20. 【开源“青女四轴”,DIY小四轴】

热门文章

  1. PaddleOCR文字识别使用
  2. php addall,thinkphp addall() 方法设置
  3. php websocket ipv6,原生socket支持ipv6
  4. java从内存角度理解类变量_深入理解volatile类型——从Java虚拟机内存模型角度...
  5. python运维方法_Python运维开发基础09-函数基础【转】
  6. session作用域_看完这篇Bean的作用域与生命周期,问到面试官不敢问-乐字节java...
  7. 利用可达矩阵判断连通性_leetcode240. 搜索二维矩阵 II
  8. pycharm出现KeyError:“Couldn't find filed google.ptotobuf.FileOption.javanano_use_deprecated_package”
  9. 测试开发:提升测试效率都有哪些具体手段?
  10. 测试行业爬了7年,从功能测试到高级测试,工资也翻了好几倍