分享

OpenGL.Stencil Buffer

 勤奋不止 2013-11-21
   3D绘图的画面内存FrameBuffer,除了要记录每个像素的颜色信息外,还要存储每个像素的Z值来做ZBuffer Test  隐藏面消除,除此以外还要分配一块Stencil Buffer 空间来记录Stencil 值。 模板缓存对应记录了帧缓存中每个像素的模板值,利用它可以将绘图区域限制在屏幕的某些部分,我们可以通过模板缓存来绘制透过汽车挡风玻璃观看车外景物的画面 ,首先,将挡风玻璃的形状存储在模板缓存中去,然后再绘制整个场景,这样,模板缓存挡住了通过挡风玻璃看不见的任何东西,而车内的仪表以及其他物品只需绘制一次,而随着车的移动,只有外面的场景在不断的更改。

模板缓存的启用:
为了使用模板缓存红能,我们必须向OpenGL请求一个模板缓冲区,一般为ZBuffer除了24bit外的那8bit,glutInitDisplayMode(GLUT_RGB|GLUT_DOUBLE|GLUT_STENCIL);
glEnable(GL_STENCIL_TEST);启用
glDisable(GL_STENCIL_TEST);禁止

设置、清除模板缓存区:
在进行模板测试之前,要指定写入模板缓存区的清除值,通过函数glClearStencil()来完成,
glClearStencil(GLuint value); vlaue用于设置模板缓冲区的模板值

在绘图之前,要确保模板缓存区被清除
glClear(GL_STENCIL_BUFFERBIT);
该函数用glClearStencil(GLuint value); 中的value值来清除模板缓冲区,如果没有指定该值,默认为0;

如果要对模板缓冲区进行屏蔽,OpenGL在将数据写入缓冲区前要对数据进行屏蔽,即将要写入的数据与屏蔽值进行按位与,使用这种方法来提高图形的消隐质量,要允许所有的数据位写入模板缓冲区,使用函数:
glStencilMask(GLuint mask);
其中mask是一个控制向模板平面单个字位写入的位屏蔽,初始时所有的屏蔽位均为1,即可写 ,mask可以设置为-1~0xFFFFFFFF

模板测试:
模板测试吧存储在模板缓冲区的像素值与参考值相比较,根据比较结果,修改模板缓冲区的值,因此,模板测试操作只在有模板缓冲区的时候才发生,若没有模板缓冲区,则当前图元总是通过测试,函数glStencilFunc()函数选择比较函数的参考值,运用glStencilOp() 函数修改模板缓冲区数值的方式。
void glStencilFunc(GLenum func, GLuint ref, gluint mask);
函数设置用于模板测试的比较函数,参考值与屏蔽值,
其中func用来设置模板测试中使用的比较函数,可以去》 > = < 《 != 总是通过 从不通过,
ref 为模板测试的参考值,取值为0~2n-1 n为模板缓冲区位平面的数目
mask为屏蔽值
默认情况下 func 为GL_ALWAYS, ref 为0,mask为1
在设置Stencil Test测试条件时,Stencil 参考值放在不等式左边,Stencil Buffer中的数值则放在不等式的右边。StencilFunc设置指的是不等式中的操作符,所能使用的选择与alpha test 和zbuffer test使用的选择一样 StencilRef op StencilBuffer

void glStencilOp(GLenum sfail, GLenum zfail, GLenum zpass);
该函数根据比较结果设置修改模板缓存区数值得方式
sfail:当蒙版测试失败时所执行的操作
zfail:当蒙版测试通过,深度测试失败时所执行的操作
zpass:当蒙版测试通过,深度测试通过时所执行的操作
默认时:三个模板操作均为GL_KEEP
GL_KEEP         保持当前模板的缓冲值
GL_ZERO        把当前的模板缓冲值设置为0
GL_REPLACE   用glStencilFunc函数所指定的参考值替换模板缓冲参考值
GL_INCR         增加当前的模板缓冲区值,但限制在允许的范围内
GL_DECR        减少...
GL_INVERT    将当前模板缓冲区的值进行逐位反转

是用Stencil Buffer Test时第一步就是要更新Stencil Buffer的值,第二步再进行Stencil Buffer Test

模板测试实例:

我们绘制这样一个场景:一个球摆放在一面镜子的前面,观察者只能观察到球在镜子里面的一部分。

我们通过模板测试实现这一功能。对镜子所在的部分模板值设置为1,其他部分为0.在绘制球在镜子中的像时,启用模板测试,便可以得到这一效果。

完整代码:

  1. //#include <GL/freeglut.h>  
  2. #include <GL/glut.h>  
  3.   
  4. //全局变量设置  
  5. GLfloat LightPos[] = {5.0f,5.0f,0.0f,1.0f};  
  6. GLfloat LightAmbient[] = {0.0f,0.0f,1.0f,1.0f};  
  7.   
  8. void init()  
  9. {  
  10.     glClearColor(0.0,0.0,0.0,0.0);  
  11.     glShadeModel(GL_SMOOTH);  
  12. }  
  13.   
  14. //绘制球体的函数  
  15. void drawSphere()  
  16. {  
  17.     //光源设置  
  18.     glEnable(GL_LIGHT0);  
  19.     glEnable(GL_LIGHTING);  
  20.   
  21.     glLightfv(GL_LIGHT0,GL_POSITION,LightPos);  
  22.     glLightfv(GL_LIGHT0,GL_AMBIENT,LightAmbient);  
  23.   
  24.     glColor3f(1,0,0);  
  25.     glPushMatrix();  
  26.         glTranslatef(0,0,2);  
  27.         glutSolidSphere(0.5,20,20);  
  28.     glPopMatrix();  
  29. }  
  30.   
  31. void display()  
  32. {  
  33.     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);  
  34.   
  35.     //设置观察点  
  36.     glMatrixMode(GL_PROJECTION);  
  37.     glLoadIdentity();  
  38.     gluPerspective(60,1,5,25);  
  39.     glMatrixMode(GL_MODELVIEW);  
  40.     glLoadIdentity();  
  41.     gluLookAt(5,0,6,0,0,0,0,1,0);  
  42.   
  43.     glEnable(GL_DEPTH_TEST);  
  44.     glDisable(GL_STENCIL_TEST);  
  45.     drawSphere();  
  46.   
  47.     glClearStencil(0x0);  
  48.     glClear(GL_STENCIL_BUFFER_BIT);  
  49.     glStencilFunc(GL_ALWAYS,1,0xFF);  
  50.     glStencilOp(GL_KEEP,GL_KEEP,GL_REPLACE);  
  51.     glEnable(GL_STENCIL_TEST);  
  52.   
  53.     glDisable(GL_LIGHTING);  
  54.     glColor3f(0.5f,0.5f,0.5f);  
  55.     glDepthMask(GL_FALSE);//设置深度缓冲区为只读  
  56.     glRectf(-1.5f,-1.5f,1.5f,1.5f);  
  57.   
  58.     glDepthMask(GL_TRUE);//重新启用深度缓冲区  
  59.   
  60.     glStencilFunc(GL_EQUAL,1,0xFF);  
  61.     glStencilOp(GL_KEEP,GL_KEEP,GL_REPLACE);  
  62.     glScalef(1.0f,1.0f,-1.0f);  
  63.     drawSphere();  
  64.   
  65.     glutSwapBuffers();  
  66. }  
  67.   
  68. int main(int argc,char** argv)  
  69. {  
  70.     glutInit(&argc,argv);  
  71.     glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_STENCIL | GLUT_DEPTH);  
  72.     glutInitWindowSize(400,400);  
  73.     glutInitWindowPosition(100,100);  
  74.     glutCreateWindow("Stencil Test");  
  75.     init();  
  76.     glutDisplayFunc(display);  
  77.     //glutReshapeFunc(reshape);  
  78.     //glutKeyboardFunc(keyboard);  
  79.     glutMainLoop();  
  80.     return 0;  
  81. }  

运行效果:




    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多