-
简介
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) );
}
接下来是两段Shader的代码,可以参考上文中提到的博文,Shader十分简单,主要是通过颜色成分来给每一个像素染色,结合上面提到的invNumPixel,可以让先绘制的像素颜色较淡,随着计数器越来越大,得到的颜色也越来越深。
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);