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

这篇具有很好参考价值的文章主要介绍了场景交互与场景漫游-交运算与对象选取(8-1)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

交运算与对象选取

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

交运算

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

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

场景交互与场景漫游-交运算与对象选取(8-1),OSG,交互,c++,图形渲染,3d

图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-1),OSG,交互,c++,图形渲染,3d

图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-1),OSG,交互,c++,图形渲染,3d

图8-23显示位置及拾取示例截图文章来源地址https://www.toymoban.com/news/detail-760944.html

到了这里,关于场景交互与场景漫游-交运算与对象选取(8-1)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Python实现交互窗口功能(Tkinter;面向对象的图形化用户界面(GUI)模块)(一)

    本文主要介绍Python中实现GUI的Tkinter模块以及模块中的控件及其使用 Python自带了tkinter 模块,面向对象的GUI工具包 TK 的Python编程接口,提供了快速便利地创建GUI应用程序的方法。 其图像化编程的基本步骤通常包括: 导入 tkinter 模块 创建 GUI 根窗体 添加人机交互控件并编写相

    2024年02月08日
    浏览(57)
  • 【OSG案例详细分析与讲解】之五:【3D交互式动画】

           OpenSceneGraph是一个强大的3D图形引擎,用于创建高质量、交互式的3D图形应用程序。其中一个常见的应用场景是 创建动画效果 。本节文章将介绍如何使用OSG和 osgWidget 库创建一个 交互式的3D动画程序 ,包括创建动画几何体、定义动画更新、具有鼠标事件的颜色标签、具

    2024年02月01日
    浏览(46)
  • threejs 实现场景漫游效果(相机沿着自定义轨道移动)

    效果视频: Video_22-06-15_18-10-11 实现思路:先创建一条曲线curve作为运动路线,然后使用const points = curve.getPoints(n)方法将curve分成n-1段;我们可以通过points[n] 获取第n个点的坐标位置;将相机的位置设置为这个坐标,在动画中不断地修改n的值达到移动的效果;具体操作如下:

    2024年02月11日
    浏览(96)
  • dataframe对象选取指定行、列的方法(个人学习)

    1、获取指定列 1.1 按列名获取指定一列 df[[\\\"name\\\"]]  返回类型是dataframe; df[\\\"name\\\"]    返回类型是series; 1.2 按列名获取多列 df[[\\\"class\\\",\\\"name\\\",\\\"age\\\"]]   返回的是dataframe对象; 2、获取指定行 2.1 按照行名获取指定的行——————loc()方法 df.loc[\\\"id_2\\\"]            # 仅获取第二行数

    2024年02月16日
    浏览(26)
  • MFC+OSG(Open Secene Graph)场景实现中文HUD(head up display)效果,防止中文乱码

    我建立了一个MFC工程,以OSG作为视图显示的基础,通过点击MFC菜单启动某些功能。因此,在工程中包含了OSG库。并且,为了使生成的exe在Windows下能正常处理中文路径,使用**多字节字符集(ANSI)**作为编码方式。因此,程序中并不会使用 L() 宏来定义Unicode字符串,也不会使用

    2024年02月08日
    浏览(43)
  • 基于 SVG 的图形交互方案实践

    不知道从什么时候起,人们开始喜欢上数字大屏这种“ 花里胡哨 ”的东西,仿佛只要用上“ 科技蓝 ”这样神奇的色调,就可以让一家公司焕然一新,瞬间变得科技感满满。不管数字大屏的实际意义,是用来帮助企业监控和决策,还是为了方便领导参观和视察,抑或是为了向

    2024年02月11日
    浏览(34)
  • 高级 Matplotlib:3D 图形和交互性

    Matplotlib 是 Python 中最重要的数据可视化库之一。在之前的文章中,我们讨论了如何使用基础和中级功能来创建各种图形。在本文中,我们将深入研究 Matplotlib 的高级特性,特别是如何创建 3D 图形和交互式图形。 Matplotlib 提供了一组用于创建 3D 图形的 API,如 3D 散点图、3D 折

    2024年02月15日
    浏览(43)
  • easyx图形库基础:2.基本运动+键盘交互

    1.如何实现动画: 相信大家已经对动画的原理已经不陌生了。想要目标物体动起来,只需要逐个播放目标物体每一时刻位置的图片。只要播放的速度足够快,人们就会在视觉上认为目标物体动起来了。 帧率:具有连续性的一些图片在1秒中绘制的个数。 物体运动的速度单位一

    2024年02月12日
    浏览(38)
  • 场景图形管理-多视图与相机(3)

            在OSG中多视图的管理是通过osgViewer:: CompositeViewer 类来实现的。该类负责多个视图的管理及同步工作,继承自osgViewer;:ViewerBase类,继承关系图如图8-13所示 图8-13 osgViewer::CompositeViewer 的继承关系图         在前面已经讲到,osgViewer: ViewerBase 类主要负责 线程管理

    2024年02月02日
    浏览(43)
  • EasyX图形库note4,动画及键盘交互

    大家好,这里是Dark Flame Master,专栏从这篇开始就会变得很有意思,我们可以利用今天所学的只是实现很多功能,同样为之后的更加好玩的内容打下基础,从这届开始将会利用所学的知识制作一些小游戏,废话不多说,开始今天的内容。 专栏:EasyX图形化编程 在之前的笔记中

    2024年02月08日
    浏览(47)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包