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)
{
nv.apply(*ths) ;
}
遍历节点树:
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);
}
示例如下:
1 #include <osg/Node>
2 #include <osgDB/ReadFile>
3 #include <iostream>
4
5 using namespace std;
6
7 class InfoVisitor: public osg::NodeVisitor
8 {
9 public:
10 InfoVisitor()
11 :osg::NodeVisitor(TRAVERSE_ALL_CHILDREN), _indent(0)
12 {}
13
14 virtual void apply(osg::Node& node)
15 {
16 for(int i = 0; i < _indent; i++) cout << " ";
17 cout << "[" << _indent << "]"<< node.libraryName()
18 << "::" << node.className() << endl;
19
20 _indent++;
21 traverse(node);
22 _indent--;
23
24 for(int i = 0; i < _indent; i++) cout << " ";
25 cout << "[" << _indent << "] "<< node.libraryName()
26 << "::" << node.className() << endl;
27 }
28
29 virtual void apply(osg::Geode& node)
30 {
31 for(int i = 0; i < _indent; i++) cout << " ";
32 cout << "[" << _indent << "] "<< node.libraryName()
33 << "::" << node.className() << endl;
34
35 _indent++;
36
37 for(unsigned int n = 0; n < node.getNumDrawables(); n++)
38 {
39 osg::Drawable* draw = node.getDrawable(n);
40 if(!draw)
41 continue;
42 for(int i = 0; i < _indent; i++) cout << " ";
43 cout << "[" << _indent << "]" << draw->libraryName() << "::"
44 << draw->className() << endl;
45 }
46
47 traverse(node);
48 _indent--;
49
50 for(int i = 0; i < _indent; i++) cout << " ";
51 cout << "[" << _indent << "]"<< node.libraryName()
52 << "::" << node.className() << endl;
53 }
54 private:
55 int _indent;
56 };
57
58 int main(int argc, char** argv)
59 {
60 osg::ArgumentParser parser(&argc, argv);
61 osg::Node* root = osgDB::readNodeFiles(parser);
62
63 if(!root)
64 {
65 root = osgDB::readNodeFile("avatar.osg");
66 }
67
68 InfoVisitor infoVisitor;
69 if(root)
70 {
71 root->accept(infoVisitor);
72 }
73
74 system("pause");
75 return 0;
76 }