osg项目经验1<MFC+OSG中模型点选效果>

  点选主要是重载osg的GUIEventHandler,

 1 class CPickHandler : public osgGA::GUIEventHandler{   //自定义回调函数名:CPickHandler
 2     osgViewer::Viewer * mViewer;   //在这里定义要在重载函数里使用的变量
 3     osg::Group * mGroup;
 4     osg::Node * lastSelect;
 5     osg::Node * replacedNode;
 6     int replaceNum;
 7 public:
 8     CPickHandler(osgViewer::Viewer * viewer, osg::Group *group) :mViewer(viewer),mGroup(group),lastSelect(0),replacedNode(0){}  //声明回调函数,括号中是回调函数需要传入的参数,冒号后的内容是给函数内自定义的变量初始化,前面是变量名,括  号内是初始化值。
 9     virtual bool handle(const osgGA::GUIEventAdapter & ea, osgGA::GUIActionAdapter & aa){
10         switch(ea.getEventType()){
11             case(osgGA::GUIEventAdapter::PUSH):{
12                 if(lastSelect){
13                     lastSelect = 0;
14                 }
15                 Pick(ea.getX(),ea.getY());    //ea即鼠标点击的地方,ea.getX(),ea.getY(),是获得鼠标点击的屏幕坐标。
16             }
17                 return true;
18         }
19         return false;
20     }
21 
22 protected:
23     void Pick(float x, float y){}//在pick()函数里传入了鼠标点击的屏幕坐标,然后可以根据屏幕坐标写你想要点击完成的动作。
24 }

其中需要注意的是,OSG中有多个坐标系,我们通过鼠标点击获得的只是屏幕坐标,我们往往需要在场景中添加东西时,都需要得到某个点的世界坐标才能比较好操作:

但是在我们知道是哪个节点的情况下,我们可以根据:

geode->getBound().center() * osg::computeLocalToWorld(geode->getParentalNodePaths()[0])

来获得节点geode的世界坐标。

我的项目的3维模型是由Obj格式导出的ive和osg文件,原始的obj模型是用sketchup做的,在制作的时候把几个模型创建组的时候会给每个模型单独的命名,而在osg中可以通过->getName()获得这些名字,我可以通过用文本浏览器notePad++打开模型的obj文件来查看这些名字,这些名字的命名都是g mash开头的,为了方便,我把每个模型的各个部分的命名改成相同的,用python很好解决这个问题。

那么我的pick函数是这样的:

 1 void Pick(float x, float y){
 2         osgUtil::LineSegmentIntersector::Intersections intersections;
 3 
 4         if(mViewer->computeIntersections(x, y, intersections)){
 5             osgUtil::LineSegmentIntersector::Intersection intersection = *intersections.begin();
 6             for(osgUtil::LineSegmentIntersector::Intersections::iterator hitr = intersections.begin(); hitr!= intersections.end(); ++hitr){
 7                 if(!hitr->nodePath.empty() && !(hitr->nodePath.back()->getName().empty())){
 8                     const osg::NodePath& np = hitr->nodePath;
 9                     
10                     for(int i = np.size() - 1; i >= 0; --i){     //遍历选中的节点
11                         osg::Node* nd = dynamic_cast<osg::Node *> (np[i]);
12                         if(nd){
13                             if(nd->getName()=="pipelineTeam1"){    //根据模型的名字判断是否选中了某个模型
14                                     /*
15                                     在这儿写对该模型做的操作
16                                     */
17                             }
18                             return;
19                         }
20                     }
21                 }
22             }
23         }

但是,这只是写好了一个回调函数,最后需要在osg控制类(我的是OSG_MFC.cpp)中的void cOSG::InitCameraConfig(void){}函数中加上一句:

mViewer->addEventHandler(new CPickHandler(mViewer, mRoot));  //要把指针转为引用 ,因为mViewer定义的时候是 osgViewer::Viewer* mViewer;现在要使用&mViewer

那么在我们点击屏幕某点的时候,就会自动调用回调函数中的pick()函数,进行其中的操作。

我的项目在pick()回调中,做到了在选中节点的位置添加一个Geometry,在Geometry上显示文字消息,并给选中的模型加上选中效果,可以做成高亮显示和加上高亮的(自定义颜色)的边框,这些会在下一篇文章中介绍。

原文地址:https://www.cnblogs.com/xiaocainiao2hao/p/4541401.html