刚刚入门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/...
未完 待续。。。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。