點選主要是重載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上顯示文字消息,並給選中的模型加上選中效果,可以做成高亮顯示和加上高亮的(自定義顏色)的邊框,這些會在下一篇文章中介紹。