任何程序都是有生命的,是生命就需要呼吸。例如普通的windows程序,当运行完main()函数后,就需要进入消息循环,来监听用户的各种操作,以便做出及时的回应。这样的每次循环就像生命的每次呼吸,来维持生命体征。

osg的程序不仅仅需要消息循环来监听用户的鼠标、键盘等操作,同时也得具备了渲染循环。当然随着我们的对osg的深入了解会发现,osg的事件监听和渲染循环是串行的。但是当我们把osg与MFC(QT)等结合时,相应UI上的鼠标,键盘事件的同时也要兼顾可能发生在osg中的效果,所以一般的osg程序起码需要两个并行的线程(例如osg与qt结合使用,为了保持足够灵敏的相应速度就需要把QTUI和osg渲染看成两种生命,分为两个线程)来维持它的正常运行。我们今天就是要解读osg程序赖以生存的每次呼吸。

首先我们得找到osg是用什么呼吸的,就想地球上的一般生物都是用鼻子呼吸,我们又大概得知道鼻子长在生物的那个位置。这样我们才可以开始我们的研究。当然我们肯定得有osg的源码,就像我们研究生物的呼吸先得有这种生物的身体。有了身体我们还得持续的观察一个有生命的生物,所以我们最先得到osg的可运行的程序就是example中的各种程序。其中大部分的程序main()函数的最后部分都是调用一下viewer.run()。

所以我们可以有一个模糊的判断这一类的通过调用viewer类的run函数的程序,他的呼吸系统可能是通过run完成的。但是run()函数是一个单独的一行,按说他执行完毕以后程序就会结束了,所以我们有了新的判断osg的每一帧的调用的入口是在run()函数中的。这是osg程序存在的一种形式(或者叫独立运行模式)。Osg还有另一种存在形式,就是和各种UI混合使用,例如qt与osg结合使用,MFC与osg结合使用等等。我们可以从examples/osgviewerQt 的例子,可以根据上一个的思路,呼吸不是一次性的动作,是只要存活就会一直存在的。所以从osgviewerQt.cpp中根据以前的经验定位到timer (计时器),他每次timeout触发时调用的函数update()中一定包含了osg的每一帧的调用的入口。

根据上面两种osg的存活形式,可以进行进一步的确认,究竟哪里才是维持osg生命体征的位置。Viewer.run()函数(OSG Core/osgViewer/Viewer.cpp)最后会继续调用ViewerBase::run()函数(OSG Core/osgViewer/ViewerBase.cpp),

  1. //OSG Core/osgViewer/Viewer.cpp
  2. int Viewer::run()
  3. {
  4. if (!getCameraManipulator() && getCamera()->getAllowEventFocus())
  5. {
  6. setCameraManipulator(new osgGA::TrackballManipulator());
  7. }
  8.  
  9. setReleaseContextAtEndOfFrameHint(false);
  10.  
  11. return ViewerBase::run();
  12. }

  

  1. //OSG Core/osgViewer/ViewerBase.cpp
  2. int ViewerBase::run()
  3. {
  4. if (!isRealized())
  5. {
  6. realize();
  7. }
  8.  
  9. const char* run_frame_count_str = getenv("OSG_RUN_FRAME_COUNT");
  10. unsigned int runTillFrameNumber = run_frame_count_str==0 ? osg::UNINITIALIZED_FRAME_NUMBER : atoi(run_frame_count_str);
  11.  
  12. while(!done() && (run_frame_count_str==0 || getViewerFrameStamp()->getFrameNumber()<runTillFrameNumber))
  13. {
  14. double minFrameTime = _runMaxFrameRate>0.0 ? 1.0/_runMaxFrameRate : 0.0;
  15. osg::Timer_t startFrameTick = osg::Timer::instance()->tick();
  16. if (_runFrameScheme==ON_DEMAND)
  17. {
  18. if (checkNeedToDoFrame())
  19. {
  20. frame();
  21. }
  22. else
  23. {
  24. // we don't need to render a frame but we don't want to spin the run loop so make sure the minimum
  25. // loop time is 1/100th of second, if not otherwise set, so enabling the frame microSleep below to
  26. // avoid consume excessive CPU resources.
  27. if (minFrameTime==0.0) minFrameTime=0.01;
  28. }
  29. }
  30. else
  31. {
  32. frame();
  33. }
  34.  
  35. // work out if we need to force a sleep to hold back the frame rate
  36. osg::Timer_t endFrameTick = osg::Timer::instance()->tick();
  37. double frameTime = osg::Timer::instance()->delta_s(startFrameTick, endFrameTick);
  38. if (frameTime < minFrameTime) OpenThreads::Thread::microSleep(static_cast(1000000.0*(minFrameTime-frameTime)));
  39. }
  40.  
  41. return 0;
  42. }

  

我们在ViewerBase::run()中继续耐心的寻找就会发现有一个特殊的函数frame(),为什么特殊呢?因为frame的英文的意思就是’帧’,而我们学渲染都知道’帧’代表屏幕上一幅画,这和osg库的本质就联系在了一起。Osg就是一个库,一个在计算机屏幕上作画的库。所以ViewerBase::frame()就是我们要找的osg中会呼吸的地方。同样我们在examples/osgviewerQt中也会发现,timer每到设定事件就会调用update()函数,而qt的update()函数在内部就会调用paintEvent()函数,我们在osgviewerQt.cpp的paintEvent()函数中也会发现osg::CompositeViewer的update函数,而osg::CompositeViewer继承自ViewerBase,所以最后也会定位到ViewerBase::frame()。这样我们就可以确定osg这类生物的呼吸的入口是ViewerBase::frame()函数。终于我们打开了通往新世界的大门,下一步就是经历轮回,看看osg这类生物是怎么生存的。

欢迎大家来我的新家看一看 3wwang个人博客-记录走过的技术之路

探索未知种族之osg类生物---起源的更多相关文章

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

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

  2. [转][osg]探索未知种族之osg类生物【目录】

    作者:3wwang 原文链接:http://www.3wwang.cn/html/article_58.html 前序 探索未知种族之osg类生物---起源 ViewBase::frame函数中的Vi ...

  3. 探索未知种族之osg类生物---状态树与渲染树以及节点树之间的关系

    节点树 首先我们来看一个场景构建的实例,并通过它来了解一下“状态节点”StateGraph 和“渲染叶”RenderLeaf 所构成的状态树,“渲染台”RenderStage 和“渲染元”Render ...

  4. 探索未知种族之osg类生物---器官初始化一

    我们把ViewerBase::frame()比作osg这类生物的肺,首先我们先来大概的看一下‘肺’长什么样子,有哪几部分组成.在这之前得对一些固定的零件进行说明,例如_done代表osg的viewer ...

  5. 探索未知种族之osg类生物---器官初始化二

    那我们回到ViewerBase::frame函数中来,继续看看为什么osg生命刚刚出生的时候会大哭,除了初始化了eventQuene和cameraManipulator之外还对那些器官进行了初始化.在 ...

  6. 探索未知种族之osg类生物---器官初始化四

    上一节我们对完成了对osg生物内部非常重要器官graphicsContext的初始化工作.这样就可保证我们场景中至少有一个graphicContext存在,不至于刚出生就面临夭折.我们根据上一节中os ...

  7. 探索未知种族之osg类生物---渲染遍历之裁剪一

    前言 上面我们用了四节课的内容,讲解了一些osg概念性的内部原理.希望大家可以再看今天的讲解之前先再仔细的研究一下前四节的内容.这样你就会对整个osg的渲染过程有一个更加清晰的认知,有助于理解下面两个 ...

  8. 探索未知种族之osg类生物---渲染遍历之认识SceneView

    前言 我们在进行osg程序的开发时,最常用到的场景管理方式是“场景节点树”的结构,     a 场景树底端的叶节点(osg::Geode)包含了各种需要渲染的几何体的顶点和渲染状态信息:     b  ...

  9. 探索未知种族之osg类生物---渲染遍历之器官协作

    好了,现在我们经过三节的介绍我们已经大体上明确了单线程模型(SingleThreaded)下 OSG 渲染遍历的工作流程.事实上无论是场景的筛选render还是绘制cull工作,最后都要归结到场景视图 ...

随机推荐

  1. Android Debug Bridge命令介绍[转]

    Android Debug Bridge命令介绍 Android Debug Bridge的一些基本命令.这个工具直译过来就是Android调试桥的意思.它提供了强大的特性,例如复制文件到设备或从设备 ...

  2. SQL语句中LEFT JOIN、JOIN、INNER JOIN、RIGHT JOIN的区别?

    w3school的一套sql教程: http://www.w3school.com.cn/sql/index.asp left join :左连接,返回左表中所有的记录以及右表中连接字段相等的记录.r ...

  3. org注释包

    1.注释包 物种 OrgDB 按蚊(Anopheles) org.Ag.eg.db 拟南芥(Arabidopsis) org.At.tair.db 牛(Brovine) org.Bt.eg.db 蠕虫 ...

  4. 提升系统的QPS和吞吐量

    简单而言通过增加集群来提升qps和吞吐量 实际上要比这个要复杂 首先我们需要知道系统的瓶颈 我们所知道的系统拓扑架构 对于rest接口而言 系统设施依次是: dns nginx tomcat db/s ...

  5. Vi命令:如何删除全部内容

    Vi命令:如何删除全部内容? 在命令模式下,输入:.,$d 一回车就全没了. 表示从当前行到末行全部删除掉. 用gg表示移动到首行.

  6. 解决pip下载速度慢

    国外的pip源下载速度过慢,可以换成国内的源,这里换成豆瓣的源. 新建一个文件vim ~/.pip/pip.conf 内容为 [global]timeout = 6000index-url= http ...

  7. Ext.js多文件选择上传,

    工作了之后来到了一家用Ext.js的公司, 一开始的时候做项目, 我被分给一个做一个单表的增删改查, 再加上文件上传功能, 带我的老师让我自己研究一下Ext.js怎么多文件选择上传, 并且能获取到上传 ...

  8. vue table中使用多选的问题(翻页后如何保存已选项),联动echarts图表实现流量监控

    流量监控项目需求: 根据表格数据,添加多选功能,默认全选,根据已选项更新图表视图 1.表格需要多选 2.要联动图表,所以关键是要利用表格多选的触发回调函数 vue table中使用多选: 很简单,只需 ...

  9. 第四章 栈与队列(c4)栈应用:中缀表达式求值

  10. FortiGate软件版本升级

    1.Web界面升级 1)注意:升级前,务必做好配置备份 2)要点 1.FortiGate防火墙的每款型号都有单独的版本文件,升级前务必确认下当前的设备型号: 2.升级包的后缀名必须为.out,前缀任意 ...