探索未知种族之osg类生物---呼吸分解之advance
回顾
我们用了两节的内容才堪堪讲解完ViewerBase::frame()函数中调用的realize()---Viewer:: realize()函数。我们简单的总结就是Viewer:: realize()主要是使GraphicsContext处于可用状态,并且启动相关的图形线程。
ViewerBase::frame()函数解读到这里,我们完成了osg生物第一次尝试呼吸所需要的所有器官的初始化工作。下面就真正的开始进入osg呼吸动作的研究了。也就意味着我们真是进入osg的仿真循环的研究当中。那我们就来看看osg呼吸的第一个动作advance()。
osgViewer::advance()
osgViewer::advance()函数的功能算是比较简单的,老规矩先介绍一下这个函数中遇到的新的成员变量。_frameStamp:(osg::FrameStamp)是用来记录osg的帧数以及时钟校准,计数所用到的内置器官,这样可以精确的掌握osg的运行时间,有利于开发人员进行调优工作。在这里(advance())
1
2
3
|
double previousReferenceTime = _frameStamp->getReferenceTime(); unsigned int previousFrameNumber = _frameStamp->getFrameNumber(); _frameStamp->setFrameNumber(_frameStamp->getFrameNumber()+1); |
首先获得osg运行的上一帧时间(是在osg内部记录的时间不是真实世界的时间),以及获得已经运行了多少帧了,并使记录加1(也就是记录目前所处的帧数),
1
2
3
4
5
6
7
8
9
10
|
_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); } |
再设置现在的相对运行的时间(根据当前时刻,重新记录参考时间,并因此得到两次记录之间的差值,即一帧经历的时间)。
1
2
3
4
5
6
7
|
// 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()); |
记录这些的目的就是有时候我们需要将帧速率,参考时间等内容予以记录并显示给用户,此时需要通过 ViewerBase::getStats 函数获得 osg::Stats 对象,用以进行帧状态的保存和显示。
1
2
3
4
5
|
if (osg::Referenced::getDeleteHandler()) { osg::Referenced::getDeleteHandler()->flush(); osg::Referenced::getDeleteHandler()->setFrameNumber(_frameStamp->getFrameNumber()); } |
上一段内容基本对advance介绍完成了,只剩下最后一个if (osg::Referenced::getDeleteHandler())判断。它的作用是用来将已经收集得到的所有的osg弃用的对象删除(osg::DeleteHandler::flush())。这里所说的“弃用”,与我们非常熟悉的 osg::ref_ptr 智能指针是密切相关的。我们已经知道,ref_ptr 采用内存引用计数的方式,当一个场景对象(通常是 Node 节点)链接到根节点或者其他节点时,它的引用计数加一,这一动作是通过 ref_ptr::ref()函数实现的;如果它被剔除出节点,那么它的引用计数减一,执行这一工作的函数是 ref_ptr::unref()。unref 函数的另一个重要任务是检查对象的引用计数值是否到达零,如果已经没有被其它对象所引用, 那么称这个对象被“弃用”,它应当被立即删除,以释放相应的内存空间,避免泄露。
osg::DeleteHandler与osg::ref_ptr
C++中通用的删除对象的方法是 delete,OSG 的智能指针也是采用这种方式来释放对 象的,不过由于OSG采用多线程更新/渲染的方式, 这样做可能带来会某些隐患,想象这样一种情况:
1、场景某个的节点负责显示某种图形,它的工作一直很正常。
2、我们采用 DrawThreadPerContext 或者 CullThreadPerCameraDrawThreadPerContext 线程模型。
3、假设我们在更新工作中立即将这个节点删除,而上次渲染工作可能正要将这个节点 中的数据送往 OpenGL 图形渲染管线,那么灾难就发生了……
看到这里,你一定已经想到了一种解决方案。对,就是在渲染后台也使用 ref_ptr 来引用(ref)图形节点,然后在渲染结束取消引用(unref),这样不就可以避免无谓的牺牲了吗?也省却用户的很多麻烦。
说得有道理,不过这其中恐怕忽视了一个核心的问题:渲染效率。是的,假设我们要渲染成千上万个这样的几何体节点(这对您来说也许简直是家常便饭),如果每个节点的渲染 都要多执行一次 ref/unref 的话,效率的损失将是无法被忽略的。事实上经过测算,CPU 时间的流失大概可以达到 6%,对于一个实时渲染系统来说,这的确值得斟酌。
因此,OSG 的新版本中提出了 DeleteHandler 的概念,也就是“垃圾收集”,把那些引 用计数已经为零的对象统一收集起来,确保它们不会再被渲染线程用到之后,再在适当的地 方予以释放。DeleteHandler 有一个重要的参数_numFramesToRetainObjects,它的意义是,垃 圾对象被收集之后,再经过多少帧(默认设置是 2),方予以释放。因此,OSG 的垃圾收集 器同样需要使用 DeleteHandler::setFrameNumber 来记录当前的帧数。 这个概念提出的时间并不长,也许还需要一段时间的测试,也许会有更好的方案来替代 它。目前,OSG 的发行版本仍然采用第一种方式,也就是渲染后台采用 ref_ptr 引用计数的 方式来避免删除对象造成的问题;如果您想要尝试使用和帮助调试 DeleteHandler 的话,可 以在自己的程序中(main 函数之前)加入:
#undef OSGUTIL_RENDERBACKEND_USE_REF_PTR
以请求使用 DeleteHandler。
欢迎大家来我的新家看一看 3wwang个人博客-记录走过的技术之路
探索未知种族之osg类生物---呼吸分解之advance的更多相关文章
- 探索未知种族之osg类生物---呼吸分解之渲染遍历二
那么今天我们就正式进入osg整个呼吸动作之中最复杂的一个动作,ViewerBase::renderingTraversals(),我们先介绍renderingTraversals的开头的简单的几步操作 ...
- 探索未知种族之osg类生物---呼吸分解之更新循环二
_scene->updateSceneGraph(*_updateVisitor); 我们用了前面4节才刚刚算是完成对DatabasePager::DatabaseThread::run()函数 ...
- 探索未知种族之osg类生物---呼吸分解之更新循环一
上节总结 前几天我们大体上介绍完成了osg的事件循环的介绍,总结一下osg的时间循环主要就是得到平台(windows)的所有消息,并遍历所有的node的eventCallback,并对他们进行处理.接 ...
- 探索未知种族之osg类生物---呼吸分解之事件循环二
VPM矩阵 1.V 表示摄像机的观察矩阵(View Matrix),它的作用是把对象从世界坐标系变换到摄像机坐标系.因此,对于世界坐标系下的坐标值 worldCoord(x0, y0, z0),如果希 ...
- 探索未知种族之osg类生物---呼吸分解之事件循环一
事件循环和更新循环 终于到了我们嘴里经常念叨的事件循环.更新循环以及渲染循环了.首先我们来区分一下事件循环和渲染循环,他们两个首先是两个不同顺序执行的过程,我们有时候会用到任意node的updateC ...
- 探索未知种族之osg类生物---呼吸分解之渲染遍历一
总结 前面我们基本上已经完成对ViewerBase::frame()函数的探究,只剩下renderingTraversals()渲染遍历的探究,虽然就剩下了一个函数,但是这却是最重要的,不可少的一个步 ...
- 探索未知种族之osg类生物---呼吸分解之更新循环三
补充 当然细心的你会发现,_scene->updateSceneGraph(*_updateVisitor)中还有一个imagePager::UpdateSceneGraph()还没有进行讲解, ...
- 探索未知种族之osg类生物---呼吸分解之事件循环三
那我们就开始处理这些事件中得到的所有的交互事件,首先我们要判断这些事件是否包含osg的退出事件,那什么情况下会触发这个退出事件呢?如果您运行过osg中example中的小例子的,聪明的你一定就会发现当 ...
- 《探索未知种族之osg类生物》目录
精力有限,博客园不在更新<探索未知种族之osg类生物>.在这里列出所有文章目录(持续更新)有兴趣的同学可以看看. 探索未知种族之osg类生物[目录] 前序 探索未知种族之osg类生物--- ...
随机推荐
- WilliamChart各种图表效果实现大全《IT蓝豹》
WilliamChart各种图表效果实现大全,有水平线条表格,有柱状表格等.由LineFragment,BarFragment,StackedFragment,SandboxFragment几个fra ...
- spring boot 实现RESTFull API
- hive sql 效率提升
转 : http://www.cnblogs.com/xd502djj/p/3799432.html hive的查询注意事项以及优化总结 . Hive是将符合SQL语法的字符串解析生成可以在Hado ...
- python字典dict的增、删、改、查操作
## python字典dict的增.删.改.查操作dict = {'age': 18, 'name': 'jin', 'sex': 'male', }#增# dict['heigh'] = 185 # ...
- hdu2669-Romantic-(扩展欧几里得定理)
Romantic Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Su ...
- Linux下怎么创建和进入带有空格的文件夹
有时候需要创建带有空格的文件夹,虽然这不是一个好的习惯,但是偶尔会遇到.用的最多的是很多时候需要进入带有空格的文件夹,如"a b"是一个文件夹名. 创建:mkdir "a ...
- kangle请求控制添加的add_header怎么查看
请求控制里添加的add header不会显示在浏览器的请求里,因为是发送给源的,你们要查看可以用phinfo查看.回应控制里添加的会显示在浏览器的回应里
- burpsuite的使用(二)
爬网 为了爬网更加顺畅,先关掉截断功能 先进行手动爬网 然后进到目标页面需要点的地方和输入的地方去操作一下,在spider下就能看到爬网的记录 自动爬网 当你爬网时需要登录身份验证时,提示输入,也可以 ...
- jquery不能实时获取CKEDITOR值的解决方法
不用传统的获取值的方法: var ckeditor = document.getElementById("ckeditor").value; 换成: var ckeditor = ...
- Javascript重点汇总
LazyMan 实现LazyMan(什么是LazyMan?请自行google) function _LazyMan(_name) { var _this = this; _this.tasks = [ ...