osgcamera例子

这个例子是一个多相机、多视口的例子,我们有机会研究一下OSG中的视口相机。
首先,程序最外面run了两次,通过EnableVBOVisitor的方式使用了定点缓冲对象,EnableVBOVisitor继


承自NodeVisitor,在accept的时候执行一次,执行NodeVisitor中的apply方法。
enum TraversalMode
        {
            TRAVERSE_NONE,
            TRAVERSE_PARENTS,
           


 TRAVERSE_ALL_CHILDREN,
            TRAVERSE_ACTIVE_CHILDREN
        };
递归的模式,不递归、向上级递归、向下级递归,递归下级所有活动的节点。
OpenGL中绘制物体的方式:glbegin,glend,顶点数组的立即模式;displaylist显示列表;VBO顶点缓冲


对象。VBO几何了前两种方法的优势,数据即可以存储在服务器端,又便于更新。
关于VBO详细的说明:http://www.cnblogs.com/azureforest/archive/2012/07/01/2572237.html
这样想一想,所有的节点的叶节点都是Geode,Geode中有多个drawable,这个drawable就应该是设置VBO


的地方,我们顺着这个思路看看drawable:
有两个函数:setUseVertexBufferObjects、setUseDisplayList
有两个变量:_useDisplayList; _useVertexBufferObjects;
在构造函数里可以看到显示列表是默认的方式,VBO是false。
特别强调,如果drawable是动态更新的,就不能用显示列表,这样不安全。
在Drawable中的draw中看看这个判断
    if (_useDisplayList && !(_supportsVertexBufferObjects && _useVertexBufferObjects && 


renderInfo.getState()->isVertexBufferObjectSupported()))


osg的默认绘制是显示列表,但是一但支持vbo并且设置了vbo的绘制方式就会有vbo绘制。
在drawable.cpp中有很多的if (!_useDisplayList) return;这样的判断,比如在


Drawable::compileGLObjects(RenderInfo& renderInfo),判断了如果不是显示列表就返回,解释一下这


是为什么?显示列表是需要提前编译的,然后再渲染,不像立即模式那样直接渲染。在osg的


databasepager中为了大数据的优化,需要提前编译一些东西,比如纹理,shader,再有就是显示列表。


在这里我们找到了源代码。
我们记者往下来,看代码drawable中的draw最后几行:
 if (_drawCallback.valid())
        _drawCallback->drawImplementation(renderInfo,this);
    


else
        drawImplementation(renderInfo);如果不使用显示列表就会执行。
这里透露出好多信息,首先(包括显示列表模式),如果自己定义了DrawCallback,重写


drawImplementation就会实现自己的绘制内容,否则执行drawable的drawImplementation,而drawable的


drawImplementation是一个纯虚方法,因此每个继承drawable的类需要重写这个函数完成绘制。
以Geometry为例,在Geometry的drawImplementation完成了几何体的绘制,在参数renderInfo中存储了渲


染的信息。在drawImplementation中有一个areFastPathsUsed()函数,用于判断使用OpenGL的顶点数组还


是普通的glbegin,glend函数,在使用顶点数组中还会继续判断是否使用顶点缓冲对象。
离题太远了,我们回到例子中。
EnableVBOVisitor重写了 void apply(osg::Geode& geode),为每个drawable设置使用定点缓冲对象。
接下来设置了线程模式,OSG中有四种线程模式:
SingleThreaded:单线程模型。OSG不会创建任何新线程来完成场景的筛选和渲染,因
而也不会对渲染效率的提高有任何助益。它适合任何配置下使用。 
CullDrawThreadPerContext:OSG 将为每一个图形设备上下文(GraphicsContext)创建
一个图形线程,以实现并行的渲染工作。如果有多个 CPU 的话,那么系统将尝试把线程分
别放在不同的 CPU上运行,不过每一帧结束前都会强制同步所有的线程。 
DrawThreadPerContext:这一线程模型同样会为每个 GraphicsContext 创建线程,并分配
到不同的 CPU 上。十分值得注意的是,这种模式会在当前帧的所有线程完成工作之前,开
始下一帧。 
CullThreadPerCameraDrawThreadPerContext:这一线程模型将为每个 GraphicsContext
和每个摄像机创建线程,这种模式同样不会等待前一次的渲染结束,而是返回仿真循环并再
次开始执行 frame 函数。如果您使用四核甚至更高的系统配置,那么使用这一线程模型将最
大限度地发挥多 CPU的处理能力。 (《最长的一帧》)
osgViewer::Viewer 通过setThreadingModel可以设置线程模式。
之后,执行了两次viewer::run()
看看AnimationPathManipulator这个操作器,运动路径操作器,里面有一个AnimationPath,


AnimationPath我们之前研究过,定义了一个路径,中间的点进行插值,这里读取了一个path文件。
这里说一下CompositeViewer、Viewer、Scene、Camera、GraphicsContext的关系:一个CompositeViewer


可以有多个Viewer,一个Viewer对应一个主相机和多个从属Camera,一个Camera对应一个


GraphicsContext,一个Viewer对应一个SceneView,一个SceneView中有一个Databasepager。
singleWindowMultipleCameras中建立了一个单视口,定义了两个相机。
    osg::GraphicsContext::WindowingSystemInterface* wsi = 


osg::GraphicsContext::getWindowingSystemInterface();


这个函数用于判断当前图形窗体是否可用,WindowingSystemInterface是osg中的结构体,具体的实现却


在osgViewer中,根据不同的操作系统有不同的类实现类,windows中对应的是GraphicsWindowWin32.cpp


,这个类的产生在cmake阶段,里面封装了windows的建立窗体、消息循环、产生事件等等。
产生窗体的玄机在:
struct RegisterWindowingSystemInterfaceProxy
{
    RegisterWindowingSystemInterfaceProxy()
    


{
        osg::GraphicsContext::setWindowingSystemInterface


(Win32WindowingSystem::getInterface());
    }


    ~RegisterWindowingSystemInterfaceProxy()
    


{
        if (osg::Referenced::getDeleteHandler())
        {
            


osg::Referenced::getDeleteHandler()->setNumFramesToRetainObjects(0);
            


osg::Referenced::getDeleteHandler()->flushAll();
        }


        


osg::GraphicsContext::setWindowingSystemInterface(0);
    }
};


static 


RegisterWindowingSystemInterfaceProxy createWindowingSystemInterfaceProxy;


}
这里面,看看这有个static,当你用osgViewer::Viewer viewer;的时候就调用了


static 


RegisterWindowingSystemInterfaceProxy createWindowingSystemInterfaceProxy;然后调用


osg::GraphicsContext::setWindowingSystemInterface(Win32WindowingSystem::getInterface());
获取了图形显示窗体,这里我们就先说到这里。
multipleWindowMultipleCameras创建多窗体多相机。
接下来从一个文件中读取窗体设置,读出窗体设置。
ModelHandler继承自GUIEventHandler,通过键盘事件在场景中加载不同的模型。
例子的最后:
viewer.realize();


    unsigned int numFrames = 0;
    while(!viewer.done() && !


(limitNumberOfFrames && numFrames>=maxFrames))
    {
        viewer.frame();
        +


+numFrames;
    }
控制程序的运行,如果需要自己控制OSG的帧数,或者获取一些统计的信息,可以像这样写。

版权声明:本文为yungis原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。