OSG中的节点主要使用回调(CallBack)来完成用户临时、需要每帧执行的工作。根据回调功能被调用的时机
划分为更新回调(Update CallBack)和人机交互时间回调(Event CallBack)。前者在每一帧中系统遍历到
当前节点时调用,后者则由交互事件触发,如操作键盘、鼠标、关闭窗口、改变窗口大小等动作。回调类基类
是osg::NodeCallBack(),主要函数如下:

//虚函数,回调函数主要操作在此函数中,子类应当重写,已完成相应操作
void operator()(Node* node, NodeVisitor* nv);
//为当前更新回调添加(删除)一个后继的回调对象
void addNestedCallback(NodeCallback* nc);
void removeNestedCallback(NodeCallback* nc);
//直接设置/获取一个最近的回调
void (NodeCallback* nc);
NodeCallback* getNestedCallback();
//调用临近中的下一个更新回调
void traverse(Node* node,NodeVisitor* nv);

节点类中完成回调函数设置和获取:

//设置/获取节点的更新回调
void setUpdateCallback(NodeCallback* );
NodeCallback* getUpdateCallback();
//设置/获取节点的事件回调
void setEventCallback(NodeCallback*);
NodeCallback* getEventCallback();

对于addNestedCallback(……)函数,其源码如下:

inline void addNestedCallback(NodeCallback* nc)
{
if (nc)
{
if (_nestedCallback.valid())
{
nc->addNestedCallback(_nestedCallback.get());
_nestedCallback = nc;
}
else
{
_nestedCallback = nc;
}
}
}

在NodeCallback类中用一个ref_ptr<NodeCallback> _nestedCallback; 来存储下一个回调对象,利用链表构成
一个回调对象序列,当要添加一个临近回调时,即调用addNestedCallback(NodeCallback* nc)时利用递归将两个
(分别以this,nc为连表头的)序列合并,例如:this->callback1->callback2->callback3->null, nc->callback4
->callback5->null。合并后新的序列为this->nc->callback1->callback4->callback2->callback5->callback3
->null。至于removeNestedCallback(...),比较简单,如下:

inline void removeNestedCallback(NodeCallback* nc)
{
if (nc)
{
if (_nestedCallback==nc)
{
_nestedCallback = _nestedCallback->getNestedCallback();
}
else if (_nestedCallback.valid())
{
_nestedCallback->removeNestedCallback(nc);
}
}
}

其中traverse()函数,其功能是对当前节点调用下一个临近回调函数,其代码如下:

void NodeCallback::traverse(Node* node,NodeVisitor* nv)
{
//如果有后续回调对象,则调用, 重载操作符"()"来实现
if (_nestedCallback.valid())
(*_nestedCallback)(node,nv);
//回调操作完成之后,访问该节点
else
nv->traverse(*node);
}

一个范例:使用回调实现旋转动画

 #include <osg/Quat>
#include <osg/PositionAttitudeTransform>
#include <osg/io_utils>
#include <osgDB/ReadFile>
#include <osgViewer/Viewer>
#include <iostream> class RotateCallBack: public osg::NodeCallback{
  public:
   RotateCallBack():_rotateZ(0.0) {}    virtualvoidoperator()(osg::Node* node, osg::NodeVisitor* nv){
    osg::PositionAttitudeTransform* pat =
    dynamic_cast<osg::PositionAttitudeTransform*>(node);
     if(pat){
      osg::Vec3 vec(, , );
      osg::Quat quat = osg::Quat(osg::DegreesToRadians(_rotateZ), osg::Z_AXIS);
      pat->setAttitude(quat);       _rotateZ += 0.10;
    }     traverse(node, nv);
  }
  
  private:
   double _rotateZ;
}; class InfoCallBack: public osg::NodeCallback{
  public:
   virtualvoidoperator()(osg::Node* node, osg::NodeVisitor* nv){
     osg::PositionAttitudeTransform* pat =
    dynamic_cast<osg::PositionAttitudeTransform*>(node);     if(pat){
       double angle = 0.0;
      osg::Vec3 axis;
      pat->getAttitude().getRotate(angle, axis);       std::cout << "Node is rotate around the axis(" << axis << "), "
      <<osg::RadiansToDegrees(angle) << "degrees" << std::endl;
    }     traverse(node, nv);
  }
}; int main(int argc, char** argv){
  osg::ArgumentParser argument(&argc, argv);
  osg::Node* model = osgDB::readNodeFiles(argument);
   if(!model)
  model = osgDB::readNodeFile("cow.osg") ;   osg::ref_ptr<osg::PositionAttitudeTransform> pat =
   new osg::PositionAttitudeTransform();
  pat->addChild(model);   pat->setUpdateCallback(new RotateCallBack() );
  pat->addUpdateCallback(new InfoCallBack() );   osgViewer::Viewer viewer;
  viewer.setSceneData(pat.get() );
   return viewer.run();
}

转自:http://www.cnblogs.com/hzhg/archive/2010/12/19/1910340.html

OSG事件回调的更多相关文章

  1. 用block做事件回调来简化代码,提高开发效率

       我们在自定义view的时候,通常要考虑view的封装复用,所以如何把view的事件回调给Controller就是个需要好好考虑的问题, 一般来说,可选的方式主要有target-action和de ...

  2. backbone collection add 事件回调参数

    this.listenTo(this.collection, 'add', this.renderBook); renderBook: function (item) { var bookView = ...

  3. Guava 源码分析(Cache 原理 对象引用、事件回调)

    前言 在上文「Guava 源码分析(Cache 原理)」中分析了 Guava Cache 的相关原理. 文末提到了回收机制.移除时间通知等内容,许多朋友也挺感兴趣,这次就这两个内容再来分析分析. 在开 ...

  4. 基于epoll封装的事件回调miniserver

    epoll技术前两节已经阐述过了,目前主要做一下封装,很多epoll的服务器都是采用事件回调方式处理, 其实并没有什么复杂的,我慢慢给大家阐述下原理. 在networking.h和networking ...

  5. ZT ANDROID jni 中的事件回调机制JNIenv的使用 2012-09-10 12:53:01

    ANDROID jni 中的事件回调机制JNIenv的使用 2012-09-10 12:53:01 分类: 嵌入式 android framework 里java调用native,使用JNI机制,ja ...

  6. MQTT事件回调流程

    TLS 如下强调: 1.每个IOT设备应该有一对独有的公钥/私钥 2.SERVER的认证通过SERVER的"root certificate" SSL产生过程: $ openssl ...

  7. tp5模型事件回调函数中不能使用$this

    tp5模型事件回调函数中不能使用$this,使用会报错,涉及到数据库操作使用Db类,不能使用$this->save()之类的方式 如果回调函数中需要使用类内函数,需要将函数定义为static,通 ...

  8. Qt 学习之路 2(19):事件的接受与忽略(当重写事件回调函数时,时刻注意是否需要通过调用父类的同名函数来确保原有实现仍能进行!有好几个例子。为什么要这么做?而不是自己去手动调用这两个函数呢?因为我们无法确认父类中的这个处理函数有没有额外的操作)

    版本: 2012-09-29 2013-04-23 更新有关accept()和ignore()函数的相关内容. 2013-12-02 增加有关accept()和ignore()函数的示例. 上一章我们 ...

  9. vue组件中—bus总线事件回调函数多次执行的问题

    在利用vue组件进行事件监听时发现,如果对N个vue组件实例的bus总线绑定同一事件的回调函数,触发任意组件的对应事件,回调函数至少会被执行N次,这是为什么呢? 为此,调研了普通对象的事件绑定和触发实 ...

随机推荐

  1. zoj1076 Gene Assembly

    这道和zoj1025一样,本质是贪心算法,首先要求任意最长的序列,我们只要保证最长就行,也就是在一幅图中找一个最长的链,首先我们需要根据y排序(输入为x,y),因为y大的肯定在y小的后面,然后就直接贪 ...

  2. zoj1025 Wooden Sticks

    DAG转移,从切题的数量来看是一道水题,给你n个棒,大的可以延续小的,问最少上升子序列的个数. 其实这道题是用贪心来写的,因为这是个有向无环图,到达分叉口,每一条路都要便历,所以每条路应该一样对待,有 ...

  3. JQuery给元素绑定click事件多次执行的解决方法

    原绑定方法: $(".subNavdiv").click(function () { ###### }); 这种方法只会在原click方法中继续添加新方法: 解决办法更改绑定方法为 ...

  4. ACID:数据库事务正确执行的四个基本要素

    ACID,指数据库事务正确执行的四个基本要素的缩写.包含:原子性(Atomicity).一致性(Consistency).隔离性(Isolation).持久性(Durability).一个支持事务(T ...

  5. bootstrap 简易模版

    <!DOCTYPE HTML> <html> <head> <meta http-equiv="Content-Type" content ...

  6. 前端开发面试题收集 css

    什么是CSS盒子模型 页面上的每个元素都被浏览器看做是一个矩形的盒子. 由内容.填充.边框.边界组成. 什么是 css sprite 将多个图片拼接在一个图片中,通过background-positi ...

  7. Spring与Mybatis配置问题

    Spring和Mybatis的整合,主要借助于Spring的依赖注入和控制反转来简化Mybatis的配置,使用两个配置文件[注:此种配置文件网上已经有很多]: spring.xml: <?xml ...

  8. 如何使用getopt()函数解析参数

    最近在写程序的过程中,把一部分时间都花费在程序对参数的处理上.今天听了学长说到getopt函数,才发现原来c里面还有一个专门解决参数处理的函数,查询了相关资料,这里简单总结一下. 使用int main ...

  9. python sys.exit()函数说明

    sys.exit()函数是通过抛出异常的方式来终止进程的,也就是说如果它抛出来的异常被捕捉到了的话程序就不会退出了. #!/usr/bin/python #!coding:utf-8 import s ...

  10. SQL PLUS远程连接

    http://blog.csdn.net/wildin/article/details/5850252 这篇文章无敌了. Oracle sqlplus添加历史记录功能: http://www.cnbl ...