OSG 节点访问器(NodeVisitor)

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()函数;

运行截图:

在 OpenSceneGraph (OSG) 中,您可以使用 `NodeVisitor` 类来遍历场景图的节点,并对每个子节点进行旋转和平移操作。下面是一个示例代码片段,展示了如何使用 `NodeVisitor` 来对子节点进行旋转和平移: ```cpp #include <osg/NodeVisitor> #include <osg/MatrixTransform> #include <osg/Geode> #include <osgDB/ReadFile> // 自定义的 NodeVisitor 子类 class MyVisitor : public osg::NodeVisitor { public: MyVisitor() : osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {} // 重写 apply 方法,在遍历每个节点时执行操作 virtual void apply(osg::Node& node) { // 在这里添加旋转和平移的代码 osg::MatrixTransform* transform = dynamic_cast<osg::MatrixTransform*>(&node); if (transform) { // 旋转节点 osg::Matrix rotationMatrix; rotationMatrix.makeRotate(osg::Quat(osg::PI / 4, osg::Vec3(0, 0, 1))); // 绕 Z 轴旋转 45 度 transform->setMatrix(transform->getMatrix() * rotationMatrix); // 平移节点 osg::Matrix translationMatrix; translationMatrix.makeTranslate(osg::Vec3(1, 0, 0)); // 沿 X 轴平移 1 单位 transform->setMatrix(transform->getMatrix() * translationMatrix); } // 继续遍历子节点 traverse(node); } }; int main() { // 加载场景文件 osg::ref_ptr<osg::Node> scene = osgDB::readNodeFile("path/to/your/scene.osg"); // 创建 MyVisitor 对象并应用于场景节点 MyVisitor visitor; scene->accept(visitor); // 运行场景图的渲染循环... return 0; } ``` 在上面的示例中,我们首先定义了一个名为 `MyVisitor` 的自定义 `NodeVisitor` 子类。在 `apply` 方法中,我们使用 `dynamic_cast` 操作将节点转换为 `osg::MatrixTransform` 类型,然后对其进行旋转和平移操作。然后,我们调用 `traverse` 方法继续遍历子节点。 在 `main` 函数中,我们加载场景文件并创建了 `MyVisitor` 对象,并将其应用于场景节点。然后,您可以根据需要执行场景图的渲染循环。 请注意,上述示例中的旋转和平移操作仅作为演示。您可以根据实际需求修改旋转和平移的参数。同时,您可能需要添加其他条件来筛选出特定的节点进行操作。 希望对您有所帮助!如果您有任何进一步的问题,请随时提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值