探索未知种族之osg类生物---呼吸分解之更新循环二
_scene->updateSceneGraph(*_updateVisitor);
我们用了前面4节才刚刚算是完成对DatabasePager::DatabaseThread::run()函数的探究,也就是了解了osg究竟是怎么完成对数据的加载的。那么我们现在要回到DatabasePager::updateSceneGraph的工作中,它是在osgViewer::Viewer:: updateTraversal()函数中遇到的
_scene->updateSceneGraph(*_updateVisitor);中被调用的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
void DatabasePager::updateSceneGraph( const osg::FrameStamp& frameStamp)
{ #define UPDATE_TIMING 0 #if UPDATE_TIMING osg::ElapsedTime timer;
double timeFor_removeExpiredSubgraphs, timeFor_addLoadedDataToSceneGraph;
#endif {
<span style= "color: #ff6600;" >removeExpiredSubgraphs(frameStamp);</span>
#if UPDATE_TIMING timeFor_removeExpiredSubgraphs = timer.elapsedTime_m();
#endif <span style= "color: #ff6600;" >addLoadedDataToSceneGraph(frameStamp);</span>
#if UPDATE_TIMING timeFor_addLoadedDataToSceneGraph = timer.elapsedTime_m() - timeFor_removeExpiredSubgraphs;
#endif }
#if UPDATE_TIMING double elapsedTime = timer.elapsedTime_m();
if (elapsedTime>0.4)
{
OSG_NOTICE<< "DatabasePager::updateSceneGraph() total time = " <<elapsedTime<< "ms" <<std::endl;
OSG_NOTICE<< " timeFor_removeExpiredSubgraphs = " <<timeFor_removeExpiredSubgraphs<< "ms" <<std::endl;
OSG_NOTICE<< " timeFor_addLoadedDataToSceneGraph = " <<timeFor_addLoadedDataToSceneGraph<< "ms" <<std::endl;
OSG_NOTICE<< " _activePagedLODList.size() = " <size()<<std::endl;
OSG_NOTICE<< " _inactivePagedLODList.size() = " <size()<<std::endl;
OSG_NOTICE<< " total = " <size() + _inactivePagedLODList->size()<<std::endl;
}
#endif } |
根据上面我们提到的,DatabasePager只有在使用 osg::PagedLOD 和 osg::ProxyNode 节点的时候才会有用。所以我们需要了解一下osg::PagedLOD和 osg::ProxyNode。
osg::PagedLOD我们先看一下类结构
Osg::Lod(level of detail)的意思就是按照用户的可视范围,将多个子节点作为同一场景的多个细节层次。这样可以在视点靠近物体时呈现较多的物体细节,而在远离时则仅仅呈现一个简化的模型,从而降低了运算和绘制的负担。但是osg::Lod节点可以其内部包含的子节点内容很多,这个时候无论加载哪一个层级都会消耗大量的计算机资源,为了解决这个问题,osg提出了pageLod这么一个类,目的就是运用了分页数据库的功能,将多个模型数据分批加载到场景图形中(作为 PagedLOD 的子节点);并根据用户当前的可视范围,将那些一段时间内均无法被看到的 PagedLOD 子节点剔除出场景图形,以节约系统资源;当然,如果用户移动了视点之后,被剔除的节点又重新进入视野,那么 OSG 的分页数据库线程将重新加载它。
Osg::ProxyNode我们还是先看看他的继承情况,再功能分析
ProxyNode就是代理节点的意思,也就是他可以看作一个node的另一个名称,这样我们在特定的时候加载模型时,就不需要进行查找工作,直接对ProxyNode进行操作就可以了。例如:当我们希望在场景仿真循环开始之后才加载某个模型文件时,可以使用ProxyNode 节点来指定要加载的文件名,并在场景筛选(Cull)的过程中加载模型,加载后的新节点将作为 ProxyNode 节点的子节点:
1
2
3
|
osg::ProxyNode* proxyNode = new osg:: ProxyNode;
proxyNode->setFileName(0, “nodefile.osg”); |
这里 setFileName 的两个参数分别是新载入的子节点在 ProxyNode 下的位置,以及对应模型文件的名称。我们还可以使用 ProxyNode::setLoadingExternalReferenceMode 来设置加载的时机,例如首先设置为不自动加载(NO_AUTOMATIC_LOADING),在适当的时候再设置为立即加载(LOAD_IMMEDIATELY)。
这样我们就大概讲述完成了DataPager的使用时机,以及完成了对_scene->updateSceneGraph(*_updateVisitor);函数的主要功能的讲解。
原文链接