OSG学习:空间变换节点和开关节点示例

本文介绍OpenSceneGraph(OSG)中空间变换节点的应用,包括AutoTransform、MatrixTransform和PositionAttitudeTransform三种节点的使用方法,以及如何通过Switch节点实现模型的动态切换。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

以下内容来自: 

1、《OpenSceneGraph三维渲染引擎设计与实践》王锐 钱学雷 清华大学出版社

2、自己的总结

下载完整工程OSG_1_NodeTransform、OSG_2_NodeSwitch

创建C++项目后,首先需要配置OSG环境。具体步骤看OSG学习:WIN10系统下OSG+VS2017编译及运行第六步:新建OSG项目测试

1.空间变换节点

根据用户视点自动进行变换的AutoTransform节点;

直接使用矩阵进行变换的MatrixTransform节点;

使用位移、旋转和缩放值进行变换的PositionAttitudeTransform节点。

// stdafx.h

#include <osg/AutoTransform> //自动变换节点类,使节点自动对齐于摄像机或屏幕。
#include <osg/MatrixTransform> //移动节点的矩阵类,最常用的移动节点的类。可随动、旋转控制节点。
#include <osg/PositionAttitudeTransform> //位置变换节点类,提供模型的位置变换、大小缩放、原点位置的设置、坐标系的变换
#include <osgViewer/Viewer> //视窗管理库,显示场景。为单独的场景保存一个单独的view,每个单独场景的程序都有一个Viewer
#include <osgDB/ReadFile> //数据读写库
//.cpp

#include "stdafx.h"

/*创建自动变换节点对象AutoTransform,使其始终面对屏幕,即用户视点*/
osg::Transform *createAutoTransform(double posX, osg::Node *model)
{
	//在osg智能指针中进行定义
	osg::ref_ptr<osg::AutoTransform> at = new osg::AutoTransform;
	at->setAutoRotateMode(osg::AutoTransform::ROTATE_TO_SCREEN); //设置自动变换模式,始终面对屏幕
	at->setPosition(osg::Vec3(posX, 0.0, 0.0)); //设置模型的位置
	at->addChild(model);
	//新建对象作为函数结果返回时,应该返回release(),并尽快引入到别的场景中,否则发生内存泄露
	return at.release();
}

/*创建空间变换矩阵节点对象MatrixTransform,并使其沿Z轴逆时针旋转45度*/
osg::Transform *createMatrixTransform(double posX, double rotateZ, osg::Node *model)
{
	//在osg智能指针中进行定义
	osg::ref_ptr<osg::MatrixTransform> mt = new osg::MatrixTransform;
	//设置空间变换矩阵的内容,格式都为setMatrix(osg::Matrix::translate(x, y, z)),其中osg::Matrix::Scale和osg::Matrix::rotate也可以被用在其中,并且可以相乘叠加
	//设置mat矩阵后把node加入到mat中,再把mat加入到Group中,在这个例子中model在main函数中就已加入到Group中了
	mt->setMatrix(osg::Matrix::rotate(rotateZ, osg::Z_AXIS) *osg::Matrix::translate(posX, 0.0, 0.0));
	mt->addChild(model);
	//新建对象作为函数结果返回时,应该返回release(),并尽快引入到别的场景中,否则发生内存泄露
	return mt.release();
}

/*创建位置姿态节点对象PositionAttitudeTransform,使其沿Z轴顺时针旋转45度*/
osg::Transform *createPositionAttitudeTransform(double posX, double rotateZ, osg::Node *model)
{
	//在osg智能指针中进行定义
	osg::ref_ptr<osg::PositionAttitudeTransform> pat = new osg::PositionAttitudeTransform;
	pat->setPosition(osg::Vec3(posX, 0.0, 0.0));
	pat->setAttitude(osg::Quat(rotateZ, osg::Z_AXIS));
	pat->addChild(model);
	//新建对象作为函数结果返回时,应该返回release(),并尽快引入到别的场景中,否则发生内存泄露
	return pat.release();
}

int main(int argc, char **argv)
{
	//读取main函数参数以及外部参数的类,会自动识别外部参数正确与否
	//它是一个单独的类
	//ArgumentParser(int *argc, char **argv)构造函数,传入参数为main的两个参数,前者代表命令行参数个数,后者代表参数的具体值
	osg::ArgumentParser arguments(&argc, argv);
	//如果外部参数正确,则使用osgDB::readNodeFile读取该模型,否则读取本地坐标系模型文件axes.osgt
	osg::Node *model = osgDB::readNodeFiles(arguments);
	if (!model)
		model = osgDB::readNodeFile("axes.osgt");

	//将3个节点加入到场景根节点中,同时它们的子节点均为一个预设的模型节点model,因此实现了场景中叶节点的共享
	osg::ref_ptr<osg::Group> root = new osg::Group;
	//把新创建的节点加入到Group中
	root->addChild(createMatrixTransform(-5.0, osg::PI / 4, model));
	root->addChild(createAutoTransform(0.0, model));
	root->addChild(createPositionAttitudeTransform(5.0, -osg::PI / 4, model));

	//实例化显示图像的类osgViewer::Viewer
	osgViewer::Viewer viewer;
	//设置viewer显示的场景
	viewer.setSceneData(root.get());
	//开始执行渲染操作,返回值一般为1,程序退出或出错返回0
	return viewer.run();
}

2、开关节点

// stdafx.h

#include <osg/Switch> //控制子类的显示与隐藏,这种隐藏不消耗内存
#include <osgViewer/Viewer> //视窗管理库,显示场景。为单独的场景保存一个单独的view,每个单独场景的程序都有一个Viewer
#include <osgDB/ReadFile> //数据读写库
//.cpp

#include "stdafx.h"

/*从NodeCallback类派生,并重构执行函数operator(),实现自定义的节点回调功能
定义名为CessnaCallback的节点更新回调,它使用getFrameNumber()随时取得当前的运行帧数
当帧数大于预先设定的切换值120时,使用setValue()执行子节点的切换*/
class CessnaCallback :public osg::NodeCallback
{
public:
	static const int _fireStartFrame = 120; //起火开始时间,即切换模型时的运行帧数,秒

	//虚函数。当回调动作发生时,将会执行这一操作符的内容,并将节点和访问器对象作为参数传入
	//重载第一个(),而(osg::Node *node, osg::NodeVisitor *nv)是该重载函数的参数表,前者为场景节点,后者为访问器对象,即访问器当前访问的节点
	virtual void operator()(osg::Node *node, osg::NodeVisitor *nv)
	{
		//dynamic_cast将一个基类对象指针(或引用)cast到继承类指针,dynamic_cast会根据基类指针是否真正指向继承类指针来做相应处理
		//dynamic_cast <type-id> (expression) 该运算符把expression转换成type-id类型的对象,Type-id 必须是类的指针、类的引用或者void*,它可以在执行期决定真正的类型
		//如果type-id是类指针类型,那么expression也必须是一个指针,如果 type-id 是一个引用,那么 expression 也必须是一个引用
		//dynamic_cast主要用于类层次间的上行转换(和static_cast效果一样)和下行转换(具有类型检查的功能,比static_cast更安全),还可以用于类之间的交叉转换
		osg::Switch *cessnaSwitch = dynamic_cast<osg::Switch *>(node); 
		if (cessnaSwitch &&nv)
		{
			//实例化类osg::FrameStamp
			//getFrameStamp()获取节点的帧数信息
			const osg::FrameStamp *frameStamp = nv->getFrameStamp();
			if (frameStamp)
			{
				//比较起火时的帧数和当前帧数,120帧以后关闭飞机模型cessna.osg开启起火后飞机模型cessnafire.osg
				if (_fireStartFrame < frameStamp->getFrameNumber()) //获取上一帧的帧号,即时间,秒
				{
					//setValue()执行子节点的切换
					cessnaSwitch->setValue(0, false);
					cessnaSwitch->setValue(1, true);
				}
			}
		}
		traverse(node, nv); //向下一个需要访问的节点推进
	}
};

int main(int argc, char **argv)
{
	//在osg智能指针中定义开关节点
	osg::ref_ptr<osg::Switch> root = new osg::Switch;
	//读取模型并将之添加到开关节点中
	//默认开启子节点飞机模型cessna.osg,默认关闭(切换后开启)子节点起火后的飞机模型cessnafire.osg
	root->addChild(osgDB::readNodeFile("cessna.osg"), true);
	root->addChild(osgDB::readNodeFile("cessnafire.osg"), false);
	//setUpdateCallback自定义回调类CessnaCallback作为更新回调传递给节点,设置人机交互回调为node->setEventCallback(new CessnaCallback)
	root->setUpdateCallback(new CessnaCallback);

	//实例化显示图像的类osgViewer::Viewer
	osgViewer::Viewer viewer;
	//设置viewer显示的场景
	viewer.setSceneData(root.get());
	//开始执行渲染操作,返回值一般为1,程序退出或出错返回0
	return viewer.run();
}

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值