赞
踩
取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 将节点高亮显示
原理:在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。
group1->addChild(node1);
group1->addChild(node2);
group2->addChild(node3);
root->addChild(group1);
root->addChild(group2);
osg::ref_ptr<osg::Group> group0 = dynamic_cast<osg::Group*>( viewer->getSceneData()->asGroup()->getChild(0));
osg::ref_ptr<osg::Group> group =dynamic_cast<osg::Group*>( nodePath[2]);
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://www.cnblogs.com/ylwn817/articles/2144696.html
分为以下三步:
3.1 显示文字框
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。