osgUtil.StateToCompile是一个用于生成OpenGL显示列表的OpenSceneGraph的工具类。
StateToCompile将给定的场景图输出到OpenGL显示列表中。显示列表是一种在渲染时优化性能的机制,其将渲染指令预编译并保存到显存中,以便在需要渲染时检索和执行。
StateToCompile基于Visitor设计模式,你需要向其提供一个用于处理每个节点的Visitor对象。例如,你可以创建一个继承自osg::NodeVisitor的类,并重写其apply(osg::Geode&)方法:
class CompileVisitor : public osg::NodeVisitor
{
public:
    void apply(osg::Geode& geode) override
    {
        if (_compileStateset.get())
        {
            geode.setStateSet(_compileStateset);
            glNewList(_listId, GL_COMPILE);
            for (unsigned int i = 0; i < geode.getNumDrawables(); ++i)
            {
                osg::Drawable* drawable = geode.getDrawable(i);
                if (drawable)
                {
                    drawable->drawImplementation(getRenderInfo());
                }
            }
            glEndList();
        }
        traverse(geode);
    }
    void setCompileStateset(osg::StateSet* stateset)
    {
        _compileStateset = stateset;
    }
    GLuint getListId() const
    {
        return _listId;
    }
protected:
    osg::ref_ptr<osg::StateSet> _compileStateset;
    GLuint _listId = 0;
};
在这个例子中,我们向StateToCompile提供了一个Visitor对象,该Visitor会将所有的Drawable绘制命令收集到一个OpenGL显示列表中。
下面是一份使用StateToCompile的简单示例代码:
#include <osgViewer/Viewer>
#include <osg/Geode>
#include <osg/ShapeDrawable>
#include <osgUtil/StateToCompile>
osg::ref_ptr<osg::Group> createSceneGraph()
{
    auto group = new osg::Group();
    auto shape = new osg::Box(osg::Vec3(0, 0, 0), 1.0);
    auto drawable = new osg::ShapeDrawable(shape);
    auto geode = new osg::Geode();
    geode->addDrawable(drawable);
    group->addChild(geode);
    return group;
}
int main(int argc, char** argv)
{
    osg::ref_ptr<osg::Group> root = createSceneGraph();
    osgUtil::StateToCompile stateToCompile;
    CompileVisitor compileVisitor;
    compileVisitor.setCompileStateset(root->getOrCreateStateSet());
    stateToCompile.setVisitor(&compileVisitor);
    stateToCompile.compileGraph(*root);
    GLuint listId = compileVisitor.getListId();
    osgViewer::Viewer viewer;
    viewer.setSceneData(root);
    viewer.realize();
    while (!viewer.done())
    {
        glCallList(listId);
        viewer.frame();
    }
    return 0;
}