void ViewerBase::frame(doublesimulationTime)
{if (_done) return;//OSG_NOTICE<<:endl>
if(_firstFrame)
{
viewerInit();if (!isRealized())
{
realize();
}
_firstFrame= false;
}
advance(simulationTime);
eventTraversal();
updateTraversal();
renderingTraversals();
}
当前位置:osgViewer/Viewer.cpp 第 643行,osgViewer:: Viewer::advance()
好的,现在我们终于正式进入仿真循环当中了,之前的 realize 函数虽然十分重要,但它实际上是循环运行前的准备工作。而从这一日开始介绍的 advance,eventTraversal,updateTraversal 和 renderingTraversals 函数,才是真正的一帧的组成部分。
advance 函数的工作内容如下:
1、获取上一次记录的参考时间(Reference Time);
2、根据当前时刻,重新记录参考时间,并因此得到两次记录之间的差值,即一帧经历的时间;
3、记录已经经过的帧数;
4、有的时候我们需要将帧速率,参考时间等内容予以记录并显示给用户,此时需要通过 ViewerBase::getStats 函数获得 osg::Stats 对象,用以进行帧状态的保存和显示;
5、如果需要的话,使用 Referenced::getDeleteHandler()来处理 osg::Referenced 对象被弃用之后的删除工作。
仿真循环运行的参考时间,总时间和总帧数都是由 osg::FrameStamp 变量_frameStamp来处理的,如果用户程序需要获取这些信息的话,也可以通过读取这个变量的成员函数来实现。当然,使用 Viewer 中的 osg::Stats 变量_stats 也是可以的,缺省情况下,这个变量会忠实地记录当前帧以及之前的 24 帧的每帧用时,事件遍历用时,更新遍历用时,以及渲染遍历用时信息。如果我们想获得更多的历史数据,抑或对于频繁的记录操作感到厌烦,可以在开始仿真循环之前执行 ViewerBase::setStats 函数,重新设置这个记录器的参数,或者简单地将其置为 NULL。
void Viewer::advance(doublesimulationTime)
{if (_done) return;double previousReferenceTime = _frameStamp->getReferenceTime();
unsignedint previousFrameNumber = _frameStamp->getFrameNumber();
_frameStamp->setFrameNumber(_frameStamp->getFrameNumber()+1);
_frameStamp->setReferenceTime( osg::Timer::instance()->delta_s(_startTick, osg::Timer::instance()->tick()) );if (simulationTime==USE_REFERENCE_TIME)
{
_frameStamp->setSimulationTime(_frameStamp->getReferenceTime());
}else{
_frameStamp->setSimulationTime(simulationTime);
}if (getViewerStats() && getViewerStats()->collectStats("frame_rate"))
{//update previous frame stats
double deltaFrameTime = _frameStamp->getReferenceTime() -previousReferenceTime;
getViewerStats()->setAttribute(previousFrameNumber, "Frame duration", deltaFrameTime);
getViewerStats()->setAttribute(previousFrameNumber, "Frame rate", 1.0/deltaFrameTime);//update current frames stats
getViewerStats()->setAttribute(_frameStamp->getFrameNumber(), "Reference time", _frameStamp->getReferenceTime());
}
//简单说来,它的工作是收集所有已经弃用的 OSG 场景对象,并在需要的时候(例如advance 函数代码的相应部分)执行 os