_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::removeExpiredSubgraphs()函数的主要作用是通过目前正在使用的PagedLOD节点移除到指定定时间时间以来未访问过(过期的)的子节点。 注意,这段操作应该只从更新循环中调用。探究这个DatabasePager::removeExpiredSubgraphs()函数的内容,发现函数的开头还是对这个删除过程的记录,最后保存到osg的log中。遇到第一个if语句就是跳过第一帧,因为这个时候没有任何过期的数据。记录一下当前_ activePagedLODList的大小numPagedLODs,当numPagedLODs没有达到最大lod数(_targetMaximumNumberOfPageLOD)就不用进行清理工作。我们要记录超过的我们约定的最大的_targetMaximumNumberOfPageLOD,的数量,这样我们就知道删除多少过期的lodpage数量(numToPrune),然后我们就是_activePagedLODList->removeExpiredChildren()来便利现在所有的pagelod,从存在时间最长的也就是_activePagedLODList最先加入的成员开始,删除子节点,直到numToPrune为0为止。这样我们就完成了对过期的pageLod的删除工作。
      • DatabasePager::addLoadedDataToSceneGraph: 向场景图中添加新的数据。还记得我们在DatabasePager::run函数中介绍到_dataToMergeList吗?这个时候就要排上用场了。函数的开头依然是要对下面的添加数据的操作进行记录。把dataToMergeList中的数据转移到localFileLoadedList中,遍历localFileLoadedList首先取得“待合并列表”_dataToMergeList,并遍历其中每一个 DatabaseRequest 对象。遍历过程中,首先执行 SharedStateManager::share 函数,将新加载节点_loadedModel 的渲染属性保存到 SharedStateManager 管理器中。然后用来判断node是否为osg::PagedLOD或者osg::ProxyNode,也就是说DatabasePager只会在指定为osg::PagedLOD或者osg::ProxyNode才会启用。然后就是得到DatabaseRequest对象使用getDatabaseRequest(plod->getNumChildren())或者是 proxyNode->getDatabaseRequest(proxyNode->getNumChildren())函数,随后执行 DatabasePager::registerPagedLODs,在加载的节点及其子树中搜索 PagedLOD节点,并添加到刚刚提到的_pagedLODList 列表中。

根据上面我们提到的,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);函数的主要功能的讲解。

原文链接

http://www.3wwang.cn/blog/article.ftl?id=30

探索未知种族之osg类生物---呼吸分解之更新循环二的更多相关文章

  1. 探索未知种族之osg类生物---呼吸分解之更新循环一

    上节总结 前几天我们大体上介绍完成了osg的事件循环的介绍,总结一下osg的时间循环主要就是得到平台(windows)的所有消息,并遍历所有的node的eventCallback,并对他们进行处理.接 ...

  2. 探索未知种族之osg类生物---呼吸分解之更新循环三

    补充 当然细心的你会发现,_scene->updateSceneGraph(*_updateVisitor)中还有一个imagePager::UpdateSceneGraph()还没有进行讲解, ...

  3. 探索未知种族之osg类生物---呼吸分解之事件循环二

    VPM矩阵 1.V 表示摄像机的观察矩阵(View Matrix),它的作用是把对象从世界坐标系变换到摄像机坐标系.因此,对于世界坐标系下的坐标值 worldCoord(x0, y0, z0),如果希 ...

  4. 探索未知种族之osg类生物---呼吸分解之事件循环一

    事件循环和更新循环 终于到了我们嘴里经常念叨的事件循环.更新循环以及渲染循环了.首先我们来区分一下事件循环和渲染循环,他们两个首先是两个不同顺序执行的过程,我们有时候会用到任意node的updateC ...

  5. 探索未知种族之osg类生物---呼吸分解之渲染遍历二

    那么今天我们就正式进入osg整个呼吸动作之中最复杂的一个动作,ViewerBase::renderingTraversals(),我们先介绍renderingTraversals的开头的简单的几步操作 ...

  6. 探索未知种族之osg类生物---呼吸分解之事件循环三

    那我们就开始处理这些事件中得到的所有的交互事件,首先我们要判断这些事件是否包含osg的退出事件,那什么情况下会触发这个退出事件呢?如果您运行过osg中example中的小例子的,聪明的你一定就会发现当 ...

  7. 探索未知种族之osg类生物---呼吸分解之advance

    回顾 我们用了两节的内容才堪堪讲解完ViewerBase::frame()函数中调用的realize()---Viewer:: realize()函数.我们简单的总结就是Viewer:: realiz ...

  8. 探索未知种族之osg类生物---呼吸分解之渲染遍历一

    总结 前面我们基本上已经完成对ViewerBase::frame()函数的探究,只剩下renderingTraversals()渲染遍历的探究,虽然就剩下了一个函数,但是这却是最重要的,不可少的一个步 ...

  9. 《探索未知种族之osg类生物》目录

    精力有限,博客园不在更新<探索未知种族之osg类生物>.在这里列出所有文章目录(持续更新)有兴趣的同学可以看看. 探索未知种族之osg类生物[目录] 前序 探索未知种族之osg类生物--- ...

随机推荐

  1. ubuntu安装nginx及其默认目录结构

    一. 安装包安装 1.1 安装Nginx $sudo apt-get install nginx Ubuntu安装之后的文件结构大致为: 所有的配置文件都在/etc/nginx下,并且每个虚拟主机已经 ...

  2. python eval()和exec()以及complie()

    1.eval() 函数 eval() 函数用来执行一个字符串表达式,并返回表达式的值. ------->>  eval(expression[, globals[, locals]]) 参 ...

  3. Linux系统编程——信号

    目录 信号的介绍 信号的机制 信号的编号 Linux常规信号一览表 信号的产生 终端按键产生信号 硬件异常产生信号 kill函数/命令产生信号 信号的操作函数 信号集设定 sigprocmask函数 ...

  4. U3D学习14-一阶段学习总结

    一.UGUI界面拖拽 1.物品类中继承以下5个接口 命名空间: UnityEngine.EventSystem; IBeingDragHandler (OnBeingDrag) IDragHandle ...

  5. WordPress版微信小程序2.1.8版发布

    近来的工作比较多,同时也在思考这个项目未来的发展方向,尽管不断有新的wordpress站长,利用我的开源程序搭建了微信小程序,但个人对这个项目的热情日渐减少,促使我不断完善和维护这个开源项目的动力也再 ...

  6. bresenham 算法生成直线

    struct Point{ Point() { posx = 0; posy = 0; } Point(int x, int y) { posx = x; posy = y; } int posx; ...

  7. 今天看了几个小时的微信小程序说说心得体会

    今天看了几个小时的微信小程序说说心得体会 小程序是个前端框架 根据微信相关提供了很多接口 1 先说说各种后缀的文件 .json 后缀的 JSON 配置文件.wxml 后缀的 WXML 模板文件.wxs ...

  8. python:选房抽签小工具

    1.房间号和姓名写在house_name.xls的house标签页中[注意!名字均不要改动]2.运行house.py3.当前同目录下会生成result.xls,即为结果:程序运行过程中不要打开该文件, ...

  9. matlab-非线性拟合函数lsqcurvefit的使用和初值选取

    所解决问题: 我们知道我们的表达式是y=A+B*exp(-x.^2)-C./log(x), 而且现在我们手里面有x与y对应的一大把数据. 我们需要根据x, y的值找出最佳的A.B.C值.则我们现在借助 ...

  10. Python学习:模块初识、数据类型

    1.模块初识 在Python中,模块分为两种: (1)标准库 标准库无需安装,只要在使用的时候import就可以使用了 (2)第三方库 第三方库必须下载安装之后才能够引入使用 下面介绍两个基本的模块: ...