osg高亮显示选中的模型

目录

1. 节点拾取

2. 高亮显示

2.1. 将节点高亮显示

2.2. 点击切换高亮

2.3 控制特定节点高亮


1. 节点拾取

        取nodepath中的最后一个即为当前节点:node = nodePath.back();
以下是最简单的节点拾取代码。仅仅用于测试节点拾取,设置点击后节点变为透明。

#include <osgViewer/Viewer>
#include <osgDB/ReadFile>
#include <osgGA/GUIEventHandler>

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;
		  if (viewer->computeIntersections(ea.getX(), ea.getY(), intersections))
		  {
			//得到选择的节点
												 
            osgUtil::LineSegmentIntersector::Intersection intersection = *intersections.begin();
			osg::NodePath& nodePath = intersection.nodePath;	
			node = nodePath.back();

			//点击节点透明
			node->setNodeMask(0);
											 }
		 }
		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::Node> node1 = osgDB::readNodeFile("cow.osg");
	osg::ref_ptr<osg::Node> node2 = osgDB::readNodeFile("cessna.osgt");
	osg::ref_ptr<osg::Node> node3 = osgDB::readNodeFile("cube_mapped_torus.osgt");

	root->addChild(node1);
	root->addChild(node2);
	root->addChild(node3);

	viewer->setSceneData(root.get());
	viewer->addEventHandler(new nodePick);
	viewer->run();
}

2. 高亮显示

分为三步:

  1. 将节点高亮显示。
  2. 在场景中操控(点击切换高亮)。
  3. 设置只有点击某些特定节点才会高亮(因为有些节点可能并不需要高亮显示)。

2.1. 将节点高亮显示

      原理:在osg里有一些特效可以直接使用,我们可能要用到的有两个:osgFX::Scribe(网格化)和osgFX::Outline(显示轮廓)。注意outline和node为父子节点关系,后面实现切换高亮功能需要理解这个关系。

osg::ref_ptr<osgFX::Outline> outline = new osgFX::Outline();
outline->addChild(node);

2.2. 点击切换高亮

      原理:关键在于如何判断当前选择的节点是否处于高亮模式。将前面*“点击节点透明”*部分置换为以下代码,并添加头文件#include <osgFX/Outline>

//点击节点切换高亮
osg::ref_ptr<osg::Group> parent = new osg::Group;
parent = dynamic_cast<osg::Group*> (nodePath[nodePath.size() - 2]);//当前选择节点的父节点
osgFX::Outline *ot = dynamic_cast<osgFX::Outline*>(parent.get());
if (!ot) //若ot不存在(未高亮) (node->parent)=>(node->outline->parent)
{
	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);
}

若未高亮,则代码中的parent为当前node节点的父节点,绘制outline直接替换node;
若高亮,则代码中的parent为outline(需转换格式),需获取当前outline的父节点,然后替换outline。

2.3 控制特定节点高亮

        考虑到整个场景中并非所有的节点都需要显示功能,因此尝试只给特定节点开启此功能。
已否定的方法:用setname和getname进行判断,但每次操作都会刷新,命名无效。
原理:将所有需要显示高亮的节点分到同一个group,再对当前group进行判断,若为特定group则进行高亮操作。
关键点:如何判断当前节点所属group为特定group。

在main函数里将节点按是否需要高亮分类(这里设定第一个group为需要高亮的团体)

	group1->addChild(node1);
	group1->addChild(node2);
	group2->addChild(node3);

	root->addChild(group1);
	root->addChild(group2);
  •  在handle函数里获取特定group0(与自己在主函数中的设置有关,此处为root的第一个子节点)
 osg::ref_ptr<osg::Group> group0 = dynamic_cast<osg::Group*>( viewer->getSceneData()->asGroup()->getChild(0));
  • 获取当前节点所属group(关键)
osg::ref_ptr<osg::Group> group =dynamic_cast<osg::Group*>( nodePath[2]);	
  • 判断当前节点所属group是否为特定group
    if (group == group0){//在此处对节点进行高亮切换操作}
    

    完整代码如下:

#include <osgViewer/Viewer>
#include <osgDB/ReadFile>
#include <osgGA/GUIEventHandler>
#include <osgFX/Scribe>
#include <osgFX/Outline>
#include <osgViewer/ViewerEventHandlers>

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==group0)
				{
					//点击节点切换高亮
					parent = dynamic_cast<osg::Group*> (nodePath[nodePath.size() - 2]);//当前选择节点的父节点
					osgFX::Outline *ot = dynamic_cast<osgFX::Outline*>(parent.get());
					if (!ot) //若ot不存在(未高亮) (node->parent)=>(node->outline->parent)
					{
						 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);
				  }
			  }
		  }
		}
		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> group1 = new osg::Group;
	osg::ref_ptr<osg::Group> group2 = new osg::Group;

	osg::ref_ptr<osg::Node> node1 = osgDB::readNodeFile("cow.osg");
	osg::ref_ptr<osg::Node> node2 = osgDB::readNodeFile("cessna.osgt");
	osg::ref_ptr<osg::Node> node3 = osgDB::readNodeFile("cube_mapped_torus.osgt");


	group1->addChild(node1);
	group1->addChild(node2);
	group2->addChild(node3);

	root->addChild(group1);
	root->addChild(group2);

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

效果如下:

我们前面将牛和滑翔机分到group1,甜甜圈分到group2,并设定group1为需要高亮的部分。
可以看到此处点击牛和滑翔机可以自由进行高亮切换,而点击甜甜圈则不会有任何反应。
由此达到我们想要的特定节点拾取的效果。

总结:关键在于判断依据,这里我们选择了判断节点当前所属group的方式进行判断。而这其中如何判断当前节点所属group也是一个重要的关键点。
 
原文链接:https://blog.csdn.net/lemon_haha/article/details/89680634

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
如果你已经成功获取了VR手柄模型,那么在OpenVR和OSG显示它应该不难。以下是一些基本的步骤: 1. 在OSG中创建一个节点,将VR手柄模型添加为其子节点。 2. 在OpenVR中创建手柄设备的句柄。 3. 在渲染循环中,使用OpenVR获取手柄的状态信息(例如位置、姿态等)。 4. 将手柄的状态信息应用于OSG节点,以便在VR中正确显示手柄。 下面是一些示例代码,可以帮助你更好地理解这些步骤: ```cpp // 创建手柄模型节点 osg::ref_ptr<osg::Node> controllerModel = osgDB::readNodeFile("path/to/controller/model.osg"); osg::ref_ptr<osg::PositionAttitudeTransform> controllerTransform = new osg::PositionAttitudeTransform(); controllerTransform->addChild(controllerModel); // 创建OpenVR手柄设备句柄 vr::TrackedDeviceIndex_t controllerIndex = vr::k_unTrackedDeviceIndexInvalid; vr::VRControllerState_t controllerState = {}; vr::ETrackedDeviceClass deviceClass = vr::VRSystem()->GetTrackedDeviceClass(controllerIndex); if (deviceClass == vr::TrackedDeviceClass_Controller || deviceClass == vr::TrackedDeviceClass_GenericTracker) { controllerIndex = deviceIndex; } // 在渲染循环中更新手柄状态 while (!done) { // 获取手柄状态 vr::VRSystem()->GetControllerState(controllerIndex, &controllerState, sizeof(controllerState)); // 获取手柄位置和姿态 vr::TrackedDevicePose_t pose = vr::TrackedDevicePose_t(); vr::VRControllerState_t state = vr::VRControllerState_t(); vr::VRSystem()->GetDeviceToAbsoluteTrackingPose(vr::TrackingUniverseStanding, 0, &pose, 1); vr::VRSystem()->GetControllerState(controllerIndex, &state, sizeof(vr::VRControllerState_t)); // 将手柄状态应用于OSG节点 osg::Quat orientation = osg::Quat(pose.mDeviceToAbsoluteTracking.m[0][0], pose.mDeviceToAbsoluteTracking.m[1][0], pose.mDeviceToAbsoluteTracking.m[2][0], pose.mDeviceToAbsoluteTracking.m[0][1], pose.mDeviceToAbsoluteTracking.m[1][1], pose.mDeviceToAbsoluteTracking.m[2][1], pose.mDeviceToAbsoluteTracking.m[0][2], pose.mDeviceToAbsoluteTracking.m[1][2], pose.mDeviceToAbsoluteTracking.m[2][2]); osg::Vec3 position = osg::Vec3(pose.mDeviceToAbsoluteTracking.m[3][0], pose.mDeviceToAbsoluteTracking.m[3][1], pose.mDeviceToAbsoluteTracking.m[3][2]); controllerTransform->setPosition(position); controllerTransform->setAttitude(orientation); // 渲染场景 viewer->frame(); } ``` 希望这些代码可以帮助你在OpenVR和OSG中正确显示VR手柄模型
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值