场景交互与场景漫游-交运算与对象选取(8-1)

交运算与对象选取

        在面对大规模的场景管理时,场景图形的交运算图形对象的拾取变成了一项基本工作。OSG作为一个场景管理系统,自然也实现了场景图形的交运算,交运算主要封装在osgUtil 工具中在OSG中,osgUtil是一个非常强有力的工具,集合了场图形处理、几何体修改工具及高层次的遍历几个功能。

交运算

        交运算(Intersection)本身是一个非常复杂的立体几何问题。当在阅读这一部分源代码时,读者会发现如果有非常丰富的立体几何思想见解,将能够很快理解源代码,如果没有的话,即使笔者在这里分析源代码也是没有用的。当然,作为一个应用者没有必要去过多关注底层是如何实现的。

        关于交运算,OSG本身的实现也是比较局限的,但是对于普通应用已经足够了,可以用一个继承关系图表示出来,如图8-21所示。

图8-21 osgUtil::Intersector 的继承关系及派生图

从继承关系图中可以看出,所有的交运算都共用一个父类osgUtil::Intersector类。下面对这个类的作用逐一说明。

  • osgUtil::Intersector:是一个纯虚类它定义了相交测试的接口osgUtil库从osgUtil::Intersection继承了多个类,适用于各种类型的几何体(如线段、多边形等)。执行相交测试时,应用程序将继承自osgUtil::Intersector的某个类实例化,再将其传递给 osgUtil::IntersectionVisitor 的实例,并请求该实例返回数据以获取交运算的结果。
  • osgUtil::LineSegmentIntersector继承自osgUtil::Intersector 类,用于检测指定线段和场景图形之间的相交情况,并向程序提供查询相交测试结果的函数。该类提供了一种定义射线的方法。它包括两个osg::Vec3实例,一个用于定义线段的起点,另一个用于定义终点。当交集测试被触发时,它将检测射线的相交情况并执行相应的操作。这个在示例显示位置及拾取示例中会用到,可以根据鼠标的位置初始化一个osgUtil::LineSegmentIntersector类的对象可以指定一个特定的线段来执行相交检测,在构造函数中即可初始化。
// 创建一个线段交集检测对象
osgUtil::LineSegmentIntersector::Intersections intersections:
viewer->computelntersections(x,y,intersections)

        通过相交运算,更多的是希望得到相交的点,可以通过申请一个迭代器来实现,代码如下:

// 得到相交交集的交点

for(osgUtil::LineSegmentIntersector::Intersections::iterator hitr = intersections.begin();hitr!=intersections.end();++hitr)
{
    // 输入流
    cout<<”Mouse in world X:”<<hitr->getWorldIntersectPoint().x()<<” Y:”<<hitr->getWorldIntersectPoint().y()<<” Z:”<<hitr->getWorldIntersectPoint().z()<<endl;
}
  • osgUtil::PolytopeIntersector与osgUtil::LineSegmentIntersector类似,不过,该类用于检测由一系列平面构成的多面体的相交运算。当鼠标单击场景图形中某一区域,希望拾取到鼠标位置附近的一个封闭多面体区域时,osgUtil::PolytopeIntersector类最实用。
  • osgUtil::PlaneIntersector,与osgUtil::LineSegmentIntersector类似,用于检测出一系列平面构成的平面的相交运算。

        osgUtil::IntersectionVisitor是一个比较特殊的类,它不直接继承自osgUtil::Intersector,继承关系图如图8-22所示。

图8-22 osgUtil::IntersectionVisitor 的继承关系图

        从继承关系图可以看出,它继承自osg::NodeVisitor,创建和触发机制与osg::NodeVisitor 实例大致相似。访问器需要维护一个进行交集测试的线段列表,而对于其中的每一条线段,访问器都会创建一个交点列表(osgUtil::IntersectVisitor::HitList 实例),它主要用于搜索场景图形中与指定几何体相交的节点。而最后相交测试的工作将在osgUtil::Intersector 的继承类中完成。在前面的自定义漫游操作器中,碰掩检测就是采用该类,最后的检测工作在osgUtil::LineSegmentIntersector 中完成,创建的过程如下:

// 创建一个交集访问器
osgUtil::IntersectVisitor ivXY;
// 根据新的位置得到两条线段检测
osg::ref_ptr<LineSegment> lineXY = new osg::LineSegment(newPos, m_vPosition);
osg::ref_ptr<osg::LineSegment> lineZ = new osg::LineSegment(newPos1 + osg::Vec3(0.0,0.0,10.0), newPos1 - osg::Vec3(0.0,0.0,-10.0));
// 添加两条线段
ivXY.addLineSegment(lineZ.get());
ivXY.addLineSegment(lineXY.get());

// 开启交集检测
m_pHowViewer->getSceneData()->accept(ivXY);

        交点列表(osgUtil::IntersectVisitor:HitList)的作用为:一条单一的线段可能与场景中的多个几何体实例(或者多次与同一个几何体)产生交集。对于每一条参与交集测试的线段,系统均会产生一个列表,这个列表包含了所有交集测试产生的 Hit 实例。如果没有监测到任何交集,该列表保持为空。

显示位置及拾取示例

        显示位置及拾取示例的代码如程序清单 8-10所示

/******************************************* 显示位置及拾取示例 *************************************/
// pick 事件处理器
class CPickHandler:public osgGA::GUIEventHandler
{
public:
	// 构造函数
	CPickHandler(osg::ref_ptr<osgText::Text> updateText) :_updateText(updateText)
	{

	}

	// 析构函数
	~CPickHandler()
	{

	}

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

	// pick
	virtual void pick(osg::ref_ptr<osgViewer::Viewer> viewer, const osgGA::GUIEventAdapter &ea);

	// 设置显示内容
	void setLabel(const std::string &name)
	{
		_updateText->setText(name);
	}
protected:
	// 得到当前视图矩阵
	osg::Vec3 position;
	osg::Vec3 center;
	osg::Vec3 up;

	// 传递一个文字对象
	osg::ref_ptr<osgText::Text> _updateText;
};

// HUD
class CreateHUD
{
public:
	CreateHUD()
	{

	}
	~CreateHUD()
	{

	}

	// 创建HUD
	osg::ref_ptr<osg::Node> createHUD(osg::ref_ptr<osgText::Text> updateText)
	{
		// 创建一个相机
		osg::ref_ptr<osg::Camera> hudCamera = new osg::Camera;

		// 设置绝对帧引用
		hudCamera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);

		// 设置正投影矩阵2D
		hudCamera->setProjectionMatrixAsOrtho2D(0, 1280, 0, 1024);

		// 设置视图矩阵
		hudCamera->setViewMatrix(osg::Matrix::identity());

		// 设置渲染顺序为POST
		hudCamera->setRenderOrder(osg::Camera::POST_RENDER);

		// 清除深度缓存
		hudCamera->setClearMask(GL_DEPTH_BUFFER_BIT);

		// 设置字体
		string timesFont = "D:\\WorkAndStudy\\SDK\\VS2013\\OSG\\Data\\font\\cour.ttf";

		// 设置位置
		osg::Vec3 position(700, 900, 0.0);

		osg::ref_ptr<osg::Geode> geode = new osg::Geode();
		osg::ref_ptr<osg::StateSet> stateset = geode->getOrCreateStateSet();

		// 关闭光照
		stateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
		
		//关闭深度测试
		stateset->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
		geode->addDrawable(updateText.get());
		hudCamera->addChild(geode.get());

		updateText->setCharacterSize(20.0f);
		updateText->setFont(timesFont);
		updateText->setColor(osg::Vec4(1.0f, 1.0, 1.0, 1.0));
		updateText->setText("");
		updateText->setPosition(position);

		// 设置数据变量为DYNAMIC
		updateText->setDataVariance(osg::Object::DYNAMIC);

		return hudCamera.get();
	}
};

/* 显示位置及拾取示例 */
void pickLineSegment_8_10(const string &strDataFolder);

/******************************************* 显示位置及拾取示例 *************************************/
// 事件处理函数
bool CPickHandler::handle(const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter &aa)
{
	switch (ea.getEventType())
	{
		// 每一帧
		case(osgGA::GUIEventAdapter::FRAME) :
		{
			osg::ref_ptr<osgViewer::Viewer> viewer = dynamic_cast<osgViewer::Viewer*>(&aa);

			// 得到视图矩阵
			viewer->getCamera()->getViewMatrixAsLookAt(position, center, up);
			if (viewer)
			{
				// 执行PICK动作
				pick(viewer.get(), ea);
			}
			return false;
		}
		default:
			return false;
	}
}

// PICK动作
void CPickHandler::pick(osg::ref_ptr<osgViewer::Viewer> viewer, const osgGA::GUIEventAdapter &ea)
{
	// 创建一个线段交集检测对象
	osgUtil::LineSegmentIntersector::Intersections intersections;
	
	std::string gdlist = "";

	// 申请一个流
	std::ostringstream os;

	// 得到鼠标的位置
	float x = ea.getX();
	float y = ea.getY();

	// 如果没有发生交集运算及鼠标没有点中物体
	if (viewer->computeIntersections(x, y, intersections))
	{
		// 得到相交交集的交点
		for (osgUtil::LineSegmentIntersector::Intersections::iterator hitr = intersections.begin(); hitr != intersections.end(); ++hitr)
		{
			// 输入流
			os << "Mouse in World X:" << hitr->getWorldIntersectPoint().x() << "  Y:" << hitr->getWorldIntersectPoint().y() << "  Z:" << hitr->getWorldIntersectPoint().z() << endl;
		}
	}

	// 输入流
	os << "Viewer Position X:" << position[0] << " Y:" << position[1] << " Z:" << position[2] << endl;

	gdlist += os.str();

	// 设置显示内容
	setLabel(gdlist);
}

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

	// 读取地形模型
	string strDataPath = strDataFolder + "lz.osg";
	osg::ref_ptr<osg::Node> node = osgDB::readNodeFile(strDataPath);
	osg::ref_ptr<osgText::Text> updateText = new osgText::Text();
	CreateHUD *hudText = new CreateHUD();

	// 添加到场景
	root->addChild(node);
	root->addChild(hudText->createHUD(updateText));

	// 添加PICK事件处理器
	viewer->addEventHandler(new CPickHandler(updateText));

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

	viewer->setSceneData(root);

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

        运行程序,截图如图 8-23 所示。

图8-23显示位置及拾取示例截图

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

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

相关文章

SDUT OJ《算法分析与设计》贪心算法

A - 汽车加油问题 Description 一辆汽车加满油后可行驶n公里。旅途中有若干个加油站。设计一个有效算法&#xff0c;指出应在哪些加油站停靠加油&#xff0c;使沿途加油次数最少。并证明算法能产生一个最优解。 对于给定的n和k个加油站位置&#xff0c;计算最少加油次数。 I…

Transformer中位置嵌入的几种形式对比

❤️觉得内容不错的话&#xff0c;欢迎点赞收藏加关注&#x1f60a;&#x1f60a;&#x1f60a;&#xff0c;后续会继续输入更多优质内容❤️ &#x1f449;有问题欢迎大家加关注私戳或者评论&#xff08;包括但不限于NLP算法相关&#xff0c;linux学习相关&#xff0c;读研读博…

JSP命令标签 静态包含/动态包含

好 下面我们聊聊JSP中的指令标签 这边 我们来说两个 分别是 静态包含 和 动态包含 我们可以将重用性代码包含起来 更好的使用 比如 我们界面上中下 分别有三个导航栏 那么 如果你写三份 就会出现很多重复代码 而且 改起来 也很不方便 要一次改三份 口说无凭 我们来做一个小案…

【机器学习基础】决策树(Decision Tree)

&#x1f680;个人主页&#xff1a;为梦而生~ 关注我一起学习吧&#xff01; &#x1f4a1;专栏&#xff1a;机器学习 欢迎订阅&#xff01;后面的内容会越来越有意思~ ⭐特别提醒&#xff1a;针对机器学习&#xff0c;特别开始专栏&#xff1a;机器学习python实战 欢迎订阅&am…

[AI]ChatGPT4 与 ChatGPT3.5 区别有多大

ChatGPT 3.5 注册已经不需要手机了&#xff0c;直接邮箱认证就可以&#xff0c;这可真算是好消息&#xff0c;坏消息是 ChatGPT 4 还是要收费。 那么 GPT-3.5 与 GPT-4 区别有多大呢&#xff0c;下面简单测试一下。 以从 TDengine 订阅数据为例&#xff0c;TDengine 算是不太小…

腾讯云轻量数据库是什么?性能如何?费用价格说明

腾讯云轻量数据库测评&#xff0c;轻量数据库100%兼容MySQL 5.7和8.0&#xff0c;腾讯云提供1C1G20GB、1C1G40GB、1C2G80GB、2C4G120GB、2C8G240GB五种规格轻量数据库&#xff0c;腾讯云百科txybk.com分享腾讯云轻量数据库测评、轻量数据库详细介绍、特性、配置价格和常见问题解…

网络运维与网络安全 学习笔记2023.11.17

网络运维与网络安全 学习笔记 第十八天 今日目标 TCP数据包格式、TCP通信流程分析、UDP协议介绍 Telnet之AAA认证、设备升级与备份 今日英语单词 TCP&#xff0c;Transmission Control Protocol 传输控制协议 UDP&#xff0c;User Datagram Protocol 用户数据报协议 Sync …

异常语法详解

异常语法详解 一&#xff1a;异常的分类&#xff1a;二&#xff1a;异常的处理1:异常的抛出:throw2&#xff1a;异常的声明:throws3&#xff1a;try-catch捕获并处理异常 三&#xff1a;finally关键字四&#xff1a;自定义异常类&#xff1a; 一&#xff1a;异常的分类&#xf…

用GPT 搭建一个占星术、解梦、塔罗牌占卜和命理学服务

今天来尝试我们的占星术、解梦、塔罗牌占卜和命理学服务&#xff0c;揭开宇宙的奥秘并获得自我认识 聊天 GPT API 集成的 HTML5 模板。我们的目标是提供易于使用且高度可定制的 API 代码&#xff0c;使您能够训练自己的人工智能解决方案并将其添加到提示中。 我们的产品是可定…

window上Clion配置C++版本的opencv

window上Clion配置opencv 注意版本一定要对的上&#xff0c;否则可能会出错&#xff0c;亲测 widnows 11mingw 8.1.0opencv 4.5.5 mingw8.1下载地址https://sourceforge.net/projects/mingw/ 配置环境变量 cmake下载 安装完添加环境变量 来到官网&#xff0c;下载 windows 对…

C/C++通过位操作实现2个uint32_t合并为uint64_t

#include <iostream> using namespace std;int main() {uint32_t a 10;uint32_t b 600;//先将uint32_t的a转为uint64_t&#xff0c;此时a前面32位都是0&#xff0c;然后左移32位&#xff0c;此时右32位为0&#xff0c;最后加上uint32_t类型的b&#xff0c;填充右32位的…

隐式转换导致索引失效的原因

Num1 int Num2 varchar Str1不能为null Str2可null 例子1&#xff1a; 结果&#xff1a;124非常快&#xff0c;0.001~0.005秒出结果。3最慢&#xff0c;4~5秒出结果。 查询执行计划&#xff1a;124索引扫描。3全表扫描。 解释&#xff1a;首先四个23都产生隐式转换&#x…

Spring cloud - Hystrix服务限流、熔断及降级

Hystrix的作用 Hystrix的主要作用是在微服务环境下防止服务雪崩&#xff0c;确保服务弹性及可用性。 具体来说&#xff0c;Hystrix可以实现&#xff1a; 服务降级&#xff1a;通过fallback实现服务不可达情况下的服务降级作用。熔断&#xff1a;服务不可达的情况下在设定时间…

linux中利用fork复制进程,printf隐藏的缓冲区,写时拷贝技术,进程的逻辑地址与物理地址

1.prinf隐藏的缓冲区 1.思考:为什么会有缓冲区的存在? 2.演示及思考? 1).演示缓存区没有存在感 那为什么我们感觉不到缓冲区的存在呢?我们要打印东西直接就打印了呢? 我们用代码演示一下: 比如打开一个main.c,输入内容如下: #include <stdio.h>int main(){printf…

Shell判断:流程控制—if(二)

一、多分支结构 1、语法&#xff1a; if 条件测试1 then 命令序列 elif 条件测试2 then 命令序列 elif 条件测试3 then 命令序列.... else 命令序列 fi 2、示例&am…

ERR:Navicat连接Sql Server报错

错误信息&#xff1a;报错&#xff1a;未发现数据源名称并且未指定默认驱动程序。 原因&#xff1a;Navicat没有安装Sqlserver驱动。 解决方案&#xff1a;在Navicat安装目录下找到sqlncli_x64.msi安装即可。 一键安装即可。 Navicat链接SQL Server配置 - MarchXD - 博客园 …

Spring Cloud学习(十)【Elasticsearch搜索功能 分布式搜索引擎02】

文章目录 DSL查询文档DSL查询分类全文检索查询精准查询地理坐标查询组合查询相关性算分Function Score Query复合查询 Boolean Query 搜索结果处理排序分页高亮 RestClient查询文档快速入门match查询精确查询复合查询排序、分页、高亮 黑马旅游案例 DSL查询文档 DSL查询分类 …

K-Means聚类

文章目录 概要整体架构流程技术名词解释技术细节小结 概要 K-means聚类算法实现 技术细节 选取的数据集是sklearn.datasets里面的鸢尾花数据集&#xff0c;方便最后的算法评价。 根据手肘法&#xff08;即根据SSE代价函数&#xff09;得出最合适的k值。 此处思路是先根据E …

C++之常用算法

C之常用算法 for_each transform #include<iostream> using namespace std; #include<vector> #include<algorithm>class Tranfor { public:int operator()(int var){return var;} };class MyPrint { public:void operator()(int var){cout << var&l…

【机器学习】特征工程:特征选择、数据降维、PCA

各位同学好&#xff0c;今天我和大家分享一下python机器学习中的特征选择和数据降维。内容有&#xff1a; &#xff08;1&#xff09;过滤选择&#xff1b;&#xff08;2&#xff09;数据降维PCA&#xff1b;&#xff08;3&#xff09;sklearn实现 那我们开始吧。 一个数据集中…