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(); }
轉自:http://www.cnblogs.com/hzhg/archive/2010/12/19/1910340.html