OpenGL.Stencil Buffer
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
比如:绘制一个墙壁 墙壁的某些块启动alpha ,然后再墙壁上绘制聚光灯:
首先把整块墙壁的Steccil Buffer清为0,接下来画墙壁时,GPU把墙壁所占据的像素Stencil值更新为1,最后在画聚光灯,会设置Stencil测试条件,只允许GPU去更新画面上像素Stencil 值为1的点,也就是墙壁所占据的点
模板缓存的启用:
为了使用模板缓存红能,我们必须向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
比如:绘制一个墙壁 墙壁的某些块启动alpha ,然后再墙壁上绘制聚光灯:
首先把整块墙壁的Steccil Buffer清为0,接下来画墙壁时,GPU把墙壁所占据的像素Stencil值更新为1,最后在画聚光灯,会设置Stencil测试条件,只允许GPU去更新画面上像素Stencil 值为1的点,也就是墙壁所占据的点
1
glClearStencil(
0
);
//
默认值是0 可省略
2 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)
3 glDiable(GL_DEPTH_BIT); // 不需要ZBuffer Test
4
5 glMatrixMode(GL_MODEVIEW);
6 glLoadIdentity();
7 glMatrixMode(GL_PROJECTION);
8 glPushMatrix(); // 把Projection矩阵放在stack中
9 glLoadIdentity();
10
11 glEnable(GL_ALPHA_TEST);
12 glAlphaFunc(GL_GREATER, 0.5 );
13 if ( g_bStencil )
14 {
15 // `启动` Stencil Buffer Test
16 glEnable(GL_STENCIL_TEST);
17 // `Stencil Test 判断条件设置成永远成立`
18 // `Stencil 参考值设置为 1`
19 // `Stencil Mask 设置成 0xff = 255`
20 glStencilFunc(GL_ALWAYS, 1, 0xff);
21 // `Stencil Test 成立时, 把 Stencil 参考值填入 Stencil Buffer 中.`
22 // `前两个 GL_KEEP 是指当 Stencil 和 ZBuffer Test 不成立时, 不去改变 Stencil Buffer`
23 glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
24 }
25 else
26 {
27 glDisable(GL_STENCIL_TEST);
28 }
29
30 画出矩形, 同时会清除ZBuffer.`
31
32 // `把存放在stack中的projection取回来`
33 glPopMatrix();
34 glDepthFunc(GL_LESS);
35 glDisable(GL_ALPHA_TEST);
36 }
37
38 {
39 if ( g_bStencil )
40 {
41 // `只更新画面上Stencil值为1的像素`
42 glStencilFunc(GL_EQUAL, 1, 0xff);
43 // `不去更新 Stencil Buffer 数值`
44 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
45 }
46
47 // `打开混合功能`
48 glEnable(GL_BLEND);
49 // `混合公式` = source_color * 1 + dest_color * 1
50 glBlendFunc(GL_ONE, GL_ONE);
51
52 画出矩形`
53 // `关闭混合功能`
54 glDisable(GL_BLEND);
55 }
56 GutSwapBuffersOpenGL();
2 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)
3 glDiable(GL_DEPTH_BIT); // 不需要ZBuffer Test
4
5 glMatrixMode(GL_MODEVIEW);
6 glLoadIdentity();
7 glMatrixMode(GL_PROJECTION);
8 glPushMatrix(); // 把Projection矩阵放在stack中
9 glLoadIdentity();
10
11 glEnable(GL_ALPHA_TEST);
12 glAlphaFunc(GL_GREATER, 0.5 );
13 if ( g_bStencil )
14 {
15 // `启动` Stencil Buffer Test
16 glEnable(GL_STENCIL_TEST);
17 // `Stencil Test 判断条件设置成永远成立`
18 // `Stencil 参考值设置为 1`
19 // `Stencil Mask 设置成 0xff = 255`
20 glStencilFunc(GL_ALWAYS, 1, 0xff);
21 // `Stencil Test 成立时, 把 Stencil 参考值填入 Stencil Buffer 中.`
22 // `前两个 GL_KEEP 是指当 Stencil 和 ZBuffer Test 不成立时, 不去改变 Stencil Buffer`
23 glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
24 }
25 else
26 {
27 glDisable(GL_STENCIL_TEST);
28 }
29
30 画出矩形, 同时会清除ZBuffer.`
31
32 // `把存放在stack中的projection取回来`
33 glPopMatrix();
34 glDepthFunc(GL_LESS);
35 glDisable(GL_ALPHA_TEST);
36 }
37
38 {
39 if ( g_bStencil )
40 {
41 // `只更新画面上Stencil值为1的像素`
42 glStencilFunc(GL_EQUAL, 1, 0xff);
43 // `不去更新 Stencil Buffer 数值`
44 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
45 }
46
47 // `打开混合功能`
48 glEnable(GL_BLEND);
49 // `混合公式` = source_color * 1 + dest_color * 1
50 glBlendFunc(GL_ONE, GL_ONE);
51
52 画出矩形`
53 // `关闭混合功能`
54 glDisable(GL_BLEND);
55 }
56 GutSwapBuffersOpenGL();