OSG:从源码看Viewer::run() 一

刚刚入门OSG不久,一直弄不清楚它到底是如何显示一副图片的,简单从源码看下。
:所用OSG的版本为3.4 release版!

1、前言

在OSG程序中,简单展示一副图片用:

    osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer;
    osg::ref_ptr<osg::Node> node = osgDB::readNodeFile("glider.osg");
    viewer->setSceneData(node);
    return viewer->run();

然后在我们的计算机显示器(屏幕中心)上就会展现滑翔机的图片,并且移动鼠标、滚轮等设备还能实现对该滑翔机的旋转、缩放、平移等一系列的操作。在OpenGL中我们知道,要实现对模型的旋转缩放等功能,需要设置相机的各种参数(相机位恣,旋转角度、平移步长、转动速率等等)。osg中简简单单的几行代码,就实现了如此之多的功能,不禁要问:run()函数里边到底发生了什么。

2、第一步

打开OSG的源码,在Viewer.cpp文件中找到Viewer::run()函数的定义:

int Viewer::run()
{
    if (!getCameraManipulator() && getCamera()->getAllowEventFocus())
    {
        setCameraManipulator(new osgGA::TrackballManipulator());
    }

    setReleaseContextAtEndOfFrameHint(false);

    return ViewerBase::run();
}

可见,将一副图片的节点读入osg的场景中后,在场景的run中首先会判断该场景中有没有漫游器(getCameraManipulator返回一个osgGA::CameraManipulator),如果该场景中不存在漫游器,则调用函数setCameraManipulator创建一个跟踪球 TrackballManipulator的场景漫游器。关键来看默认的漫游器osgGA::TrackballManipulator()做了什么!

2.1 默认漫游器

先看osgGA::TrackballManipulator()的默认构造函数:

TrackballManipulator::TrackballManipulator( int flags )
   : inherited( flags )
{
    setVerticalAxisFixed( false );
}

将该类当做参数传递给了setCameraManipulator,重点来看setCameraManipulator干了什么,源码:

void View::setCameraManipulator(osgGA::CameraManipulator* manipulator, bool resetPosition)
{
    _cameraManipulator = manipulator;

    if (_cameraManipulator.valid())
    {
        _cameraManipulator->setCoordinateFrameCallback(new ViewerCoordinateFrameCallback(this));

        if (getSceneData()) _cameraManipulator->setNode(getSceneData());

        if (resetPosition)
        {
            osg::ref_ptr<osgGA::GUIEventAdapter> dummyEvent = _eventQueue->createEvent();
            _cameraManipulator->home(*dummyEvent, *this);
        }
    }
}

可以看出,该函数主要设置了当前场景的主相机的动作,设置了当前场景节点的坐标系以及场景中的数据,同时通过设置home--漫游器初始位置。
紧接着通过setReleaseContextAtEndOfFrameHint()设置了渲染场景的上下文关系。

3、再看 ViewerBase::run()

源码:

int ViewerBase::run()
{
    if (!isRealized())
    {
        realize();
    }

    const char* run_frame_count_str = getenv("OSG_RUN_FRAME_COUNT"); //getenv()从环境变量中去字符串
    unsigned int runTillFrameNumber = run_frame_count_str==0 ? osg::UNINITIALIZED_FRAME_NUMBER : atoi(run_frame_count_str);

    while(!done() && (run_frame_count_str==0 || getViewerFrameStamp()->getFrameNumber()<runTillFrameNumber))
    {
        double minFrameTime = _runMaxFrameRate>0.0 ? 1.0/_runMaxFrameRate : 0.0;
        osg::Timer_t startFrameTick = osg::Timer::instance()->tick();
        if (_runFrameScheme==ON_DEMAND)
        {
            if (checkNeedToDoFrame())
            {
                frame();
            }
            else
            {
                // we don't need to render a frame but we don't want to spin the run loop so make sure the minimum
                // loop time is 1/100th of second, if not otherwise set, so enabling the frame microSleep below to
                // avoid consume excessive CPU resources.
                if (minFrameTime==0.0) minFrameTime=0.01;
            }
        }
        else
        {
            frame();
        }

        // work out if we need to force a sleep to hold back the frame rate
        osg::Timer_t endFrameTick = osg::Timer::instance()->tick();
        double frameTime = osg::Timer::instance()->delta_s(startFrameTick, endFrameTick);
        if (frameTime < minFrameTime) OpenThreads::Thread::microSleep(static_cast<unsigned int>(1000000.0*(minFrameTime-frameTime)));
    }

    return 0;
}

在该函数中,实现了每一帧的渲染、计算帧率等。
frame()中:

void ViewerBase::frame(double simulationTime)
{
    if (_done) return;

    // OSG_NOTICE<<std::endl<<"CompositeViewer::frame()"<<std::endl<<std::endl;

    if (_firstFrame)
    {
        viewerInit();

        if (!isRealized())
        {
            realize();
        }

        _firstFrame = false;
    }
    advance(simulationTime);

    eventTraversal();
    updateTraversal();
    renderingTraversals();
}

可见,在osg的每一帧的绘制中,实现了对事件的遍历(eventTraversal())、更新( updateTraversal())和渲染(renderingTraversals()),同时这也是漫游器真正被添加进来起作用的地方。至于每一帧中到底如何处理事件的(eventTraversal()函数作用),可参看源码文件Viewer.cpp中void Viewer::eventTraversal()的具体定义。

主要参考文章:http://blog.csdn.net/csxiaosh...
http://blog.csdn.net/popy007/...

未完 待续。。。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值