OSG 节点访问器(NodeVisitor)
前言:学习OSG还有点痛苦,大概是对于新东西学起来都是痛苦的吧!
osg::NodeVisitor 类:
※ NodeVisitor( TraversalModel tm);
构造函数;传入参数为节点树的遍历方式:
TRAVERSE_NONE, 仅当前节点;
TRAVERSE_PARENTS, 向当前节点的父节点遍历;
TRAVERSE_ALL_CHILDREN, 向子节点遍历;
※ void traverse(Node& node);
向下一个需要访问的节点推进;
※ void apply(Node& node)
※ void apply(Group& node)
※ void apply(Geode& node)
虚函数,访问各种类型的节点,并执行访问器中自定义的节点操作;
osg::Node 类:
※ void accept(NodeVisitor& nv);
接受一个访问器;
对于节点的访问是从节点接收一个访问器开始的,用户执行某个节点的accept()函数,将一个具体的访问器对象传递给节点。
第二步,节点反过来执行访问器的apply()函数,并将自身传入访问器。
这两步的实现过程可以用一行十分简单的函数代码来表达:
void Node::accept(NodeVisitor& nv)
{
nv.apply(*this);
}
最后,在具体访问器对象中重写的apply()函数中,执行节点的具体访问操作。使用一个自定义访问器UserVisitor来访问已知场景节点树:
UserVisitor visitor;
subgraph->accept(visitor);
例子:节点属性访问器:
#include <osg/Node>
#include <osgDB/ReadFile>
#include <iostream>
class InfoVisitor : public osg::NodeVisitor
{
public:
InfoVisitor(): osg::NodeVisitor(TRAVERSE_ALL_CHILDREN), _indent(0){} //向子节点遍历
virtual void apply( osg::Node &node){ //获取访问节点对象,并执行自定义节点操作
//当访问到默认的Node节点时,使用该函数打印节点的名称
//并根据节点层次适当使用_indent缩进
for ( int i = 0; i < _indent; ++i)
{
std::cout<< " ";
}
std::cout<< "["<< _indent + 1<< "]"<< node.libraryName()
<< "::"<< node.className()<< std::endl;
_indent++;
traverse( node); //向下一个需要的节点推进
_indent--;
}
//当访问到Geode节点时,不仅打印叶节点的名称属性,还打印叶节点所包含的所有可绘制体的名称
virtual void apply( osg::Geode& node){
for ( int i = 0; i < _indent; ++i)
{
std::cout<< " ";
}
std::cout<< "["<< _indent + 1<<"]"<< node.libraryName()
<< "::"<< node.className()<< std::endl;
for (unsigned int n = 0; n < node.getNumDrawables(); ++n)
{
osg::Drawable* drawable = node.getDrawable(n);
if(!drawable) continue;
for(int i = 0; i <= _indent; ++i){
std::cout<< " ";
}
std::cout<< drawable->libraryName()<< "::"
<< drawable->className()<< std::endl;
}
_indent ++;
traverse( node);
_indent --;
}
protected:
int _indent;
};
int main()
{
osg::ref_ptr<osg::Node> root = osgDB::readNodeFile("axes.osgt");
InfoVisitor infoVisitor;
if (root)
{
root->accept( infoVisitor); //接受自定义访问器
}
return 0;
}
root->accept( infoVisitor);
谁调用accept,就以此为根结点向下进行深度优先遍历,如果想向上遍历,就将traverse()函数改为ascend()函数;
运行截图: