osg节点访问和遍历

        OSG中节点的访问使用的是一种访问器模式。一个典型的访问器涉及如下角色:

  • 抽象访问者角色(Visitor)。
  • 具体访问者(Concrete Visitor)。
  • 节点角色(Node)。

OSG中访问者角色为NodeVisitor类,其基本结构如下:  

    NodeVisitor(TraversalMode tm)    // 构造函数,TraversalMode为节点树的遍历方式
                     // TRAVERSE_NONE, 仅当前节点
                     // TRAVERSE_PARENTS, 向当前节点的父节点遍历
                     // TRAVERSE_ALL_CHILDREN, 向子节点遍历
  void traverse(Node& node)        // 向下一个需要访问的节点推进
  void apply(Node& node)          // 虚函数,访问各种节点类型,并执行访问器中的自定义操作
  void apply(Group& node)
  void apply(Geode& node)
  …………

NodeVisitor 只是访问器角色的抽象接口,要使用访问器访问节点并执行自定义操作时,需要继承并重写apply(……)函数实现自定义功能。osg::Node类中的访问接口为:

void accept(NodeVisitor& nv)

        对节点的访问从节点接受一个访问器开始,将一个具体的访问器对象传递给节点,节点反过来执行访问器的apply(...)函数,并将自己传入访问器。可如下简单表示:

void Node::accept(NodeVisitor& nv)  //节点访问与遍历从这个函数开始实施
{
    if (nv.validNodeMask(*this)) 
    {
        nv.pushOntoNodePath(this);  //将节点Node加入到一个Vector中
        nv.apply(*this);
        nv.popFromNodePath();
    }
}

void NodeVisitor::apply(Node& node)  //基类的虚函数中没有实现操作,只需进行遍历
{
    traverse(node);
}

遍历节点树:
 osg::Node类中有两个辅助函数:  

void ascend(NodeVisitor& nv)     // 虚函数,向上一级节点推进访问器
void traverse(NodeVisitor& nv)   // 虚函数,向下一级节点推进访问器

  NodeVisitor的traverse()函数实现如下:  

      inline void traverse(Node& node)
      {
            if (_traversalMode == TRAVERSE_PARENTS) 
        node.ascend(*this);
            else if (_traversalMode != TRAVERSE_NONE) 
        node.traverse(*this);   //调用子集的accept函数,关联访问器进行遍历操作
      }

Node类中的traverse()为空,具体实现是在Group类中

void Group::traverse(NodeVisitor& nv)
{
    for(NodeList::iterator itr=_children.begin();
        itr!=_children.end();
        ++itr)
    {
        (*itr)->accept(nv);
    }
}
示例代码
#include 
#include 
#include 


 using namespace std;
 class InfoVisitor: public osg::NodeVisitor
 {

 public:

    InfoVisitor()
       :osg::NodeVisitor(TRAVERSE_ALL_CHILDREN), _indent(0)

    {}

   virtual void apply(osg::Node& node)
    {

        for(int i = 0; i < _indent; i++)  cout << "    ";
        cout << "[" << _indent << "]"<< node.libraryName()

              << "::" << node.className() << endl;

        _indent++;
        traverse(node);
        _indent--;

       for(int i = 0; i < _indent; i++)  cout << "    ";
        cout << "[" << _indent << "] "<< node.libraryName()
               << "::" << node.className() << endl;

    }

   virtual void apply(osg::Geode& node)
    {

        for(int i = 0; i < _indent; i++)  cout << "    ";
        cout << "[" << _indent << "] "<< node.libraryName()
               << "::" << node.className() << endl;

        _indent++;
        for(unsigned int n = 0; n < node.getNumDrawables(); n++)
         {

            osg::Drawable* draw = node.getDrawable(n);
           if(!draw)
               continue;

             for(int i = 0; i <  _indent; i++)  cout << "    ";
            cout << "[" << _indent << "]" << draw->libraryName() << "::" 
                   << draw->className() << endl;

        }

        traverse(node);
        _indent--;

         for(int i = 0; i < _indent; i++)  cout << "    ";
        cout << "[" << _indent << "]"<< node.libraryName()
                 << "::" << node.className() << endl;

     }

private:
   int _indent;
 };


int main(int argc, char** argv)
 {

   osg::ArgumentParser  parser(&argc, argv);
   osg::Node* root = osgDB::readNodeFiles(parser);

    if(!root)
    {
       root = osgDB::readNodeFile("2.OSGB");
    }

    InfoVisitor infoVisitor;
    if(root)
   {

        root->accept(infoVisitor);
     }

   system("pause");
   return 0;

 }

你可能感兴趣的:(#,osg基础技术点,osg,osg节点遍历)