osg的NodeCallback回调使用方法

来源:互联网 发布:美女公寓小说txt淘宝 编辑:程序博客网 时间:2024/06/05 07:00

osg的NodeCallback回调使用方法


#include <Windows.h>
#include <osgViewer/Viewer>
#include <osg/Math> 
#include <osgDB/ReadFile> 
#include <osg/NodeCallback> 
#include <osg/MatrixTransform> 
//从osg::NodeCallBack继承一个新类,实现simpleCallBack的回调
class simpleCallBack:public osg::NodeCallback
{
public:
    simpleCallBack():_angle(0)
    {

    }

    virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
    {
        //创建矩阵转换节点
        osg::ref_ptr<osg::MatrixTransform> mt=dynamic_cast<osg::MatrixTransform*>(node);
        //创建矩阵
        osg::Matrix mx;
        //绕着Z轴旋转
        mx.makeRotate(_angle,osg::Vec3(0.0,0.0,1.0));
        //设置矩阵
        mt->setMatrix(mx);

        _angle+=0.01;

        //继续遍历
        traverse(node,nv);

    }

public:
    //旋转角度
    double _angle;
};

int main()
{
    osg::ref_ptr<osgViewer::Viewer> viewer=new osgViewer::Viewer;
    osg::ref_ptr<osg::Group> root=new osg::Group;

    //读取模型
    osg::ref_ptr<osg::Node> node=osgDB::readNodeFile("cow.osg");

    //创建矩阵变换节点
    osg::ref_ptr<osg::MatrixTransform> mt=new osg::MatrixTransform;
    mt->addChild(node.get());

    //设置更新回调函数
    mt->setUpdateCallback(new simpleCallBack());

    root->addChild(mt.get());
    viewer->setSceneData(root.get());
    viewer->realize();
    viewer->run();
    return 0;
}

 

所有继承自NodeCallback类的子类,可重载operator()方法,对于OSG结点指定更新毁掉为类实例,结点会自动调用类的operator方法进行回调更新。



---------------------------

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

1
2
3
4
5
6
7
8
9
10
//虚函数,回调函数主要操作在此函数中,子类应当重写,已完成相应操作
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);

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

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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(...),比较简单,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
inline void removeNestedCallback(NodeCallback* nc)
{
       if (nc)
       {
                if (_nestedCallback==nc)
                {
                    _nestedCallback = _nestedCallback->getNestedCallback();
                }
                else if (_nestedCallback.valid())
                {
                    _nestedCallback->removeNestedCallback(nc);
                }
        }
}

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

1
2
3
4
5
6
7
8
9
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) {}    virtual void operator()(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:    virtual void operator()(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() );
    viewer.setUpViewOnSingleScreen(0);    viewer.setUpViewInWindow(0, 0, 600, 800,0);
    return viewer.run();}


0 0