剛剛入門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
先看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/...
未完 待續。。。