场景交互与场景漫游-场景漫游器(6)

 场景漫游

        在浏览整个三维场景时,矩阵变换是非常关键的,通过适当的矩阵变换可以获得各种移动或者渲染效果。因此,在编写自己的场景漫游操作器时,如何作出符合逻辑的矩阵操作器是非常重要的,但这对初学者来说还是有一定难度的。在 OSG 中,已经提供了一个矩阵操作器的康的接口,即为osgGA::MatrixManipulator。在前面讲到的很多操作器都继承自osgGA:MatrixManipulator

编写一个自己的操作器,需要处理的主要问题如下:

  • 鼠标或键盘按下时该怎么处理?
  • 如何得到当前的矩阵及其逆矩阵?
  • 如何控制当前的速度?
  • 是否开启碰撞检测?
  • 如何设置出生位置?

        这些都是做一些简单场景漫游时需要面对的问题。只有充分理解了读者需要解决什么,才会知道解决需要做什么,至于怎么做只是时间问题,只要读者肯花时间研究源代码,也可以解决。编写自定义场景漫游操作器的主要步骤如下:

  • 编写一个继承自osgGA:GUIEventHandler 类的新类
  • 重载handlel()及相关矩阵变换函数,注意在handle()中添加合适的事件处理函数,并指定执行相关的动作。
  • 进行碰撞检测。碰撞检测的方法有很多,如果读者想达到精确的碰撞检测,可以使用一些经典的物理学引擎如牛顿引擎。在第 8.2.5节的示例中只是使用一种非常简单的碰撞检测方法如图8-17所示:

图8-17简单碰撞检测

  • 关联该操作器到当前视图场景中,没有这一步,在OSG 的场中是不会自动启动该操作器的,关联很简单,代码如下:

        viewer->setCameraManipulator(camera):;

        通过学习上面的简单步骤,相信读者也可以完成一个操作器的编写,只要明白原理是如何实现的,结果或许就不那么重要了。下面还是看一下示例,不然可能会不懂其中的一些细节。

自定义操作器场景漫游示例

        自定义操作器场景漫游示例的代码如程序清单 8-8 所示

/******************************************* 自定义漫游器示例 *************************************/
/*
	编码时遇到无法打开文件osgGA / MatrixManipulator错误,
	无法打开包括文件 : “osgGA / MatrixManipulator” : No such file or directory
	解决办法:
	新版本中已经改名为CameraManipulator
	将MatrixManipulator改成CameraManipulator即可
	并且要#include <osgGA/CameraManipulator>
*/
class TravelManipulator : public osgGA::CameraManipulator
{
public:
	// 构造函数
	TravelManipulator();

	// 析构函数
	~TravelManipulator(void);

	// 把漫游加入到场景中
	static TravelManipulator *TravelToScene(osg::ref_ptr<osgViewer::Viewer> viewer);

private:
	osg::ref_ptr<osgViewer::Viewer> m_pHostViewer;

	// 移动速度
	float m_fMoveSpeed;
	osg::Vec3 m_vPosition;
	osg::Vec3 m_vRotation;

public:
	// 鼠标左键是否按下
	bool m_bLeftButtonDown;

	// 鼠标XY
	float m_fpushY;
	float m_fpushX;

	// 设置矩阵
	virtual void setByMatrix(const osg::Matrixd &matrix);

	// 设置逆矩阵
	virtual void setByInverseMatrix(const osg::Matrixd &matrix);

	// 得到矩阵
	virtual osg::Matrixd getMatrix(void) const;

	// 得到逆矩阵
	virtual osg::Matrixd getInverseMatrix(void)const;


	// 事件处理函数
	virtual bool handle(const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter &aa);

	// 屏幕角度
	float m_fAngle;

	// 位置变换函数
	void ChangePosition(osg::Vec3 &delta);

	// 碰撞检测是否开启
	bool m_bPeng;

	// 设置速度
	float getSpeed();

	void setSpeed(float &);

	// 设置起始位置
	void SetPosition(osg::Vec3 &position);

	osg::Vec3 GetPosition();
};

void travelManipulator_8_8(const string &strDataFolder);

/******************************************* 自定义漫游器示例 *************************************/
TravelManipulator::TravelManipulator() 
	:m_fMoveSpeed(1.0f)
	, m_bLeftButtonDown(false)
	, m_fpushX(0)
	, m_fAngle(2.5)
	, m_bPeng(true)
	, m_fpushY(0)
{
	m_vPosition = osg::Vec3(-22.0f, -274.0f, 100.0f);
	m_vRotation = osg::Vec3(osg::PI_2, 0.0f, 0.0f);
}

TravelManipulator::~TravelManipulator()
{
}

// 把漫游器加入到场景中
TravelManipulator* TravelManipulator::TravelToScene(osg::ref_ptr<osgViewer::Viewer> viewer)
{
	TravelManipulator *camera = new TravelManipulator;
	viewer->setCameraManipulator(camera);
	camera->m_pHostViewer = viewer;

	return camera;
}

// 设置矩阵
void TravelManipulator::setByMatrix(const osg::Matrixd& matrix)
{

}

// 设置逆矩阵
void TravelManipulator::setByInverseMatrix(const osg::Matrixd& matrix)
{

}

// 得到矩阵
osg::Matrixd TravelManipulator::getMatrix()const
{
	osg::Matrixd mat;
	mat.makeRotate(m_vRotation._v[0], osg::Vec3(1.0f, 0.0f, 0.0f), 
		m_vRotation._v[1], osg::Vec3(0.0f, 1.0f, 0.0f),
		m_vRotation._v[2], osg::Vec3(0.0f, 0.0f, 1.0f));
	return mat * osg::Matrixd::translate(m_vPosition);
}

// 得到逆矩阵
osg::Matrixd TravelManipulator::getInverseMatrix()const
{
	osg::Matrixd mat;
	mat.makeRotate(m_vRotation._v[0], osg::Vec3(1.0f, 0.0f, 0.0f),
		m_vRotation._v[1], osg::Vec3(0.0f, 1.0f, 0.0f),
		m_vRotation._v[2], osg::Vec3(0.0f, 0.0f, 1.0f));
	return osg::Matrixd::inverse(mat * osg::Matrixd::translate(m_vPosition));
}

// 事件处理函数
bool TravelManipulator::handle(const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter &aa)
{
	// 得到鼠标的位置
	float mouseX = ea.getX();
	float mouseY = ea.getY();

	int iEventType = ea.getEventType();
	switch (iEventType)
	{
		case (osgGA::GUIEventAdapter::KEYDOWN) :
		{
			// 空格键
			if (ea.getKey() == 0x20)
			{
				//us.requestRedraw();
				//us.requestContinuousUpdate(false);
				return true;
			}
			// 上移动
			if (ea.getKey() == 0xFF50)
			{
				ChangePosition(osg::Vec3(0, 0, m_fMoveSpeed));
				return true;
			}
			// 下移动
			if (ea.getKey() == 0xFF57)
			{
				ChangePosition(osg::Vec3(0, 0, -m_fMoveSpeed));
				return true;
			}
			// 增加速度
			if (ea.getKey() == 0x2B)
			{
				m_fMoveSpeed += 1.0f;
				return true;
			}
			// 减少速度
			if (ea.getKey() == 0x2D)
			{
				m_fMoveSpeed -= 1.0f;
				if (m_fMoveSpeed < 1.0f)
				{
					m_fMoveSpeed = 1.0f;
				}
				return true;
			}
			// 前进
			if (ea.getKey() == 0xFF52 || ea.getKey() == 0x57 || ea.getKey() == 0x77)//up
			{
				ChangePosition(osg::Vec3(0, m_fMoveSpeed * sinf(osg::PI_2 + m_vRotation._v[2]), 0));
				ChangePosition(osg::Vec3(m_fMoveSpeed * sinf(osg::PI_2 + m_vRotation._v[2]), 0, 0));

				return true;
			}

			// 后退
			if (ea.getKey() == 0xFF54 || ea.getKey() == 0x53 || ea.getKey() == 0x73)//down
			{
				ChangePosition(osg::Vec3(0, -m_fMoveSpeed * sinf(osg::PI_2 + m_vRotation._v[2]), 0));
				ChangePosition(osg::Vec3(-m_fMoveSpeed * sinf(osg::PI_2 + m_vRotation._v[2]), 0, 0));

				return true;
			}

			// 向左
			if (ea.getKey() == 0x41 || ea.getKey() == 0x61)
			{
				ChangePosition(osg::Vec3(0, m_fMoveSpeed * sinf(osg::PI_2 + m_vRotation._v[2]), 0));
				ChangePosition(osg::Vec3(-m_fMoveSpeed * sinf(osg::PI_2 + m_vRotation._v[2]), 0, 0));

				return true;
			}

			// 向右
			if (ea.getKey() == 0x44 || ea.getKey() == 0x64)
			{
				ChangePosition(osg::Vec3(0, m_fMoveSpeed * sinf(osg::PI_2 + m_vRotation._v[2]), 0));
				ChangePosition(osg::Vec3(m_fMoveSpeed * sinf(osg::PI_2 + m_vRotation._v[2]), 0, 0));

				return true;
			}
			// Right
			if (ea.getKey() == 0xFF53)
			{
				m_vRotation._v[2] -= osg::DegreesToRadians(m_fAngle);
			}
			// Left
			if (ea.getKey() == 0xFF51)
			{
				m_vRotation._v[2] += osg::DegreesToRadians(m_fAngle);
			}
			// 改变屏角
			if (ea.getKey() == 0x46 || ea.getKey() == 0x66)//F
			{
				m_fAngle -= 0.2;

				return true;
			}

			if (ea.getKey() == 0x47 || ea.getKey() == 0x67)//G
			{
				m_fAngle += 0.2;

				return true;
			}

			return false;
		}
		// 鼠标按下
		case (osgGA::GUIEventAdapter::PUSH):
		{
			if (ea.getButton() == 1)
			{
				m_fpushX = mouseX;
				m_fpushY = mouseY;

				m_bLeftButtonDown = true;
			}
			return false;
		}
		// 拖动
		case (osgGA::GUIEventAdapter::DRAG) :
		{
			if (m_bLeftButtonDown)
			{
				m_vRotation._v[2] -= osg::DegreesToRadians(m_fAngle *(mouseX - m_fpushX));

				m_vRotation._v[0] += osg::DegreesToRadians(1.1 *(mouseY - m_fpushY));

				if (m_vRotation._v[0] >= 3.14)
				{
					m_vRotation._v[0] = 3.14;
				}

				if (m_vRotation._v[0] <= 0)
				{
					m_vRotation._v[0] = 0;
				}
			}

			return false;
		}
		// 鼠标释放
		case (osgGA::GUIEventAdapter::RELEASE) :
		{
			if (ea.getButton() == 1)
			{
				m_bLeftButtonDown = false;
			}

			return false;
		}
		default:
		{
			return false;
		}
	}
}

// 位置变换函数
void TravelManipulator::ChangePosition(osg::Vec3 &delta)
{
	// 碰撞检测
	if (m_bPeng)
	{
		// 得到新的位置
		osg::Vec3 newPos1 = m_vPosition + delta;
		osgUtil::IntersectVisitor ivXY;
		
		// 根据新的位置得到两条线段检测
		osg::ref_ptr<osg::LineSegment> lineXY = new osg::LineSegment(newPos1, m_vPosition);

		osg::ref_ptr<osg::LineSegment> lineZ = new osg::LineSegment(newPos1 + osg::Vec3(0.0f, 0.0f, 10.0f), newPos1 - osg::Vec3(0.0f, 0.0f, -10.0f));

		ivXY.addLineSegment(lineZ.get());
		ivXY.addLineSegment(lineXY.get());

		// 结构交集检测
		m_pHostViewer->getSceneData()->accept(ivXY);

		// 如果没有碰撞检测
		if (!ivXY.hits())
		{
			m_vPosition += delta;
		}
	}
	else
	{
		m_vPosition += delta;
	}
}

// 设置速度
void TravelManipulator::setSpeed(float &sp)
{
	m_fMoveSpeed = sp;
}

// 得到当前速度
float TravelManipulator::getSpeed()
{
	return m_fMoveSpeed;
}

// 设置其实的位置
void TravelManipulator::SetPosition(osg::Vec3 &position)
{
	m_vPosition = position;
}

// 得到当前位置
osg::Vec3 TravelManipulator::GetPosition()
{
	return m_vPosition;
}

void travelManipulator_8_8(const string &strDataFolder)
{
	// 创建Viewer对象,场景浏览器
	osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer();

	// 把漫游器加入到场景中
	TravelManipulator::TravelToScene(viewer.get());
	osg::ref_ptr<osg::Group> root = new osg::Group();

	// 读取地形模型
	string strDataPath = strDataFolder + "lz.osg";
	osg::ref_ptr<osg::Node> node = osgDB::readNodeFile(strDataPath);

	// 添加到场景
	root->addChild(node.get());

	// 优化场景数据
	osgUtil::Optimizer optimizer;
	optimizer.optimize(root.get());

	viewer->setSceneData(root.get());

	viewer->realize();
	viewer->run();
}

        运行程序,截图如图8-18所示:

图8-18自定义操作器场景漫游示例截图

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/160036.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Flutter笔记:桌面端应用多窗口管理方案

Flutter笔记 桌面端应用多窗口管理方案 作者&#xff1a;李俊才 &#xff08;jcLee95&#xff09;&#xff1a;https://blog.csdn.net/qq_28550263 邮箱 &#xff1a;291148484163.com 本文地址&#xff1a;https://blog.csdn.net/qq_28550263/article/details/134468587 【简介…

Excel 文件比较工具 xlCompare 11.01 Crack

比较两个 Excel 文件之间的差异 xlCompare. xlCompare.com 是性能最佳的 Excel diff 工具&#xff0c;用于比较两个 Excel 文件或工作表并在线突出显示差异。xlCompare 包括免费的在线 Excel 和 CSV 文件比较服务以及用于比较和合并 Excel 文件的强大桌面工具。如果您想在线了…

C语言每日一题(32)环形链表

力扣网 141.环形链表 题目描述 给你一个链表的头节点 head &#xff0c;判断链表中是否有环。 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链表中存在环。 为了表示给定链表中的环&#xff0c;评测系统内部使用整数 pos 来表示链表尾…

2024年山东省职业院校技能大赛中职组 “网络安全”赛项竞赛试题-C卷

2024年山东省职业院校技能大赛中职组 “网络安全”赛项竞赛试题-C卷 2024年山东省职业院校技能大赛中职组 “网络安全”赛项竞赛试题-C卷A模块基础设施设置/安全加固&#xff08;200分&#xff09;A-1&#xff1a;登录安全加固&#xff08;Windows, Linux&#xff09;A-2&#…

聚观早报 |零跑C10亮相广州车展;小鹏X9亮相广州车展

【聚观365】11月18日消息 零跑C10亮相广州车展 小鹏X9亮相广州车展 坦克700 Hi4-T开启预售 超A级家轿五菱星光正式预售 哪吒汽车发布山海平台2.0 零跑C10亮相广州车展 零跑汽车首款全球车型C10在广州车展首次亮相&#xff0c;同时该车也是零跑LEAP 3.0技术架构下的首款全…

asp.net 学校资源信息管理系统VS开发sqlserver数据库web结构c#编程计算机网页项目

一、源码特点 asp.net 学校资源信息管理系统 是一套完善的web设计管理系统&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。 asp.net学校资源管理系统 二、功能介绍 本系统使用Microsoft Visual Studio 2019为开发工具&#xff0c;SQL …

小米真无线耳机 Air 2s产品蓝牙配对ubuntu20.04 笔记本电脑

小米真无线耳机 Air 2s产品蓝牙配对ubuntu20.04 笔记本电脑 1.我的笔记本是 22款联想拯救者y9000k&#xff0c;安装了双系统&#xff0c;ubuntu20.04。 2.打开耳机&#xff0c;按压侧面按钮2秒&#xff0c;指示灯显示白色闪烁。 3.打开ubunru20.04 系统右上角wifi的位置&…

C++菜鸟日记2

关于getline()函数&#xff0c;在char和string输入的区别 参考博客 1.在char中的使用&#xff1a; 2.在string中的使用&#xff1a; 关于char字符数组拼接和string字符串拼接方法 参考博客 字符串拼接方法&#xff1a; 1.直接用 号 2.利用append&#xff08;&#xff0…

Jmeter 如何监控目标服务的系统资源

下载Jmeter插件管理下载 perfmon 将这个插件管理放到Jmeter的\lib\ext目录下 然后重启Jmeter jmeter-plugins-manager-1.10.jar 下载 perfmon插件 添加 io 内存 磁盘的监听 并且添加监听 在宿主机中安装代理监听程序 并启动 ServerAgent.tar.gz

python django 小程序商城源码

开发环境&#xff1a; PyCharm&#xff0c;mysql5.7&#xff0c;微信开发者工具 技术说明&#xff1a; python django html vue.js bootstrap 微信小程序 功能介绍&#xff1a; 用户端&#xff1a; 登录注册&#xff08;含授权登录&#xff09; 首页显示搜索商品(可根据…

重磅消息:ChatGPT创始人Sam Altman被开除!

OpenAI CEO Sam Altman 将离开公司&#xff0c;GregBrockman 将辞去董事会主席一职。首席技术官 Mira Murati将担任临时CEO。 至于 Altman 先生的离职&#xff0c;这是董事会经过深思熟虑的宙查后做出的决定。董事会发现 Altman 在与董事会的沟通中并非始终保持坦率&#xff0c…

ES聚合与分组查询取值参数含义(Java api版本)

一、说明 在项目中使用Elasticsearch的聚合与分组查询后,对于返回结果一脸懵逼,查阅各资料后,自己总结了一下参数取值的含义,不一定全面,只含常见参数 二、分组查询 2.1 参数解释 SearchResponse<Map> searchResponse null;try {searchResponse client.search(s ->…

2023_“数维杯”问题B:棉秸秆热解的催化反应-详细解析含代码

题目翻译&#xff1a; 随着全球对可再生能源需求的不断增加&#xff0c;生物质能作为一种成熟的可再生能源得到了广泛的关注。棉花秸秆作为一种农业废弃物&#xff0c;因其丰富的纤维素、木质素等生物质成分而被视为重要的生物质资源。虽然棉花秸秆的热解可以产生各种形式的可…

机器视觉选型-什么时候用远心镜头

物体厚 当被检测物体厚度较大&#xff0c;需要检测不止一个平面时&#xff0c;典型应用如食品盒&#xff0c;饮料瓶等。 物体位置变化 当被测物体的摆放位置不确定&#xff0c;可能跟镜头成一定角度时。 物体上下跳动 当被测物体在被检测过程中上下跳动&#xff0c;如生产线上下…

初学编程学习,计算机编程怎么自学,中文编程工具下载

初学编程学习&#xff0c;计算机编程怎么自学&#xff0c;中文编程工具下载 给大家分享一款中文编程工具&#xff0c;零基础轻松学编程&#xff0c;不需英语基础&#xff0c;编程工具可下载。 这款工具不但可以连接部分硬件&#xff0c;而且可以开发大型的软件&#xff0c;象如…

MySQL优化(2):索引与优化原理(上)

作者简介&#xff1a;大家好&#xff0c;我是smart哥&#xff0c;前中兴通讯、美团架构师&#xff0c;现某互联网公司CTO 联系qq&#xff1a;184480602&#xff0c;加我进群&#xff0c;大家一起学习&#xff0c;一起进步&#xff0c;一起对抗互联网寒冬 上一篇&#xff0c;我们…

CF1899C Yarik and Array(DP,贪心)

题目链接 题目 A subarray is a continuous part of array. Yarik recently found an array a of n elements and became very interested in finding the maximum sum of a non empty subarray. However, Yarik doesn’t like consecutive integers with the same parity, s…

VS 将 localhost访问改为ip访问

项目场景&#xff1a; 使用vs进行本地调试时需要多人访问界面,使用ip访问报错 问题描述 vs通过ip访问报错 虚拟机或其它电脑不能正常打开 原因分析&#xff1a; 原因是vs访问规则默认是iis,固定默认启动地址是localhost 解决方案&#xff1a; 1.vs项目启动之后会出现这个 右…

【mysql】1153 - Got a packet bigger than ‘max_allowed_packet‘ bytes

执行mysql 语句出现&#xff1a;1153 - Got a packet bigger than max_allowed_packet bytes&#xff1b; 1153-得到一个大于“max_allowed_packet”字节的数据包。 数据包太大了怎么办。该配置吧。 查看max_allowed_packet show global variables like max_allowed_packet;…

js-webApi 笔记2之DOM事件

目录 1、表单事件 2、键盘事件 3、事件对象 4、排他思想 5、事件流 6、捕获和冒泡 7、阻止默认和冒泡 8、事件委托 9、事件解绑 10、窗口加载事件 11、窗口尺寸事件 12、元素尺寸和位置 13、窗口滚动事件 14、日期对象 15、节点 16、鼠标移入事件 1、表单事件 获取…