OSG 的更新遍历函数updateTraversal 在系统每帧的执行过程中有着重要的地位,除了
处理用户的更新回调对象之外,还要负责更新摄像机的位置,并且更新分页数据库
DatabasePager 和图像库ImagePager 的内容。这里我们首先对它的流程做一个概述:
1、获取函数的起始时刻。
2、使用预设的更新访问器_updateVisitor,访问场景图形的根节点并遍历其子节点,实
现各个节点和Drawable 对象的更新回调。
3、使用DatabasePager::updateSceneGraph 函数以及ImagePager::updateSceneGraph 函数,
分别更新场景的分页数据库和分页图像库。
4、处理用户定义的更新工作队列_updateOperations。
5、执行主摄像机_camera 以及从摄像机组_slaves 的更新回调(但是不会遍历到它们的
子节点),注意摄像机回调的执行时机与场景节点还是有所区别的。
6、根据漫游器_cameraManipulator 的位置姿态矩阵,更新主摄像机_camera 的观察矩阵。
注意这里使用的函数是MatrixManipulator::getInverseMatrix,根据第七日介绍的内容,摄像
机在世界坐标系中的位置姿态矩阵,即是其观察矩阵的逆矩阵,由是可得。
7、使用View::updateSlaves 函数更新从摄像机组_slaves 中所有摄像机的投影矩阵,观
察矩阵和场景筛选设置(CullSettings)。
8、获取函数的结束时刻,将相关的时刻信息保存到记录器中。
不要以为我们对这个函数的介绍就这么草草地完结了。事实上,在浏览更新遍历的执行
流程时,我们已经遇到了一大堆之前没有提及的概念,如果不从中好好地发掘一番,“最长
的一帧”这个标题恐怕就徒有虚名了(其实本来就徒有虚名)。
首先是更新工作队列_updateOperations 的问题。第四日中我们曾介绍过可以使用
ViewerBase::setRealizeOperation 来自定义的场景预处理工作,更新工作的作用及实现方法与
之相似,均需要继承osg::Operation 并重写operator()操作符,以实现一些特定的用户操作。
不过在这里,用户可以使用ViewerBase::addUpdateOperation 写入多组更新处理器Operation
对象(或者使用对应的成员函数removeUpdateOperation 来移除),因此可以实现的操作也更加丰富。