OSG交互:选中场景模型并高亮显示

这篇具有很好参考价值的文章主要介绍了OSG交互:选中场景模型并高亮显示。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1、目的

  可以在osg视图中选中指定模型实体,并高亮显示。共分为两种,一种鼠标点选,一种框选。

2、鼠标点选

2.1 功能说明

  1. 生成两组对象,一组cow对象可以被选中,另一组robot不能被选中;
  2. 点击cow对象被选中高亮,点击robot被选中不高亮;
  3. 点击空白处,弹出“select nothing!”提示未选择任何实体;

备注:
  存在bug:当点击一个cow时,通过osg::PositionAttitudeTransform矩阵变换节点生成的另一个牛也被高亮,后续抽空来研究原因解决处理。

2.2 效果

效果如下:
osg点选,OSG/OSGEarth开发,交互,osg,选中高亮

2.3 源码

#include <osg/Geode>
#include <osg/Geometry>
#include <osg/LineWidth>
#include <osgViewer/Viewer>
#include <osgViewer/CompositeViewer>
#include <osgDB/ReadFile>
#include <osgDB/WriteFile>
#include <osgViewer/ViewerEventHandlers>  
#include <osg/Geode>
#include <osg/Geometry>
#include <osg/LineWidth>
#include <osgViewer/Viewer>
#include <osg/Node>
#include <osgDB/ReadFile>
#include <osgViewer/Viewer>
#include <osgDB/ReadFile>
#include <osgDB/WriteFile>
#include <osgViewer/ViewerEventHandlers> 
#include <osgViewer/CompositeViewer> 
#include <osg/PositionAttitudeTransform> 
#include <osg/MatrixTransform> 
#include <osgFX/Scribe> 
#include <osgParticle/PrecipitationEffect> 
#include <osg/NodeCallback> 
#include <osg/DrawPixels> 
#include <osg/ShapeDrawable>
#include <osg/ComputeBoundsVisitor>
#include <osgGA/TrackballManipulator>
#include <osgGA/StateSetManipulator>
#include <osg/GraphicsContext>
#include <osgViewer/GraphicsWindow>
#include <iostream>
#include <osgFX/Scribe>
#include <osgFX/Outline>
#include <osgViewer/ViewerEventHandlers>

#pragma comment(lib, "OpenThreadsd.lib")
#pragma comment(lib, "osgd.lib")
#pragma comment(lib, "osgDBd.lib")
#pragma comment(lib, "osgUtild.lib")
#pragma comment(lib, "osgGAd.lib")
#pragma comment(lib, "osgViewerd.lib")
#pragma comment(lib, "osgTextd.lib")
#pragma comment(lib, "osgSimd.lib")
#pragma comment(lib, "osgFXd.lib")

class nodePick :public osgGA::GUIEventHandler
{
	virtual bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa)
	{
		osgViewer::Viewer* viewer = dynamic_cast<osgViewer::Viewer*> (&aa);
		switch (ea.getEventType())
		{
		case osgGA::GUIEventAdapter::PUSH:
		{
			osgUtil::LineSegmentIntersector::Intersections intersections;
			osg::ref_ptr<osg::Node> node = new osg::Node();
			osg::ref_ptr<osg::Group> parent = new osg::Group();
			osg::ref_ptr<osg::Group> group0 = dynamic_cast<osg::Group*>(viewer->getSceneData()->asGroup()->getChild(0));
			if (viewer->computeIntersections(ea.getX(), ea.getY(), intersections))
			{
				//得到选择的节点
				osgUtil::LineSegmentIntersector::Intersection intersection = *intersections.begin();
				osg::NodePath& nodePath = intersection.nodePath;
				node = nodePath.back();

				// 判定所属的分组
				osg::ref_ptr<osg::Group> group = dynamic_cast<osg::Group*>(nodePath[2]);
				if (group->getName() == "groupCow")
				{
					//点击节点切换高亮
					parent = dynamic_cast<osg::Group*> (nodePath[nodePath.size() - 2]);//当前选择节点的父节点
					osgFX::Outline* ot = dynamic_cast<osgFX::Outline*>(parent.get());
					//若ot不存在(未高亮) (node->parent)=>(node->outline->parent)
					if (!ot) 
					{
						osg::ref_ptr<osgFX::Outline> outline = new osgFX::Outline();
						outline->setColor(osg::Vec4(1, 1, 0, 1));
						outline->setWidth(5);
						outline->addChild(node);
						parent->replaceChild(node, outline);
					}
					//若ot存在(高亮)找出当前outline的父节点(node->outline->*itr)=>(node->*itr)
					else
					{
						osg::Node::ParentList parentList = ot->getParents();
						osg::Node::ParentList::iterator itr = parentList.begin();
						(*itr)->replaceChild(ot, node);
					}
				}
			}
			else
			{
				std::cout << "select nothing!" << std::endl;
			}
		}
		default:
			return false;
		}
	}
};

int main()
{
	osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer;
	osg::ref_ptr<osg::Group> root = new osg::Group;

	osg::ref_ptr<osg::Group> groupCow = new osg::Group;
	groupCow->setName("groupCow");

	osg::ref_ptr<osg::Group> groupRobot = new osg::Group;
	groupRobot->setName("groupRobot");

	osg::ref_ptr<osg::Node> cowNode = osgDB::readNodeFile("D:\\OpenSceneGraph_Data\\cow.osg");
	osg::ref_ptr<osg::Node> robotNode = osgDB::readNodeFile("D:\\OpenSceneGraph_Data\\robot.osg");

	osg::ref_ptr<osg::PositionAttitudeTransform> cowpatNode = new osg::PositionAttitudeTransform();
	cowpatNode->setPosition(osg::Vec3(0, 0, 0));
	cowpatNode->addChild(cowNode.get());
	cowpatNode->setName("cow1");

	osg::ref_ptr<osg::PositionAttitudeTransform> cowpatNode2 = new osg::PositionAttitudeTransform();
	cowpatNode2->setPosition(osg::Vec3(10, 0, 0));
	cowpatNode2->addChild(cowNode.get());
	cowpatNode2->setName("cow2");

	osg::ref_ptr<osg::PositionAttitudeTransform> robotpatNode = new osg::PositionAttitudeTransform();
	robotpatNode->setPosition(osg::Vec3(0, 10, 0));
	robotpatNode->addChild(robotNode.get());

	osg::ref_ptr<osg::PositionAttitudeTransform> robotpatNode2 = new osg::PositionAttitudeTransform();
	robotpatNode2->setPosition(osg::Vec3(10, 10, 0));
	robotpatNode2->addChild(robotNode.get());

	groupCow->addChild(cowpatNode);
	groupCow->addChild(cowpatNode2);

	groupRobot->addChild(robotpatNode);
	groupRobot->addChild(robotpatNode2);

	root->addChild(groupCow);
	root->addChild(groupRobot);

	viewer->setSceneData(root.get());
	viewer->addEventHandler(new nodePick);
	viewer->addEventHandler(new osgViewer::WindowSizeHandler());//F键控制全/半屏

	viewer->run();
}

3、鼠标框选

  参照osgChina站长杨石兴的博客代码。

3.1 功能说明

  1. 生成20个圆球对象可被选中;
  2. 点击鼠标+ctrl键可以绘制框选;
  3. 框选实体变红;

备注:
  存在bug:卡顿、按F快捷键退出全屏,绘制出的框会偏离鼠标位置不随鼠标拖动、实用性不强需要改进。

3.2 效果

效果如下:
osg点选,OSG/OSGEarth开发,交互,osg,选中高亮文章来源地址https://www.toymoban.com/news/detail-754615.html

3.3 源码

#include <osgViewer/Viewer>
#include <osgDB/ReadFile>
#include <osg/Camera>
#include <osgGA/GUIEventHandler>
#include <osg/Geode>
#include <osg/ShapeDrawable>
#include <osg/Geometry>
#include <algorithm>


//掩码为NODE_NPICK则不接受PICK,为NODE_PICK为接受PICK
#define NODE_NPICK ~0x0F
#define NODE_PICK 0x0F

//绘制一些球,用于被选择
class MySphere : public osg::Geode
{
public:
	MySphere(osg::Vec3 center, float radius)
	{
		_bSelect = false;
		_sd = new osg::ShapeDrawable(new osg::Sphere(center, radius));
		_sd->setColor(osg::Vec4(0.5, 0.5, 0.5, 1.0));
		addDrawable(_sd);
		setNodeMask(NODE_PICK);
	}

	//设置球是否被选择
	void setSelect(bool bSelect)
	{
		if (_bSelect == bSelect)
		{
			return;
		}

		_bSelect = bSelect;
		if (_bSelect)
		{
			_sd->setColor(osg::Vec4(1.0, 0.2, 0.2, 1.0));
			setNodeMask(NODE_NPICK);
		}
		else
		{
			_sd->setColor(osg::Vec4(0.5, 0.5, 0.5, 1.0));
			setNodeMask(NODE_PICK);
		}

		//重绘
		_sd->dirtyDisplayList();
	}

	osg::ShapeDrawable* _sd;
	bool _bSelect;
};

//用于选择的场景
osg::Node* g_selectNode = nullptr;

//绘制很多球
osg::Node* BuildScene()
{
	osg::Group* root = new osg::Group;

	//这些小球可以被选择
	g_selectNode = root;

	//绘制100个球
	for (int i = 0; i < 20; i++)
	{
		osg::Vec3 center(::rand() % 100, ::rand() % 100, ::rand() % 100);
		float r = ::rand() % 10 + 1.0;
		root->addChild(new MySphere(center, r));
	}

	return root;
}

//清空点选状态
void ClearSelect()
{
	for (int i = 0; i < 20; i++)
	{
		((MySphere*)g_selectNode->asGroup()->getChild(i))->setSelect(false);
	}
}

//结点的掩码,显示与隐藏
#define NODE_SHOW ~0x0
#define NODE_HIDE 0x0

//选择框做为一个全局变量,使用起来方便
osg::Geometry* g_geomSelectBox = new osg::Geometry;

//
osg::Camera* createHUD(osg::Viewport* vp)
{
	osg::Camera* camera = new osg::Camera;

	//设置投影矩阵为正交投影
	camera->setProjectionMatrix(osg::Matrix::ortho2D(0, vp->width(), 0, vp->height()));

	//设置其观察矩阵为单位矩阵,且不改变,该相机永远显示,也不用参与拣选
	camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
	camera->setViewMatrix(osg::Matrix::identity());

	//只清空深度缓存,使得其显示内容可以以主相机为背景
	camera->setClearMask(GL_DEPTH_BUFFER_BIT);

	//最后渲染,因为需要以主相机显示的内容为背景
	camera->setRenderOrder(osg::Camera::POST_RENDER);

	//不需要响应事件
	camera->setAllowEventFocus(false);

	//绘制选择框
	osg::Geode* gnode = new osg::Geode;
	camera->addChild(gnode);

	gnode->addDrawable(g_geomSelectBox);
	//设置透明
	osg::StateSet* ss = gnode->getOrCreateStateSet();
	ss->setMode(GL_BLEND, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
	ss->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
	ss->setMode(GL_LIGHTING, osg::StateAttribute::OFF | osg::StateAttribute::OVERRIDE);

	//设置顶点
	osg::Vec3Array* vertices = new osg::Vec3Array;
	float depth = -0.1;
	vertices->push_back(osg::Vec3(0, 0, depth));
	vertices->push_back(osg::Vec3(100, 0, depth));
	vertices->push_back(osg::Vec3(100, 100, depth));
	vertices->push_back(osg::Vec3(0, 100, depth));
	g_geomSelectBox->setVertexArray(vertices);

	//设置颜色
	osg::Vec4Array* color = new osg::Vec4Array;
	color->push_back(osg::Vec4(0.8, 0.8, 0.8, 0.2));
	g_geomSelectBox->setColorArray(color, osg::Array::BIND_OVERALL);

	//绘制盒子
	g_geomSelectBox->addPrimitiveSet(new osg::DrawArrays(GL_QUADS, 0, 4));

	return camera;
}

class MyEvent : public osgGA::GUIEventHandler
{
public:
	MyEvent() :osgGA::GUIEventHandler(),
		_xStart(0),
		_yStart(0)
	{
	}

	virtual bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa)
	{
		//左ctrl按着,又鼠标点击,则进入绘制状态
		if (ea.getEventType() == ea.PUSH) //
		{
			//判断左CTRL键是否按下
			if (ea.getModKeyMask() == ea.MODKEY_LEFT_CTRL)
			{
				_xStart = ea.getX();
				_yStart = ea.getY();
				//清空之前绘制的结果,这里仅隐藏即可
				g_geomSelectBox->setNodeMask(NODE_HIDE);

				//清空点选内容,一切重新开始
				_pickArea.clear();
				ClearSelect();

				//返回真代表后续事件处理器包括操作器不再处理该事件,就实现了拖动时场景不动
				return true;
			}
		}

		//左ctrl点下时,进入到选择状态,开始绘制选择框,且操作器不再处理鼠标拖动事件
		if (ea.getEventType() == ea.DRAG) //鼠标拖动,拖动是鼠标按键按下的时候移动鼠标
		{
			//判断左CTRL键是否按下
			if (ea.getModKeyMask() == ea.MODKEY_LEFT_CTRL)
			{
				//开始绘制,调整顶点参数就可以
				g_geomSelectBox->setNodeMask(NODE_SHOW);

				//获取顶点、更新顶点
				osg::Vec3Array* vertices = (osg::Vec3Array*)g_geomSelectBox->getVertexArray();
				int xEnd = ea.getX();
				int yEnd = ea.getY();
				float depth = -0.1;
				vertices->at(0).set(_xStart, _yStart, depth);
				vertices->at(1).set(xEnd, _yStart, depth);
				vertices->at(2).set(xEnd, yEnd, depth);
				vertices->at(3).set(_xStart, yEnd, depth);

				//重绘
				g_geomSelectBox->dirtyDisplayList();

				int xMin = _xStart > ea.getX() ? ea.getX() : _xStart;
				int xMax = _xStart < ea.getX() ? ea.getX() : _xStart;
				int yMin = _yStart > ea.getY() ? ea.getY() : _yStart;
				int yMax = _yStart < ea.getY() ? ea.getY() : _yStart;

				//将框选的区域压入到_pickArea
				for (int i = xMin; i <= xMax; i += 5)
				{
					for (int j = yMin; j <= yMax; j += 5)
					{
						if (!isPick(i, j))
						{
							_pickArea.push_back(osg::Vec2i(i, j));
							//进行pick
							osgViewer::View* view = dynamic_cast<osgViewer::View*>(&aa);
							osgUtil::LineSegmentIntersector::Intersections intersections;
							//只pick和NODE_PICK相&得true的
							if (view->computeIntersections(i, j, intersections, NODE_PICK))
							{
								for (osgUtil::LineSegmentIntersector::Intersections::iterator iter = intersections.begin();
									iter != intersections.end(); iter++)
								{
									osg::NodePath np = iter->nodePath;

									MySphere* ms = dynamic_cast<MySphere*>(np.at(np.size() - 1));
									if (ms)
									{
										ms->setSelect(true);
									}
								}
							}
						}

					}
				}

				//返回真代表后续事件处理器包括操作器不再处理该事件,就实现了拖动时场景不动
				return true;
			}
		}

		return false;
	}

	//看一个点是不是pick过,返回true是已经pick过
	bool isPick(int x, int y)
	{
		for (int i = 0; i < _pickArea.size(); i++)
		{
			if ((_pickArea.at(i).x() == x) && (_pickArea.at(i).y() == y))
			{
				return true;
			}
		}

		return false;
	}

	int _xStart, _yStart;

	//鼠标按下去的时候,再拖动,就把框选的区域内的点都压进去,用于pick
	std::vector<osg::Vec2i> _pickArea;
};


int main()
{
	osgViewer::Viewer viewer;

	osg::Group* root = new osg::Group;

	root->addChild(BuildScene());

	viewer.setSceneData(root);
	viewer.realize();

	//realize之后,上下文已经被初始化,可以获得视口大小
	//在此处获得视口大小是为了创建HUD时使其视口大小与创建的一致
	osg::Viewport* vp = viewer.getCamera()->getViewport();
	root->addChild(createHUD(vp));

	viewer.addEventHandler(new MyEvent);
	viewer.addEventHandler(new osgViewer::WindowSizeHandler());//F键控制全/半屏

	return viewer.run();
}

到了这里,关于OSG交互:选中场景模型并高亮显示的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • opencv,opengl,osg,vulkan,webgL,opencL,cuda,osg,vtk,ogre的区别

    OpenCV OpenCV是一个基于BSD许可(开源)发行的跨平台计算机视觉和机器学习软件库,可以运行在Linux、Windows、Android和Mac OS操作系统上。 它轻量级而且高效——由一系列 C 函数和少量 C++ 类构成,同时提供了Python、Ruby、MATLAB等语言的接口,实现了图像处理和计算机视觉方面的很

    2024年02月13日
    浏览(5)
  • osg实现鼠标框选

    osg实现鼠标框选

    目录 1. 需求的提出 2. 具体实现      2.1. 禁止场景跟随鼠标转动      2.2. 矩形框前置绘制 3. 附加说明         3.1. 颜色设置说明         3.2.矩形框显示和隐藏的另一种实现        有时需要在屏幕通过按住键盘上的某个键如Ctrl键且按住鼠标左键,拖出一个矩形,实现框选

    2024年02月08日
    浏览(17)
  • OSG StatsHandler 初步学习

    OSG StatsHandler 初步学习

      osg为视景器的使用和调试提供了丰富的辅助组件,它们主要是以osg::ViewerBase的成员变量或交互事件处理器(osgGA::GUIEventHandler)的形式出现。osgViewer::StatsHandler、osg::Stats类就是其中的两个经常用到的辅助组件。   每按一下s键,视景窗口会多输出一些东西;控制台窗口也会输出

    2024年02月02日
    浏览(7)
  • osg+pbr-直射光

    osg+pbr-直射光

    算法是来自于learn opengl pbr相关部分, 只考虑如何移植到osg。 1,法线如何从局部坐标系到世界坐标系(逆转置矩阵) 2,视点通过漫游器获取, 3,视点uniform指针传递给漫游器,在漫游器中改变 为了说明正确性,先把视点设置为原点,按右方向键时正常。 可见,面向原点的

    2024年02月11日
    浏览(7)
  • OSG三维渲染引擎编程学习之八十八:“第八章:OSG文字” 之 “8.7 osgText3D”

    目录   第八章 OSG文字 8.7 osgText3D 8.7.1 osgText3D介绍 8.7.2 osgText3D实例       适当的文字信息对于显示场景信息是非常重要的。在OSG中,osgText提供了向场景中添加文字的强大功能,由于有第三方插件FreeType的支撑,可完全支持TrueType字体。       TrueType是由AppleComputer公司和Micro

    2024年02月13日
    浏览(11)
  • OpenSceneGraph几何基础教程【OSG】

    OpenSceneGraph几何基础教程【OSG】

    默认情况下,OSG 使用顶点数组法和显示列表法来渲染几何体。 但是,渲染策略可能会发生变化,具体取决于几何数据的呈现方式。 在本文中,我们将了解在 OSG 中处理几何体的基本技术。 OpenSceneGraph 后端的 OpenGL 使用几何图元(例如点、线、三角形和多边形面)来构建三维

    2024年02月04日
    浏览(10)
  • OSG粒子系统特效-----雨雪、爆炸、烟雾

    OSG粒子系统特效-----雨雪、爆炸、烟雾

    飞机坠毁 陨石坠落 源码: 源码:

    2024年02月07日
    浏览(6)
  • STM32LCD--基于HAL库(选中高亮?一文看懂如何玩转高亮显示)

    STM32LCD--基于HAL库(选中高亮?一文看懂如何玩转高亮显示)

    相关说明: 开发板:CT117E-M4(STM32G431RB 蓝桥杯嵌入式比赛板) 开发环境: CubeMX+Keil5 第六届到第十二届省赛题中,高亮显示考察了四次,分别是第六、七、九、十届,第十一届和第十二届没有考察,今年考察几率仍然较大。 说明: 如何看这块LCD的坐标?将单片机 顺时针旋转

    2023年04月08日
    浏览(17)
  • CISSP-OSG-各章节书面实验整理

    1. 讨论和描述CIA 三元组。 CIA 三元组是保密性、完整性和可用性的结合。 保密性指用于确保保护数据、对象或资源的隐密性的措施。 完整性是保护数据可靠性和正确性的概念。 可用性指被授权的主体能及时不间断地访问对象。 CIA 三元组这个术语用来表示安全解决方案的三

    2024年02月06日
    浏览(32)
  • CISSP学习-安全运营(OSG安全运营管理)

    目录 1、安全运营概念 1.1 定义 1.2 知其所需和最小特权 1.3 职责分离 1.4 岗位轮换 1.5 强制休假 1.6 监控特权账户 1.7 管理信息生命周期 1.8 服务水平协议SLA 1.9 人员安全 1.10 可问责 2、安全配置资源 2.1 管理硬件和软件资产 2.2 硬件库和软件库(资产库)的安全作用 2.3 维护配置清

    2024年02月05日
    浏览(8)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包