为了方便可以在一个命令中清除多个缓冲区(使用|操作符)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
了解模板缓冲区的原理,下面我们看看在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);
glClearStencil(0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glEnable(GL_STENCIL_TEST); glStencilFunc(GL_NEVER, 0x0, 0x0); glStencilOp(GL_INCR, GL_INCR, GL_INCR); glColor3f(1.0f, 1.0f, 1.0f); GLdouble dRadius = 1.0; //在模板缓冲区绘制(因为模板测试失败不能在颜色缓冲区写入) glBegin(GL_LINE_STRIP); for (double angle = 0.0; angle < 400.0; angle += 0.1) { glVertex3d(dRadius * cos(angle), dRadius * sin(angle), 0.0); dRadius *= 1.002; } glEnd(); //现在与颜色缓冲区在模板缓冲区对应处有线的地方不会绘制 glStencilFunc(GL_NOTEQUAL, 0x1, 0x1); glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); glColor3f(0.0, 1.0, 1.0); glRectf(x, y, x+_rectSize, y-_rectSize);运行的结果如下图所示:
这个颜色缓冲区中的矩形的一部分(条纹线)并没有被绘制,因为这部分对应到Stencil Buffer里面的值是1,而值等于1的地方不会通过模板缓冲区测试(因此并不会在颜色缓冲区中被绘制出来)
下面我们看看在osg中怎么实现同样的效果:
osg::Geometry *lineStripGeometry = new osg::Geometry; osg::Vec3Array *lineVertexArray = new osg::Vec3Array; double dRadius = 0.1; for (float angle = 0.0; angle < 400.0; angle += 0.1) { lineVertexArray->push_back(osg::Vec3(dRadius * cos(angle), dRadius * sin(angle), 0)); dRadius *= 1.002; } osg::Vec4Array *lineColorArray = new osg::Vec4Array; lineColorArray->push_back(osg::Vec4(1.0, 1.0, 1.0, 1.0)); lineStripGeometry->setVertexArray(lineVertexArray); lineStripGeometry->setColorArray(lineColorArray); //OSG 3.2之后的版本在setColorArray中设置绑定方式 lineStripGeometry->setColorBinding(osg::Geometry::BIND_OVERALL); lineStripGeometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINE_STRIP, 0, lineVertexArray->size())); lineStripGeometry->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF); //添加模板测试 osg::Stencil *lineStripStencil = new osg::Stencil; lineStripStencil->setFunction(osg::Stencil::NEVER, 0x0, 0x0); lineStripStencil->setOperation(osg::Stencil::INCR, osg::Stencil::INCR, osg::Stencil::INCR); lineStripGeometry->getOrCreateStateSet()->setAttributeAndModes(lineStripStencil); ////////////////////////////////////////////////////////////////////////// osg::Geometry *quadGeometry = new osg::Geometry; osg::Vec3Array *quadVertexArray = new osg::Vec3Array; quadVertexArray->push_back(osg::Vec3(0, 0, 0)); quadVertexArray->push_back(osg::Vec3(25, 0, 0)); quadVertexArray->push_back(osg::Vec3(25, 25, 0)); quadVertexArray->push_back(osg::Vec3(0, 25, 0)); osg::Vec4Array *quadColorArray = new osg::Vec4Array; quadColorArray->push_back(osg::Vec4(0.0, 1.0, 1.0, 1.0)); quadGeometry->setVertexArray(quadVertexArray); quadGeometry->setColorArray(quadColorArray); quadGeometry->setColorBinding(osg::Geometry::BIND_OVERALL); quadGeometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS, 0, 4)); quadGeometry->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF); osg::Stencil *quadStencil = new osg::Stencil; quadStencil->setFunction(osg::Stencil::NOTEQUAL, 0x1, 0x1); quadStencil->setOperation(osg::Stencil::KEEP, osg::Stencil::KEEP, osg::Stencil::KEEP); quadGeometry->getOrCreateStateSet()->setAttributeAndModes(quadStencil); osg::Geode *geode = new osg::Geode; geode->addDrawable(lineStripGeometry); geode->addDrawable(quadGeometry);
本文参考文章: