osg示例解析之osgatomiccounter(1)

  • 简介

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);

你可能感兴趣的:(Examples,OSG)