OSG节点更新与事件回调

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(0, 0, 1);
       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();
 }
时间: 2024-08-02 15:18:17

OSG节点更新与事件回调的相关文章

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

OSG使用更新回调来更改模型 转自:http://blog.sina.com.cn/s/blog_668aae7801017gl7.html 使用回调类实现对场景图形节点的更新.本节将讲解如何使用回调来实现在每帧的更新遍历(update traversal)中进行节点的更新. 回调概览用户可以使用回调来实现与场景图形的交互.回调可以被理解成是一种用户自定义的函数,根据遍历方式的不同(更新update,拣选cull,绘制draw),回调函数将自动地执行.回调可以与个别的节点或者选定类型(及子类型)

unity3d动画帧事件回调脚本必须直接挂在模型上

unity3d动画帧事件回调脚本必须直接挂在模型上,即与Animator同级,不能挂接在模型的父节点或者子节点,否则无法找到回调函数 以上在idle动作中新增帧事件skill,回调模型脚本中的skill()函数

使用aicp实现事件回调模式

相对于asio事件等待池aiop的reactor模式,基于proactor模式的事件回调池aicp封转的更加的上层. 在类unix系统上 底层是基于aiop的实现,在一个线程里面进行事件等待,然后分发所有事件,在worker中处理完后调用回调返回到上层. 并对不同系统的aiop支持力度,进行针对性优化. 如果aiop支持边缘触发(例如:epoll.kqueue),尽量启用边缘触发,以减少系统api的频繁调用. 使用sendfile对发送文件进行优化 针对linux系统,启用native file

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

我们在自定义view的时候,通常要考虑view的封装复用,所以如何把view的事件回调给Controller就是个需要好好考虑的问题, 一般来说,可选的方式主要有target-action和delegate,以及这次要强烈推荐的block. target-action和delegate方式有个很不方便的地方,就是配置代码和action代码不在同一个地方,你肯定要多写一个selector方法或者delegate方法,这就带来一个问题,一旦代码比较长或者selector方法比较多,找起来就很不方便.

CodeForces 444C 节点更新求变化值的和

http://vjudge.net/problem/viewProblem.action?id=51622 题目大意: 给定一列n个数字,最初赋予值1到n 两个操作:1.将区间[l,r]内的数改为x,则这区间中所有数的改变值进行求和,即ans=abs(a[l]-x)+abs[a[l+1]-x).....abs(a[r]-x),但不要求输出 2.需要将刚才要求得到的区间改变值输出出来 这里我们利用一个color[]数组相当于给这堆数进行染色,当某个区间内的赋予的值相等时,我们可以看做有一个相同的c

jquery中动态新增的元素节点无法触发事件解决办法

在使用jquery中动态新增的元素节点时会发现添加的事件是无法触发的,我们下面就为各位来详细的介绍此问题的解决办法. 比如做一个ajax读取留言列表的时候,每条留言后面有个回复按钮,class为“reply”,如果你用的是$(".reply").click(function(){ //do something... }),想必后面通过ajax加载进来的列表中的回复按钮,点击事件会失效. 其实最简单的方法就是直接在标签中写onclick="",但是这样写其实是有点lo

事件回调

Listener是一个接口 An event listener is an interface in the View class that contains a single callback method. These methods will be called by the Android framework when the View to which the listener has been registered is triggered by user interaction w

AngularJS之基础-4 DI(控制器参数、监听)、指令(模板包含、节点控制)、事件绑定

一.DI-控制器参数 $scope - 在js和html之间传递数据 - 仅在控制器作用域内有效 $element - 是一个jQuery对象 - 作用域控制器所在的html元素 - 在js中,通过$element获取DOM对象 - var e = $element.children().eq(0); - $scope.w = e.width(); - $scope.h = e.height(); $http - http协议请求 - $http.get(url).success(functio

解决jquery中动态新增的元素节点无法触发事件的问题有两种解决方法

解决jquery中动态新增的元素节点无法触发事件的问题有两种解决方法,如下: 为了达到更好的演示效果,假设在某个页面的body下有以下结构的代码: ? 1 2 3 4 5 6 7 8 9 10 11 <p id="pLabel">新加一条</p> <ul id="ulLabel">  <li class="liLabel">aaa1</li>  <li class="li