• 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上显示文字消息,并给选中的模型加上选中效果,可以做成高亮显示和加上高亮的(自定义颜色)的边框,这些会在下一篇文章中介绍。

  • 相关阅读:
    Linux环境下配置Google Test、TBB、OpenMP和OpenCV
    构建一个真实的应用电子商务SportsStore(六)
    编写简单的c运行库(一)
    构建一个真实的应用电子商务SportsStore(七)
    Entity Framework性能测试
    C++在VS下创建、调用dll
    Contextfree Grammar的编译器设计和实现
    XP方法概述
    项目代码风格要求
    WCF学习 第三天 事务的使用
  • 原文地址:https://www.cnblogs.com/xiaocainiao2hao/p/4541401.html
Copyright © 2020-2023  润新知