观察MyReadFileCallback结构体的内容,可以发现它继承自osgDB::Registry::ReadFileCallback,并重载了一个函数readNode,分析源代码可知,该函数在osgDB::readNodeFile函数中被调用,即,在加载模型文件时,即会调用 MyReadFileCallback结构体所重载的readNode函数并执行相应的内容。示例程序中该函数的内容如下:
class MyReadFileCallback : public osgDB::Registry::ReadFileCallback
{
public:
virtual osgDB::ReaderWriter::ReadResult readNode(const std::string& fileName, const osgDB::ReaderWriter::Options* options)
{
std::cout<<"before readNode"<<std::endl;
// note when calling the Registry to do the read you have to call readNodeImplementation NOT readNode, as this will
// cause on infinite recusive loop.
osgDB::ReaderWriter::ReadResult result = osgDB::Registry::instance()->readNodeImplementation(fileName,options);
std::cout<<"after readNode"<<std::endl;
return result;
}
};
其中较为重要的是readNodeImplementation一行,这是模型文件读取的实际执行函数,如果在回调中对于这一语句的使用有错,那么模型无论怎样都不能被加载。

InsertCallbacksVisitor的内容比较复杂,它继承自osg::NodeVisitor,属于用户自定义的节点访问器。换句话说,当执行到:
InsertCallbacksVisitor icv;
rootnode->accept(icv);
节点访问器将从根节点rootnode开始,遍历所有的子节点并执行相应的操作。
节点访问器InsertCallbacksVisitor的构造函数中,可以传递一个遍历方式的枚举量TraversalMode ,它的取值意义如下:
TRAVERSE_NONE:仅仅传递到当前节点,然后停止传递; 
TRAVERSE_PARENTS:传递给当前节点及其父节点,注意,如果当前节点有不止一个父节点,那么访问器将列举出所有的传递路线,其中可能有多个重复出现的节点; 
TRAVERSE_ALL_CHILDREN:传递给当前节点及其所有子节点,同样,对于多个子节点的情况,访问器将列举所有的传递路线; 
TRAVERSE_ACTIVE_CHILDREN:传递给当前节点及所有被激活的子节点,例如遇到LOD节点和Switch节点时,将不会传递给当前无法显示的子节点。

在节点访问器中,使用apply函数来实现对各种类型的节点的访问。当遍历过程中遇到与某个重载的apply的输入参数相符合的节点时,将执行这一 apply函数的内容。示例代码中重载了Node,Geode和Transform节点的访问函数。在Geode节点的访问函数中,实现了对场景图形结构中每个节点的回调指定:
// 指定Geode节点的更新回调。
geode.setUpdateCallback(new UpdateCallback());

// 指定Geode节点中所有关联几何体(Drawables)的绘制回调,拣选回调和更新回调。
for(unsigned int i=0;i<geode.getNumDrawables();++i)
{
     geode.getDrawable(i)->setUpdateCallback(new DrawableUpdateCallback());
     geode.getDrawable(i)->setCullCallback(new DrawableCullCallback());
     geode.getDrawable(i)->setDrawCallback(new DrawableDrawCallback());
}

在Geode之外的其它节点的apply函数中,往往包含有下面的语句:
traverse(node);
这表示对场景图形节点的遍历将继续进行。换句话说,如果某种类型的节点的apply函数中不包含这一语句,那么场景图形遍历到这一类型的节点时,当前遍历的路线将自动结束,以下的子节点均被忽略。而对Geode节点来说,因为不存在子节点,因此也不必添加这一语句。

使用节点访问器为场景图形节点或几何体添加的回调主要有以下几种:
几何体绘制遍历(DrawableDrawCallback):重载函数drawImplementation,当几何体进行绘制时,函数的内容被调用,注意需要添加Drawable::drawImplementation函数以实现几何体的实际绘制,否则将无法画出当前的几何形状。可以参阅 include/osg/Drawable,draw函数中的调用过程。
几何体拣选遍历(DrawableCullCallback):重载函数cull,当几何体进行拣选优化时,函数的内容被调用。可以参阅src/osgUtil/CullVisitor,apply(Geode&)函数中的调用过程。
几何体更新遍历(DrawableUpdateCallback):重载函数update,当几何体更新时,函数的内容被调用。可以参阅include/osgUtil/UpdateVisitor,handle_geode_callbacks函数中的调用过程。
拣选遍历(CullCallBack):重载操作符operator(),当场景执行拣选优化时,operator()的内容被调用,注意需要添加 traverse函数以实现节点的继续遍历。可以参阅include/osgUtil /CullVisitor,handle_cull_callbacks_and_traverse函数中的调用过程。
更新遍历(UpdateCallBack):重载操作符operator(),当场景更新时,operator()的内容被调用,注意需要添加 traverse函数以实现节点的继续遍历。可以参阅src/osg/StateSet.cpp,runUpdateCallbacks函数中的调用过程。

最后,观察CameraUpdateCallback和CameraEventCallback结构体的内容,可以发现它们均继承自 osg::NodeCallback,并重载了操作符operator(),当执行摄像机更新或者事件回调时,operator()的内容将被调用,添加 traverse函数可以实现节点的继续遍历。

此外,还可以使用Node::setEventCallback来设置节点的事件回调,其输入参数为继承自osg::NodeCallback的用户类,且需要重载操作符operator()以实现回调过程的处理。

综上,可以得出回调的编写方法:
1、编写用户结构体,继承OSG中相应的虚函数结构体,如osg::NodeCallBack;
2、重载回调执行函数,根据回调种类的不同,执行函数的名称也不同,可以参考osgcallback中的设置;
3、注意在回调执行的过程中,有一些必要的系统操作需要交由用户来完成,例如readNodeImplementation,Drawable::drawImplementation,traverse等,否则系统本身的渲染工作可能会不正常。

编译运行osgcallback之后,可以看到控制台不断输出各种回调的执行结果,用户可以根据自己的需要在不同的时间段进入不同的回调来完成所需的工作。

[osg]osgcallback各种回调使用的例子介绍的更多相关文章

  1. ThinkPHP 自动创建数据、自动验证、自动完成详细例子介绍(十九)

    原文:ThinkPHP 自动创建数据.自动验证.自动完成详细例子介绍(十九) 1:自动创建数据 //$name=$_POST['name']; //$password=$_POST['password ...

  2. OSG使用更新回调来更改模型

    OSG使用更新回调来更改模型 转自:http://blog.sina.com.cn/s/blog_668aae7801017gl7.html 使用回调类实现对场景图形节点的更新.本节将讲解如何使用回调 ...

  3. js 回调函数小例子

    js 回调函数小例子 <script> //将函数作为另一个函数的参数 function test1(){ alert("我是test1"); } function t ...

  4. [源][osg][osgBullet]osgBullet例子介绍

    1.BasicDemo 基本样例 一个小玩具飞机坠落,一个立方体盒子在转圈 2.centerofmass 质心 3.collision 碰撞检测 这里有一个大神自己改的例子: http://blog. ...

  5. js的回调函数 一些例子

    这边用bootstrap 3.0的  上传控件做例子 下面是上传控件的一段完整的 js 操作 代码. <!-- 上传缩略图控件配置 --><script> // 定义这四个全局 ...

  6. 转:Delphi 回调函数及例子

    http://anony3721.blog.163.com/blog/static/5119742010866050589/ { http://anony3721.blog.163.com/blog/ ...

  7. 回调--一个经典例子让你彻彻底底理解java回调机制

    本文出自xiaanming的博客(http://blog.csdn.net/xiaanming/article/details/17483273),请尊重他人的辛勤劳动成果,谢谢 以前不理解什么叫回调 ...

  8. Android Loader详解四:回调及完整例子

    onLoadFinished 这个方法是在前面已创建的装载器已经完成其加载过程后被调用.这个方法保证会在应用到装载器上的数据被释放之前被调用.在此方法中,你必须删除所有对旧数据的使用(因为它将很快会被 ...

  9. [osg]OSG使用更新回调来更改模型

    使用回调类实现对场景图形节点的更新.本节将讲解如何使用回调来实现在每帧的更新遍历(update traversal)中进行节点的更新.        回调概览       用户可以使用回调来实现与场景 ...

随机推荐

  1. Camera2点击对焦实现

    https://www.jianshu.com/p/76225ac72b56 android从5.0开始,废弃了原有的Camera接口,提供了全新的Camera2接口.Camera2接口为了给app提 ...

  2. python简说(十五)MD5加密

    def my_md5(s): news = str(s).encode() m = hashlib.md5(news) return m.hexdigest()

  3. keras与tensorboard结合使用

    使用tensorboard将keras的训练过程显示出来(动态的.直观的)是一个绝好的主意,特别是在有架设好的VPS的基础上,这篇文章就是一起来实现这个过程. 一.主要原理 keras的在训练(fit ...

  4. py4CV例子1猫狗大战和Knn算法

    1.什么是猫狗大战: 数据集来源于Kaggle(一个为开发商和数据科学家提供举办机器学习竞赛.托管数据库.编写和分享代码的平台),原数据集有12500只猫和12500只狗,分为训练.测试两个部分. 2 ...

  5. matlab的三维绘图和四维绘图

    一.三维绘图1.曲线图plot3(X1,Y1,Z1,...):以默认线性属性绘制三维点集(X1,Y1,Z1)确定的曲线plot3(X1,Y1,Z1,LineSpec):以参数LineSpec确定的线性 ...

  6. Codeforces 437D The Child and Zoo - 树分治 - 贪心 - 并查集 - 最大生成树

    Of course our child likes walking in a zoo. The zoo has n areas, that are numbered from 1 to n. The ...

  7. volatile的陷阱

         对于volatile关键字,大部分C语言的教程都是一笔带过,并没有做太深入的分析,所以这里简单的整理了一些 关于volatile的使用注意事项.实际上从语法上来看volatile和const ...

  8. 在Linux系统安装Appium

    安装sudo apt-get update sudo apt-get install nodejs sudo apt-get install npm npm install -g appium 卸载: ...

  9. Restful framework【第九篇】分页器

    基本使用 分页 -简单分页 page_size = api_settings.PAGE_SIZE :每页显示条数 page_query_param = 'page' :查询的页码数 page_size ...

  10. javascript的执行过程, 语法错误和运行时错误?

    js的执行错误分为 语法syntaxError,和 runtime error, 首先, js引擎会检查 整个脚本的语法, 如果在检查语法的过程中,发现了错误, 比如括哈不配对, 字符串少了 另一半的 ...