赞
踩
遍历场景中的节点,可用于在场景渲染的时候找到需要的节点
OSG::Node节点中有Node::accept(NodeVisitor& nv)方法,NodeVisitor中有nv.apply()方法,根据不同节点类型重载apply()方法,实现对不同类型节点的操作,可以实现对当前节点/当前节点的父节点/当前节点的子节点的访问。
OSG中的NodeVisitor实际上采用观察者模式(Observer Pattern)
方式实现。
意图: 对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
编码关键:
优点: 观察者和被观察者是抽象耦合的。
缺点:
NodeVisitor 文件 class OSG_EXPORT NodeVisitor : public virtual Object { public: enum TraversalMode //遍历方式 { TRAVERSE_NONE, TRAVERSE_PARENTS,//访问父节点 TRAVERSE_ALL_CHILDREN,//访问子节点 TRAVERSE_ACTIVE_CHILDREN//访问激活子节点 }; virtual void apply(Drawable& drawable); virtual void apply(Geometry& geometry); virtual void apply(Node& node); virtual void apply(Geode& node); virtual void apply(Billboard& node); ... void NodeVisitor::apply(Node& node) { traverse(node); } void NodeVisitor::apply(Geode& node) { apply(static_cast<Group&>(node)); } /** Method for handling traversal of a nodes. If you intend to use the visitor for actively traversing the scene graph then make sure the accept() methods call this method unless they handle traversal directly.*/ // 访问者主动遍历时调用该方法 实现迭代遍历 inline void traverse(Node& node) { if (_traversalMode==TRAVERSE_PARENTS) node.ascend(*this); else if (_traversalMode!=TRAVERSE_NONE) node.traverse(*this); } // } Node 文件 typedef std::vector< Node* > NodePath; class OSG_EXPORT Node : public Object { public: virtual void accept(NodeVisitor& nv); inline void pushOntoNodePath(Node* node) { if (_traversalMode!=TRAVERSE_PARENTS) _nodePath.push_back(node); else _nodePath.insert(_nodePath.begin(),node); } inline void popFromNodePath() { if (_traversalMode!=TRAVERSE_PARENTS) _nodePath.pop_back(); else _nodePath.erase(_nodePath.begin()); } /** Traverse upwards : calls parents' accept method with NodeVisitor.*/ virtual void ascend(NodeVisitor& nv); /** Traverse downwards : calls children's accept method with NodeVisitor.*/ virtual void traverse(NodeVisitor& /*nv*/) {} } Node.cpp 文件 void Node::accept(NodeVisitor& nv) { if (nv.validNodeMask(*this)) { nv.pushOntoNodePath(this); nv.apply(*this); nv.popFromNodePath(); } } Group 文件 class OSG_EXPORT Group : public Node { public : virtual void traverse(NodeVisitor& nv); void Group::traverse(NodeVisitor& nv) { for(NodeList::iterator itr=_children.begin(); itr!=_children.end(); ++itr) { (*itr)->accept(nv); } } } //Switch 文件 class OSG_EXPORT Switch : public Group { public : virtual void traverse(NodeVisitor& nv); void Switch::traverse(NodeVisitor& nv) { if (nv.getTraversalMode()==NodeVisitor::TRAVERSE_ACTIVE_CHILDREN) { for(unsigned int pos=0;pos<_children.size();++pos) { if (_values[pos]) _children[pos]->accept(nv); } } else { Group::traverse(nv); } } }
class VisitorNodePath : public osg::NodeVisitor { public: VisitorNodePath() :osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) {} //注意Node是Group的父类,若不重载Group的apply方法,则也会进入Node的apply方法 void apply(osg::Node& node) { std::cout << "Apply node: " << node.getName() << std::endl; if (node.getName() == "glider")//通过名字确定节点 { //Do something } traverse(node); } } int main() { osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer; viewer->addEventHandler(new ChangeWindow()); osg::ref_ptr<osg::Group> root = new osg::Group; osg::ref_ptr<osg::Node> glider = osgDB::readNodeFile("glider.osg"); root->setName("root");//添加名字方便遍历 glider->setName("glider"); root->addChild(glider); viewer->setSceneData(root); VisitorNodePath vn; root->accept(vn); return viewer->run(); }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。