osgAtomicCounter主要向我们演示了怎么使用OpenGL 4.2引入的新扩展GL_ARB_shader_atomic_counters, Atomic Counter的介绍可以参考另一篇博客的介绍:OpenGL缓冲区对象之Atomic Counter Object
代码中首先定义了一个osg::Camera::DrawCallback,它的作用是在每帧渲染完成之后记录这一帧总共绘制了多少个像素(也就是调用了多少次Fragment Shader),通过我们在Shader中的Atomic Counter变量进行统计调用的次数
virtual void operator () (osg::RenderInfo& renderInfo) const { _acbb->readData(*renderInfo.getState(), *_atomicCounterArray); unsigned int numPixel = osg::maximum(1u, _atomicCounterArray->front()); if ((renderInfo.getView()->getFrameStamp()->getFrameNumber() % 10) == 0) { OSG_INFO << "osgatomiccounter : draw " << numPixel << " pixels." << std::endl; } _invNumPixelUniform->set( 1.0f / static_cast<float>(numPixel) ); }
ResetAtomicCounter的作用是让蓝色成分中的数据失效,也就是说蓝色成分的Atomic Buffer缓冲区仅仅负责记录像素点的数量,但是不能在绘制中用到它,否则场景就会是从黑色渐变到白色了,而不是从淡黄色到黄色。也就是让蓝色值成分始终为0
接下来就是main函数部分:
设置操作器和添加EventHandler的部分很简单,主要需要解释的部分是设置Atomic Counter Buffer的地方,参考下面的注释:
//获取节点状态,将Shader添加其中 osg::StateSet * ss = loadedModel->asGeode()->getDrawable(0)->getOrCreateStateSet(); ss->setAttributeAndModes( createProgram(), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED ); ss = loadedModel->getOrCreateStateSet(); //设置缓冲区对象存储空间初值 osg::ref_ptr<osg::UIntArray> atomicCounterArrayRedAndGreen = new osg::UIntArray; atomicCounterArrayRedAndGreen->push_back(0); atomicCounterArrayRedAndGreen->push_back(0); osg::ref_ptr<osg::UIntArray> atomicCounterArrayBlue = new osg::UIntArray; atomicCounterArrayBlue->push_back(0); //设置缓冲区对象及其使用方式 osg::ref_ptr<osg::AtomicCounterBufferObject> acboRedAndGreen = new osg::AtomicCounterBufferObject; acboRedAndGreen->setUsage(GL_STREAM_COPY); atomicCounterArrayRedAndGreen->setBufferObject(acboRedAndGreen.get()); osg::ref_ptr<osg::AtomicCounterBufferObject> acboBlue = new osg::AtomicCounterBufferObject; acboBlue->setUsage(GL_STREAM_COPY); atomicCounterArrayBlue->setBufferObject(acboBlue.get()); //设置缓冲区对象绑定的位置(与Shader中layout中的bindingpoint一致) osg::ref_ptr<osg::AtomicCounterBufferBinding> acbbRedAndGreen = new osg::AtomicCounterBufferBinding(0, acboRedAndGreen.get(), 0, sizeof(GLuint)*3); ss->setAttributeAndModes(acbbRedAndGreen.get()); osg::ref_ptr<osg::AtomicCounterBufferBinding> acbbBlue = new osg::AtomicCounterBufferBinding(2, acboBlue.get(), 0, sizeof(GLuint)); ss->setAttributeAndModes(acbbBlue.get()); //使缓冲区中的数据失效,让程序重新加载 acbbRedAndGreen->setUpdateCallback(new ResetAtomicCounter); acbbBlue->setUpdateCallback(new ResetAtomicCounter); //重新设置绘制的像素点数量 osg::ref_ptr<osg::Uniform> invNumPixelUniform = new osg::Uniform("invNumPixel", 1.0f/(800.0f*600.0f)); ss->addUniform( invNumPixelUniform.get() ); AdaptNumPixelUniform * drawCallback = new AdaptNumPixelUniform; drawCallback->_invNumPixelUniform = invNumPixelUniform; drawCallback->_acbb = acbbBlue; viewer.getCamera()->setFinalDrawCallback(drawCallback);