OSG:從源碼看Viewer::run() 一

剛剛入門OSG不久,一直弄不清楚它究竟是如何顯示一副圖片的,簡單從源碼看下。
:所用OSG的版本爲3.4 release版!node

一、前言

在OSG程序中,簡單展現一副圖片用:ide

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()函數裏邊到底發生了什麼。函數

二、第一步

打開OSG的源碼,在Viewer.cpp文件中找到Viewer::run()函數的定義:oop

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()作了什麼!ui

2.1 默認漫遊器

先看osgGA::TrackballManipulator()的默認構造函數:this

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

將該類當作參數傳遞給了setCameraManipulator,重點來看setCameraManipulator幹了什麼,源碼:.net

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()設置了渲染場景的上下文關係。code

三、再看 ViewerBase::run()

源碼:blog

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/...

未完 待續。。。

相關文章
相關標籤/搜索