OpenGL: 模板缓冲区的理解

引用:http://blog.163.com/danshiming@126/blog/static/109412748201632895137788/

这几天看《OPenGL 编程指南》中的模板缓冲区,一头雾水,根本就没怎么理解,然后网上找了一些例子,先将自己理解的记录如下:

模板缓冲区(Stencil Buffer):与颜色缓冲区和深度缓冲区类似,模板缓冲区可以为屏幕上的每个像素点保存一个无符号整数值。这个值的具体意义视程序的具体应用而定。在渲染的过程中,可以用这个值与一个预先设定的参考值相比较,根据比较的结果来决定是否更新相应的像素点的颜色值。这个比较的过程被称为模板测试。模板测试发生在透明度测试(alpha test)之后,深度测试(depth test)之前。如果模板测试通过,则相应的像素点更新,否则不更新。就像使用纸板和喷漆一样精确的混图一样,当启动模板测试时,通过模板测试的片段像素点会被替换到颜色缓冲区中,从而显示出来,未通过的则不会保存到颜色缓冲区中,从而达到了过滤的功能。下图描述了模板缓冲区的原理:
OpenGL: 模板缓冲区的理解 - danshiming - danshiming的博客
如上图中:人拿着喷漆枪通过一个有T形孔的板向后面的纸板喷漆,由于T形孔板其它部分都是不透空的,只有T形孔是空的,所以油漆只能从T形空透过去,喷到后面的纸板上,从而使纸板呈现出一个T形。这里的T形版可以理解为OPenGL的模板缓冲区,后面的纸板可以理解为OPenGL的颜色缓冲区,整个过程可例比为OPenGL的模板测试。
 
OpenGL的模板缓冲区其实就是采用过滤的技术来控制那些颜色可以绘制,那些不能进行绘制。这里的过滤技术也就是我们的一个控制方法。 了解模板缓冲区的原理,下面我们看看在OpenGL中如何使用模板缓冲区进行测试。OpenGL中与模板缓冲区相关的函数有如下几个:
// 默认模板缓冲区并未开启需要使用glEnable开启
glEnable(GL_STENCIL_TEST); 
 // 设置模板缓冲区的写入掩码:当为false时禁止在Stencil Buffer中写入(默认0xff)
glStencilMask(0xFF);
// 清除Stencil Buffer的值默认为0
glClearStencil(clearStencilValue); 
 // 默认值GL_ALWAYS, 0, 0xFF, 总是通过Stencil测试
glStencilFunc(func, ref, mask);
// 默认GL_KEEP, GL_KEEP, GL_KEEP, 不会改变Stencil Buffer
glStencilOp(fail,zfail,zpass); 
// 清除StencilBuffer
glClear(GL_STENCIL_BUFFER_BIT); 
模板测试只有存在模板缓冲区且模板缓冲区开启的情况下进行,模板测试把像素存储在模板缓冲区的点与一个参考值进行比较(glStencilFunc),根据测试结果,对模板缓冲区的值进行响应的修改glStencilOp
//哈哈:来我这儿考试吧,通过的和不通过的都去glStencilOp那儿看看下一步的操作吧
void glStencilFunc (GLenum func, GLint ref, GLuint mask);
  func:
    GL_NEVER 从来不能通过
  GL_ALWAYS 永远可以通过(默认值)
  GL_LESS 小于参考值可以通过
  GL_LEQUAL 小于或者等于可以通过
  GL_EQUAL 等于通过
  GL_GEQUAL 大于等于通过
  GL_GREATER 大于通过
  GL_NOTEQUAL 不等于通过
  ref:  参考值
    mask: 掩码值(会与参考值和模板缓冲区内的值先作与操作,在参考func中的参数测试是否通过测试)
//呵呵:来看看怎么处理你们:
void glStencilOp (GLenum fail, GLenum zfail, GLenum zpass);
  fail模板测试未通过时该如何变化;zfail表示模板测试通过,但深度测试未通过时该如何变化;zpass表示模板测试和深度测试或者未执行深度测试均通过时该如何变化
  GL_KEEP(不改变,这也是默认值)
  GL_ZERO(回零)
  GL_REPLACE(使用测试条件中的设定值来代替当前模板值)
  GL_INCR(增加1,但如果已经是最大值,则保持不变),
  GL_INCR_WRAP(增加1,但如果已经是最大值,则从零重新开始)
  GL_DECR(减少1,但如果已经是零,则保持不变),
  GL_DECR_WRAP(减少1,但如果已经是零,则重新设置为最大值)
  GL_INVERT(按位取反)
也就是说对模板缓冲区有三种操作方式:分别是:

1. 模板缓冲区测试失败了:那么执行glStencilOp中第一个参数fail的操作方式;

2.模板缓冲区测试通过了:那么执行glStencilOp中第二个参数zfail的操作方式;

3.模板缓冲区测试通过了:那么执行glStencilOp中第三个参数zpass的操作方式;

注意三者的共同点都是对模板缓冲区进行操作。

如果模板缓冲区测试失败了,那么对颜色缓冲区就不会写入任何值。利用这个特点,我们可以如下操作:

// 设置模板缓冲区测试失败,后续的绘制操作只会在模板缓冲区中进行

glStencilFunc(GL_NEVER, 0x0, 0x0);

glStencilOp(GL_INCR, GL_INCR, GL_INCR);

//绘制模板对象

draw_template_object()

//接着在非模板对象的缓冲区绘制,这样就可以把模板部分空出来,有种被模板楼空的感觉

glStencilFunc(GL_NOTEQUAL, 0x1, 0x1);

glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);

在这里我想通过这样一个例子来说明一下:

#include <math.h>

#include <iostream>

#include <assert.h>

#include <GL/glut.h>

#pragma comment(lib, "glut32.lib")

// #include <GL/glew.h>

// #pragma comment(lib, "glew32.lib")

void init()

{ glClearColor(0.0, 0.0, 1.0, 0.0);

glClearStencil(0);

glEnable(GL_STENCIL_TEST);

}

void display()

{

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

glLoadIdentity();

glTranslatef(0.0, 0.0, -20.0);

glStencilFunc(GL_ALWAYS, 0, 0x00);

//glStencilFunc(GL_NEVER, 0x0, 0x0);

//glStencilOp(GL_INCR, GL_INCR, GL_INCR);//

glColor3f(1.0f, 1.0f, 1.0f);

float dRadius = 5.0 * (sqrt(2.0) / 2.0);

glBegin(GL_LINE_STRIP);

for (float dAngel = 0; dAngel < 380.0; dAngel += 0.1)

{

glVertex2d(dRadius * cos(dAngel), dRadius * sin(dAngel));

dRadius *= 1.003;

}

glEnd();

//glStencilFunc(GL_NOTEQUAL,0x1,0x1);

//glStencilOp(GL_INCR,GL_INCR,GL_INCR);//

glColor3f(1.0f, 0.0f, 0.0f);

glRectf(-5, -5, 5, 5);

        glutSwapBuffers();

}


void reshape(int w, int h)

{

glViewport(0, 0, w, h);

float aspect = (w * 1.0) / h;

glMatrixMode(GL_PROJECTION);

glLoadIdentity();

gluPerspective(60, aspect, 1, 100);

glMatrixMode(GL_MODELVIEW);

glLoadIdentity();

}


int main(int argc, char* argv[])

{

glutInit(&argc, argv);

glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA|GLUT_STENCIL);

glutInitWindowPosition(200,200);

glutInitWindowSize(600,600);

glutCreateWindow(argv[0]);

//  assert(GLEW_NO_ERROR == glewInit());

init();

glutReshapeFunc(reshape);

glutDisplayFunc(display);

glutMainLoop();

return 0;

}

结果如下:

OpenGL: 模板缓冲区的理解 - danshiming - danshiming的博客
加入模板控制之后的结果:
#include <math.h>
#include <iostream>
#include <assert.h>
#include <GL/glut.h>
#pragma comment(lib, "glut32.lib")
// #include <GL/glew.h>
// #pragma comment(lib, "glew32.lib")

void init()
{
glClearColor(0.0, 0.0, 1.0, 0.0);
glClearStencil(0);
glEnable(GL_STENCIL_TEST);
}

void display()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);   // 1
glLoadIdentity();
glTranslatef(0.0, 0.0, -20.0);
//glStencilFunc(GL_ALWAYS, 0, 0x00);
glStencilFunc(GL_NEVER, 0x0, 0x0);           // 2
glStencilOp(GL_INCR, GL_INCR,GL_INCR);// 3
glColor3f(1.0f, 1.0f, 1.0f);
float dRadius = 5.0 * (sqrt(2.0) / 2.0);
glBegin(GL_LINE_STRIP);
for (float dAngel = 0; dAngel < 380.0; dAngel += 0.1)
{
glVertex2d(dRadius * cos(dAngel), dRadius * sin(dAngel));
dRadius *= 1.003;
}
glEnd();

glStencilFunc(GL_NOTEQUAL, 0x1, 0x1);    // 4 
glStencilOp(GL_INCR, GL_INCR, GL_INCR);// 5
glColor3f(1.0f, 0.0f, 0.0f);
glRectf(-5.0, -5.0, 5.0, 5.0);
glutSwapBuffers();
}

void reshape(int w, int h)
{
glViewport(0, 0, w, h);
float aspect = (w * 1.0) / h;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0, aspect, 1.0, 100.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}

int main(int argc, char* argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_STENCIL);
glutInitWindowPosition(200, 200);
glutInitWindowSize(600, 600);
glutCreateWindow(argv[0]);

//  assert(GLEW_NO_ERROR == glewInit());

init();
glutReshapeFunc(reshape);
glutDisplayFunc(display);
glutMainLoop();

return 0;
}
运行结果如下:
OpenGL: 模板缓冲区的理解 - danshiming - danshiming的博客
 先分析如下:
        当执行到1处,3个缓冲区都被清空
  颜色缓冲区:每个像素点颜色都是蓝色
  深度缓冲区:每个像素点深度都是1.0(注:执行 glClear后会使深度缓冲区中的值恢复成默认值1
  模板缓冲区:每个像素点模板值都是0
  执行到2,3处,模板测试条件是从不通过测试,且不通过测试结果后使模板值加1
  接着应用模板测试进行绘制一组点,由于模板测试条件是从不通过测试,所以颜色缓冲区值不会变化,
       但是绘制的点对应的像素点的模板值变为1,此时
  颜色缓冲区:每个像素点颜色都是蓝色
  深度缓冲区:每个像素点深度都是1.0
  模板缓冲区:点数组对应的模板值是1,其他区域像素点的模板值还是0
  执行到4,5处,模板测试条件是模板值不等于1则通过测试,且不通过测试结果是模板值加1
     接着应用刚才的模板测试进行绘制一个(-5,-5,5,5)的矩形,在这个矩形区域内,
       像素点的模板值分为2种,值为1的是上一步点数组中的像素点。值为0的是 上一步非点数组中的像素点。
         根据 那个模板测试条件,模板值为0的像素点通过测试,通过测试的像素点就用绘制目标 (这里指绘制的红色矩形) 的          颜色,即通过测试的像素点可以进行替换颜色缓冲区的值(替换成红色),
       模板值为1的像素点不能通过测 试,因此不能改变颜色缓冲区的值,就用颜色缓冲区中原来的颜色即蓝色。
      故:
  颜色缓冲区:(-5,-5,5,5)区域内 模板值为0的像素点为红色,其他区域都为蓝色
  深度缓冲区:每个像素点深度都是1.0
  模板缓冲区:点数组对应的模板值是1,其他区域像素点的模板值还是0

本文参考:
http://www.cnblogs.com/dragon2012/p/3757790.html
http://blog.csdn.net/csxiaoshui/article/details/23457273
http://blog.csdn.net/augusdi/article/details/20456923
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值