osg自带的遍历器,关键接口:
- apply
void NodeVisitor::apply(Node& node)
{
traverse(node);
}
void NodeVisitor::apply(Drawable& drawable)
{
apply(static_cast<Node&>(drawable));
}
重载函数,根据类型进行不同的接口,默认都调用apply(Node& node);我们若需要对不同类型进行操作,只需重写自己需要的类型即可。
2. traverse
inline void traverse(Node& node)
{
if (_traversalMode==TRAVERSE_PARENTS) node.ascend(*this);
else if (_traversalMode!=TRAVERSE_NONE) node.traverse(*this);
}
由源码可知其最后调用的是每个不同类中的traverse,跟踪一下(group为例)
void Group::traverse(NodeVisitor& nv)
{
for(NodeList::iterator itr=_children.begin();
itr!=_children.end();
++itr)
{
(*itr)->accept(nv);
}
}
可见其遍历了自己的子节点,并进行遍历。
- accept
void Node::accept(NodeVisitor& nv)
{
if (nv.validNodeMask(*this))
{
nv.pushOntoNodePath(this);
nv.apply(*this);
nv.popFromNodePath();
}
}
由源码可以调用了apply();
由上面三个接口便可以完成一个完整的遍历过程,其中NodeVisitor的参数可以设置遍历模式,TraversalMode::TRAVERSE_ACTIVE_CHILDREN遍历所有活动的子节点
TraversalMode::TRAVERSE_PARENTS遍历所有的父节点
TraversalMode::TRAVERSE_ALL_CHILDREN遍历所有的子节点
以下为示例代码:
#include "OsgCommon.h"
class MyNodeVisitor:public osg::NodeVisitor
{
public:
MyNodeVisitor() :osg::NodeVisitor(TraversalMode::TRAVERSE_ACTIVE_CHILDREN){}
virtual void apply(osg::Geode & node)
{
int num=node.getNumDrawables();
for (int i=0;i<num;i++)
{
osg::Drawable *geo = node.getDrawable(i);
osg::ref_ptr<osg::Geometry> gm = dynamic_cast<osg::Geometry*>(geo);
osg::Vec3Array *vx = dynamic_cast<osg::Vec3Array*>(gm->getVertexArray());
for (int j=0;j<vx->size();j++)
{
osg::Vec3d pos= vx->at(j);
osg::ref_ptr<osg::Geode>temp = new osg::Geode;
temp->addDrawable(new osg::ShapeDrawable(new osg::Sphere(pos, 0.02)));
group->addChild(temp);
}
}
traverse(node);
}
void setGroup(osg::Group *gp)
{
group = gp;
}
private:
osg::ref_ptr<osg::Group> group;
};
int main()
{
osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer;
osg::ref_ptr<osg::Node> glider = osgDB::readNodeFile("glider.osg");
MyNodeVisitor bv;
osg::ref_ptr<osg::Group> group = new osg::Group;
group->setName("root");
bv.setGroup(group);
glider->accept(bv);
group->addChild(glider);
viewer->setSceneData(group);
return viewer->run();
}