先看看全流程
先抄一抄节点访问器NodeVisitor的工作原理.当我们执行节点的accept(NodeVisitor* nv)函数时,当前节点自动调哟个NodeVisitor::apply方法,将自身的信息传递给节点访问器nv,由它负责执行相应的处理工作;然后节点将自动执行Node::traverse函数,调用所有子节点的accept函数,从而实现了节点数的遍历。在遍历的过程中,每个节点都会调用NodeVisitor::apply,将自身的指针传递给访问器,因此,NodeVisitor的每个派生类都会重载针对各个节点的apply函数,以实现针对不同类型节点的访问操作。
来个最简单的不向下走,调用
可以看到,apply()是accept调用的
下一步接下来递归调用
#include <osg/NodeVisitor>
#include <iostream>
#include <osg/Group>
#include <osg/Geode>
using namespace osg;
class myVisitor : public osg::NodeVisitor
{
public:
myVisitor() : NodeVisitor(TRAVERSE_ALL_CHILDREN)
{
}
virtual void apply(Node& node)
{
std::string strName = node.getName();
std::cout << strName << std::endl;
traverse(node);
}
virtual void apply(Group& grp)
{
std::string strName = grp.getName();
std::cout << strName << std::endl;
traverse(grp);
}
virtual void apply(Geode& geode)
{
std::string strName = geode.getName();
std::cout << strName << std::endl;
traverse(geode);
}
};
int main()
{
osg::ref_ptr<osg::Node> node = new osg::Node;
node->setName("node");
osg::ref_ptr<osg::Geode> geode = new osg::Geode;
geode->setName("geode");
osg::ref_ptr<osg::Group> group = new osg::Group;
group->addChild(node.get());
group->addChild(geode.get());
group->setName("group");
myVisitor nv;
group->accept(nv);
return 0;
}
运行结果
继续抄抄电子书,筛选访问器(cullvisitor)的重载函数针对Geode,Billboard,LightSource,ClipNode,TexGenNode,Group,Transform,Projection,Switch,LOD,ClearNode,Camera,OccluderNode,OcclusionQueryode以及通用的Node类节点执行了相应的筛选工作
下面进行cullVisitor的使用
可以通过Node::setCullingActive()保持节点Node永远不会被删除
看看几个相关的成员变量,
电子书上介绍了其它几种。
它的不同之处在于
对于Geode节点
不同的地方如下
当场景树中出现一个摄像机节点时它以下的场景子树将按照这恶摄像机的筛选、视口、观察矩阵和投影矩阵设置进行显示。我们也可以使用此摄像机指向另一个图形设备(窗口),Camera节点的特性使得HUD文字,鹰眼图等效果都可以在OSG的场景中轻松实现。
除去类似的步骤,具体如下
最后,进行例行的弹出
总结下,Cullvisitor用于构建OSG系统的状态树和渲染树,并在这一过程中使用isCulled函数剔除了场景中对渲染没有助益的对象(在下次遍历时,还会重新审核所有的节点,上次被剔除的节点可能在新的循环中将被显示出来)