1、默認的相機和全部模型求交的方式spa
1.1 傳統的模型與屏幕點求交的方法以下:3d
1 osgViewer::View* viewer = dynamic_cast<osgViewer::View*>(&aa); 2 if ( viewer ) 3 { 4 osg::ref_ptr<osgUtil::LineSegmentIntersector> intersector = 5 new osgUtil::LineSegmentIntersector(osgUtil::Intersector::WINDOW, ea.getX(), ea.getY()); 6 osgUtil::IntersectionVisitor iv( intersector.get() ); 7 viewer->getCamera()->accept( iv ); 8 9 if ( intersector->containsIntersections() ) 10 { 11 osgUtil::LineSegmentIntersector::Intersection result = *(intersector->getIntersections().begin()); 12 doUserOperations( result ); 13 } 14 }
從上面能夠知道經過點擊屏幕上一點其實就是構造一根線,而後將這條線和場景中的模型進行碰撞檢測,會生成一個結果集,經過遍歷結果集就能夠處理相交的點,默認結果集中第一個點就是最近的相交點code
可是在osg和點雲結合的程序中,經過線和點雲求交是幾乎沒有交點的,因此咱們須要重寫與點雲模型的求交器,下面的PointIntersector求交器就是派生自osgUtil::LineSegmentIntersector,而後重寫求交邏輯的點雲模型求交器,主要參考的就是OpenSceneGraph Cookbook,下面就是點雲模型和屏幕點求交的用法:orm
1.二、OSG中與點雲模型選點的方法:對象
1 osg::ref_ptr<PointIntersector> intersector = new PointIntersector(osgUtil::Intersector::WINDOW, ea.getX(), ea.getY()); 2 osgUtil::IntersectionVisitor iv(intersector.get()); 3 viewer->getCamera()->accept(iv); 4 5 if (intersector->containsIntersections()) 6 { 7 //osg::Vec3d worldpoint = CRealInteractionUtil::getNeartestPoint(intersector, osg::Vec2f(ea.getX(), ea.getY()), transformMatrix*vpw); 8 PointIntersector::Intersection result = *intersector->getIntersections().begin();
//....
9 }
以上經過osg裏面重寫的求交器能夠與場景中的點雲模型進行求交,而後求得相交點的座標,求交的原理大概就是PointIntersector求交器首先構造一個管狀空間,此空間參數能夠設置,默認半徑是兩米,因此求交的結果集是屏幕點生成線,而後經過線擴充成圓柱,根據此圓柱和點雲模型求得結果集,結果集會包括屏幕點附近的點,此時如何知道結果集中哪一個點時認爲認爲的選中點呢?默認結果集中第一個結果就是最近的相交點blog
2、指定的模型節點和相機求交的方式get
經過以上方式也能夠求得和點雲求交選中點的座標,但若是是單獨與osg中的點雲節點求交,此時就不能經過屏幕點構造求交器了,緣由以下:it
camera中的點都是基於屏幕的二維座標,用屏幕點構造求交器也是二維座標,因此二者能夠進行求交得出碰撞點io
特定節點中的點多是基於世界座標系的三維點,因此求交器也得是世界座標系的三維點來構造的,若是用屏幕點構造求交器去求交就會致使沒結果,由於座標系沒有統一塊兒來ast
因此須要先構造三維場景中的一個開始點和一個結束點構造求交器,以下:
1 osgViewer::View* viewer = dynamic_cast<osgViewer::View*>(&aa); 2 if (!viewer) 3 { 4 return false; 5 } 6 osg::Matrixd Matrix_V = viewer->getCamera()->getViewMatrix();//觀察矩陣-將對象由世界座標變換爲像機座標 7 osg::Matrixd Matrix_P = viewer->getCamera()->getProjectionMatrix();//投影矩陣-投影到屏幕 8 osg::Matrixd Matrix_W = viewer->getCamera()->getViewport()->computeWindowMatrix();//視口矩陣-將投影座標變換到二維視口 9 osg::Matrixd vwp = Matrix_V*Matrix_P*Matrix_W; //求得 世界到屏幕的矩陣 10 osg::Matrixd inverseVPW = osg::Matrixd::inverse(vwp); 11 osg::Vec3d world_sta = osg::Vec3d(ea.getX(), ea.getY(), 0)*inverseVPW;//屏幕座標轉成世界座標 12 osg::Vec3d world_end = osg::Vec3d(ea.getX(), ea.getY(), 1)*inverseVPW; 13 osg::ref_ptr<PointIntersector> intersector = new PointIntersector(world_sta, world_end); 14 osgUtil::IntersectionVisitor iv(intersector.get()); 15 m_pDataManagerSingleton->getVectorNode()->accept(iv); 16 if (!intersector->containsIntersections()) 17 { 18 return false; 19 } 20 osg::Vec3d worldpoint = CRealInteractionUtil::getNeartestPoint(intersector, osg::Vec2f(ea.getX(), ea.getY()), vwp); 21 PointIntersector::Intersection result = *(intersector->getIntersections().begin());
1 osg::Vec3d CRealInteractionUtil::getNeartestPoint(PointIntersector* intersector, osg::Vec2f& curScreenXY, osg::Matrixd& vpw) 2 { 3 vector<osg::Vec3d> points; 4 for (osgUtil::LineSegmentIntersector::Intersections::iterator iter = intersector->getIntersections().begin(); iter != intersector->getIntersections().end(); iter++) 5 { 6 points.push_back(iter->getWorldIntersectPoint()); 7 } 8 float distance = 10000; 9 osg::Vec3d curNeartestPoint; 10 for (int i = 0; i < points.size(); i++) 11 { 12 osg::Vec3d tempPoint = points[i] * vpw; 13 osg::Vec2f tempScreenXY = osg::Vec2f(tempPoint[0], tempPoint[1]); 14 float lenth = (tempScreenXY - curScreenXY).length2(); 15 if (lenth < distance) 16 { 17 distance = lenth; 18 curNeartestPoint = points[i]; 19 } 20 } 21 return curNeartestPoint; 22 }
以上代碼就是經過三維中的一個開始點和一個結束點構造一個柱狀空間與點雲模型求交,此時會求出不少個相交的點結果,若是咱們默認也認爲結果集的第一個就是正確的點,那就錯了,開始我也是如此使用的,可是始終以爲會選偏,就是選不許,返回的第一個點老是在屏幕點附近,而不是正中心的那個點,即便我把半徑設爲很小,仍是會偏,由於求交的結果集是在一個圓柱裏面的,都是雜亂無章的,咱們是沒法判斷哪一個是正確的那個點的,此時咱們能夠將結果集的三維點先投影到屏幕中,經過與屏幕點的點再次求一個最近點,此時這個點的三維座標就是正確的點雲求交點了