OSG节点更新与事件回调

时间:2022-06-23 16:10:27

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);
}   

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

OSG节点更新与事件回调OSG节点更新与事件回调代码
   
   
   
1 #include < osg / Quat >
2 #include < osg / PositionAttitudeTransform >
3 #include < osg / io_utils >
4 #include < osgDB / ReadFile >
5 #include < osgViewer / Viewer >
6 #include < iostream >
7
8   class RotateCallBack: public osg::NodeCallback
9 {
10   public :
11 RotateCallBack():_rotateZ( 0.0 ) {}
12
13 virtual void operator ()(osg::Node * node, osg::NodeVisitor * nv)
14 {
15 osg::PositionAttitudeTransform * pat =
16 dynamic_cast < osg::PositionAttitudeTransform *> (node);
17 if (pat)
18 {
19 osg::Vec3 vec( 0 , 0 , 1 );
20 osg::Quat quat = osg::Quat(osg::DegreesToRadians(_rotateZ), osg::Z_AXIS);
21 pat -> setAttitude(quat);
22
23 _rotateZ += 0.10 ;
24 }
25
26 traverse(node, nv);
27 }
28
29   private :
30 double _rotateZ;
31 };
32
33
34   class InfoCallBack: public osg::NodeCallback
35 {
36   public :
37 virtual void operator ()(osg::Node * node, osg::NodeVisitor * nv)
38 {
39 osg::PositionAttitudeTransform * pat =
40 dynamic_cast < osg::PositionAttitudeTransform *> (node);
41
42 if (pat)
43 {
44 double angle = 0.0 ;
45 osg::Vec3 axis;
46 pat -> getAttitude().getRotate(angle, axis);
47
48 std::cout << " Node is rotate around the axis( " << axis << " ), "
49 << osg::RadiansToDegrees(angle) << " degrees " << std::endl;
50 }
51
52 traverse(node, nv);
53 }
54 };
55
56
57 int main( int argc, char ** argv)
58 {
59 osg::ArgumentParser argument( & argc, argv);
60 osg::Node * model = osgDB::readNodeFiles(argument);
61 if ( ! model)
62 model = osgDB::readNodeFile( " cow.osg " ) ;
63
64 osg::ref_ptr < osg::PositionAttitudeTransform > pat =
65 new osg::PositionAttitudeTransform();
66 pat -> addChild(model);
67
68 pat -> setUpdateCallback( new RotateCallBack() );
69 pat -> addUpdateCallback( new InfoCallBack() );
70
71 osgViewer::Viewer viewer;
72 viewer.setSceneData(pat. get () );
73 return viewer.run();
74 }

 

 

 

 

 

相关文章