OSG鼠標選擇求交

OSG鼠標選擇求交

////求交方法一:(用WINDOW座標值,在相機下求交)

           //osg::ref_ptr< osgUtil::LineSegmentIntersector > picker = new osgUtil::LineSegmentIntersector(

           //  osgUtil::Intersector::WINDOW, ea.getX(), ea.getY());

           //osgUtil::IntersectionVisitor iv( picker.get());

           //cameraMaster->accept( iv);//(從相機往下遍歷)

 

//求交方法二:(直接用view求交)

//view->computeIntersections( x, y, intersections);

 

//求交方法三:(用世界座標值,既可在某個節點node下求交,也可在相機下求交。但需注意,在某個節點node下求交時,需要把該node的有矩陣變換的父節點都用上,比如根節點->MT節點->cow模型節點,則可用MT節點->accept( iv)或根節點->accept( iv)。求交時是根據執行accept( iv)的節點向下遍歷,求出節點的真實世界座標。而如果用cow->accept( iv) ,則會忽略父節點的MT節點,導致求不出真正的世界座標值,這樣求交會產生錯誤)

           osg::ref_ptr< osgUtil::LineSegmentIntersector > picker =new osgUtil::LineSegmentIntersector(

              nearPoint, farPoint);//線段(真實的世界座標)

           osgUtil::IntersectionVisitor iv( picker.get());

    g_grpMouse->getParent( 0)->getChild( 0)->asGroup()->getChild( 0)->accept( iv);//模型求交

 

//求最前交點 方法一:

if (picker->containsIntersections())

           {  //獲取最前的交點。

              osg::Vec3 ptWorldIntersectPointFirst= picker->getFirstIntersection().getWorldIntersectPoint();

              cout<<"world coords vertex("<< ptWorldIntersectPointFirst.x()<<","

                  << ptWorldIntersectPointFirst.y()<< ","<< ptWorldIntersectPointFirst.z()<<")"<< std::endl;

             

           }

/*下面方法也可以計算求出最前的交點:*/

//求最前交點 方法二:

    /*double dLen2Shortest= DBL_MAX, dLenTmp;           osgUtil::LineSegmentIntersector::Intersections::iterator hitrShortest;

              osgUtil::LineSegmentIntersector::Intersections intersections= picker->getIntersections();

           for( osgUtil::LineSegmentIntersector::Intersections::iterator hitr = intersections.begin();

                  hitr != intersections.end();

                  ++hitr)

              {

                  //求離視點最近的點,即鼠標選擇的最前面的點

                  dLenTmp= ( ptEye.x()- hitr->getWorldIntersectPoint().x())*

                     ( ptEye.x()- hitr->getWorldIntersectPoint().x())+

                     ( ptEye.y()- hitr->getWorldIntersectPoint().y())*

                     ( ptEye.y()- hitr->getWorldIntersectPoint().y())+

                     ( ptEye.z()- hitr->getWorldIntersectPoint().z())*

                     ( ptEye.z()- hitr->getWorldIntersectPoint().z());

                  if ( dLen2Shortest> dLenTmp)

                  {

                     dLen2Shortest= dLenTmp;

                     hitrShortest= hitr;                   

                  }

              }

其中ptEye爲視點的世界座標值:

osg::Matrix _inverseMV;

           _inverseMV.invert( cameraMaster->getViewMatrix());

           osg::Vec3 ptEye= osg::Vec3(  0, 0, 0) * _inverseMV;

*/

 

參考代碼如下:

/*OSG中的HUD實時顯示視點座標*/

#include <osgDB/ReadFile>

#include <osgViewer/Viewer>

#include <osg/Geode>

#include <osg/Depth>

#include <osg/CameraNode>

#include <osgText/Text>

#include <osgGA/TrackballManipulator>

#include <osg/LineWidth>

#include <osg/Point>

#include <osg/ShapeDrawable>

#include <osg/MatrixTransform>

 

 

 

#include <iostream>

#include <sstream>

 

#pragma comment( lib, "osgd.lib"); //.在Debug版本下的庫名都加d,如"osgd.lib"

#pragma comment( lib, "osgDBd.lib")

#pragma comment( lib, "osgViewerd.lib");

#pragma comment( lib, "osgTextd.lib");

#pragma comment( lib, "osgGAd.lib");

#pragma comment( lib, "osgUtild.lib");

 

osg::ref_ptr<osg::Group> g_grpMouse;

 

using namespace std;

 

//事件類

class CHUD_viewPoint: public osgGA::GUIEventHandler  

{

public:  

 

    /**構造函數*/

      CHUD_viewPoint(osgText::Text* updateText):

      m_text(updateText) {}

 

      ~CHUD_viewPoint(){}

 

      virtual bool handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter& aa);

      void UpdateText(osgViewer::Viewer* viewer,const osgGA::GUIEventAdapter&);

 

      /**LABEL*/

      void setLabel(const std::string& name)

      {

         if ( m_text.get())

         {

             m_text->setText(name); 

         }

      }

 

protected

    osg::Vec2 m_vPosWindowMouse;//鼠標單擊處的窗口座標

 

    osg::ref_ptr<osgText::Text>  m_text;//視點信息,會動態改變

};

 

bool CHUD_viewPoint::handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter& aa)

{

    switch(ea.getEventType())

    {

    //case(osgGA::GUIEventAdapter::FRAME):

    //  {

    //     osgViewer::Viewer* viewer = dynamic_cast<osgViewer::Viewer*>(&aa);

 

    //     if (viewer)

    //     {

    //         osg::Vec3 vCenter, vUp;

    //         viewer->getCamera()->getViewMatrixAsLookAt( m_vPosEye, vCenter, vUp);//獲取視點信息

    //         UpdateText( viewer, ea);//更新文字信息       

 

    //     }

 

    //     return true; 

    //  }    

    case( osgGA::GUIEventAdapter::PUSH):

    {

       m_vPosWindowMouse.set( ea.getX(), ea.getY());//鼠標單擊處的窗口座標

      

       osgViewer::Viewer* viewer = dynamic_cast< osgViewer::Viewer*>( &aa);

      

       if (viewer)

       {

           UpdateText( viewer, ea);//更新文字信息

 

           //主相機

           osg::ref_ptr<osg::Camera> cameraMaster = viewer->getCamera();

 

           osg::Matrix mvpw = cameraMaster->getViewMatrix() * cameraMaster->getProjectionMatrix();

           if ( cameraMaster->getViewport()) mvpw.postMult( cameraMaster->getViewport()->computeWindowMatrix());

 

           osg::Matrix _inverseMVPW;

           _inverseMVPW.invert( mvpw);

 

           osg::Vec3d nearPoint = osg::Vec3d( ea.getX(), ea.getY(), 0.0)* _inverseMVPW;//透視投影中Znear平面的交點

           osg::Vec3d farPoint = osg::Vec3d( ea.getX(), ea.getY(), 1.0)* _inverseMVPW;//透視投影中Zfar平面的交點

 

           osg::Vec3 vPosEye, vCenter, vUp;

           cameraMaster->getViewMatrixAsLookAt( vPosEye, vCenter, vUp);//獲取視點信息

 

 

           osg::Matrix _inverseMV;

           _inverseMV.invert( cameraMaster->getViewMatrix());

           osg::Vec3 ptEye= osg::Vec3(  0, 0, 0) * _inverseMV;//獲取視點座標

           osg::Vec3d deltaEye= ptEye- vPosEye;

           if ( deltaEye.length()< 1e-8)

           {

              cout<< "yes,eye\n";

           }

           else

           {

              cout<< "no,eye\n";

           }

 

           osg::Vec3d dir1= farPoint- nearPoint;

           dir1.normalize();

 

           osg::Vec3d dir2= farPoint- vPosEye;

           dir2.normalize();

 

           osg::Vec3d delta= dir1- dir2;

 

           //看視點、Znear平面的交點、Zfar平面的交點是否在同一直線上。經驗證,確定在同一直線上

           if ( delta.length()< 1e-8)

           {

              cout<< "yes,line\n";

           }

           else

           {

              cout<< "no,line\n";

           }

 

 

           osg::Geode* geode= new osg::Geode();

           osg::Geometry* pyramidGeometry = new osg::Geometry();

 

           geode->addDrawable( pyramidGeometry);

 

           osg::Vec3Array* pyramidVertices = new osg::Vec3Array;

           pyramidVertices->push_back( nearPoint);

           pyramidVertices->push_back( farPoint);

   

           pyramidGeometry->setVertexArray( pyramidVertices );

 

           //顏色

           osg::Vec4Array* colors = new osg::Vec4Array;

           colors->push_back( osg::Vec4(  1.0f, 0.0f, 0.0f, 1.0f) );//紅色

           pyramidGeometry->setColorArray( colors);

           pyramidGeometry->setColorBinding( osg::Geometry::BIND_OVERALL);

          

           //紅點表示透視投影中Znear平面的交點

          pyramidGeometry->addPrimitiveSet(  new osg::DrawArrays( osg::PrimitiveSet::POINTS, 0, 1/*3*/));

           //紅線表示鼠標點擊的線,其起點爲Znear平面交點,終點爲Zfar平面交點。

           pyramidGeometry->addPrimitiveSet(  new osg::DrawArrays( osg::PrimitiveSet::LINES, 0, 2));/**/

 

           ////設置線寬

           //osg::ref_ptr <osg::LineWidth> LineSize = new osg::LineWidth;

           //LineSize ->setWidth( 12.0) ;      

           //geode->getOrCreateStateSet()->setAttributeAndModes( LineSize.get (),osg::StateAttribute::ON);

 

           //設置點大小

           osg::ref_ptr <osg::Point> ptSize = new osg::Point;

           ptSize->setSize( 12.0) ;      

           geode->getOrCreateStateSet()->setAttributeAndModes( ptSize.get (),osg::StateAttribute::ON);          

          

           /*當只有一個點時,包圍球半徑爲,所以可能看不到這個點,故需要重新設置包圍球大小,可把包圍球半徑設大點。

           如對glider、cow等小模型,半徑取.1可以,對fountain.osg則.1太小。爲統一,可大些,如*/

           osg::Vec3d ptCnt= geode->getBound().center();

           double dRadius= geode->getBound().radius();

           //重新設置包圍球的半徑(可調用setInitialBound()

           osg::BoundingSphere bs( ptCnt, 100);

           geode->setInitialBound( bs);

 

           g_grpMouse->removeChildren( 0, g_grpMouse->getNumChildren());

           g_grpMouse->addChild( geode);

 

           //獲取從根節點到當前節點的路徑向量

           osg::NodePathList parentNodePaths = geode->getParentalNodePaths();

           if ( !parentNodePaths.empty())

           {

              osg::Matrixd mt= computeWorldToLocal( parentNodePaths[ 0]);

 

           }

 

           ////求交

           //osg::ref_ptr< osgUtil::LineSegmentIntersector > picker = new osgUtil::LineSegmentIntersector(

           //  osgUtil::Intersector::WINDOW, ea.getX(), ea.getY());

           //osgUtil::IntersectionVisitor iv( picker.get());

           ////g_grpMouse->getParent( 0)->getChild( 0)->accept( iv);//模型求交

           //cameraMaster->accept( iv);//模型求交(從相機往下遍歷)

 

           //求交

           osg::ref_ptr< osgUtil::LineSegmentIntersector > picker =new osgUtil::LineSegmentIntersector(

              nearPoint, farPoint);//線段(真實的世界座標)

           osgUtil::IntersectionVisitor iv( picker.get());

           //g_grpMouse->getParent( 0)->getChild( 0)->accept( iv);//模型求交/**/

           g_grpMouse->getParent( 0)->getChild( 0)->/*asGroup()->getChild( 0)->*/accept( iv);//模型求交/**/

            //               根節點     cow的MT節點

           //cameraMaster->accept( iv);//模型求交(從相機往下遍歷)

 

 

          

           //if (picker->containsIntersections())

           //{

           //  double dLen2Shortest= DBL_MAX, dLenTmp;

           //  osgUtil::LineSegmentIntersector::Intersections::iterator hitrShortest;

           //  osgUtil::LineSegmentIntersector::Intersections intersections= picker->getIntersections();

 

           //  for( osgUtil::LineSegmentIntersector::Intersections::iterator hitr = intersections.begin();

           //     hitr != intersections.end();

           //     ++hitr)

           //  {

           //     //求離視點最近的點,即鼠標選擇的最前面的點

           //     dLenTmp= ( ptEye.x()- hitr->getWorldIntersectPoint().x())*

           //         ( ptEye.x()- hitr->getWorldIntersectPoint().x())+

           //         ( ptEye.y()- hitr->getWorldIntersectPoint().y())*

           //         ( ptEye.y()- hitr->getWorldIntersectPoint().y())+

           //         ( ptEye.z()- hitr->getWorldIntersectPoint().z())*

           //         ( ptEye.z()- hitr->getWorldIntersectPoint().z());

           //     if ( dLen2Shortest> dLenTmp)

           //     {

           //         dLen2Shortest= dLenTmp;

           //         hitrShortest= hitr;                   

           //     }

           //  }

           // 

           //  //輸出

           //  if ( dLen2Shortest != DBL_MAX)

           //  {

           //     cout<<"world coords vertex("<< hitrShortest->getWorldIntersectPoint().x()<<","

           //         << hitrShortest->getWorldIntersectPoint().y()<<","

           //         << hitrShortest->getWorldIntersectPoint().z()<<")"<<std::endl;

 

           //     //高亮此點              

           //     double dPointRadius= 15.0f;

           //     osg::ShapeDrawable* pShd= new osg::ShapeDrawable(

           //         new osg::Sphere( hitrShortest->getWorldIntersectPoint(), dPointRadius));//繪製交點的球

           //     pShd->setColor( osg::Vec4( 0, 1, 0, 1));

           //     geode->addDrawable( pShd);

           //    

           //  }

 

 

           //}

 

           if (picker->containsIntersections())

           {

              osg::Vec3 ptWorldIntersectPointFirst= picker->getFirstIntersection().getWorldIntersectPoint();

              cout<<"world coords vertex("<< ptWorldIntersectPointFirst.x()<<","

                  << ptWorldIntersectPointFirst.y()<< ","<< ptWorldIntersectPointFirst.z()<<")"<< std::endl;

 

              //高亮此點              

              double dPointRadius= 15.0f;

              osg::ShapeDrawable* pShd= new osg::ShapeDrawable(

                  new osg::Sphere( ptWorldIntersectPointFirst, dPointRadius));

              pShd->setColor( osg::Vec4( 0, 1, 0, 1));

              geode->addDrawable( pShd);

 

           }

          

 

       }

       return true;

    }

    default:     

       return false

 

    }

}

 

void CHUD_viewPoint::UpdateText(osgViewer::Viewer* viewer,const osgGA::GUIEventAdapter&)

{

    std::string gdlist=""

 

    std::ostringstream os;

    os<<"MousePos(X: "<< m_vPosWindowMouse.x()<<",Y: "<< m_vPosWindowMouse.y()<<")";//座標

   

    gdlist = os.str(); 

 

    setLabel(gdlist); 

}

 

osg::Node* createHUD_viewPoint( osgText::Text* text)

{

    //設置字體

    std::string font("fonts/arial.TTF");//此處設置的是漢字字體 "fonts/STCAIYUN.TTF"

    text->setFont( font); 

    //設置文字顯示的位置(左下爲(0,0),X正向朝右,Y正向朝上)

    osg::Vec3 position( 100.0f, 10.0f,0.0f);

    text->setPosition(position);   

    text->setColor( osg::Vec4( 1, 1, 0, 1));

    text->setText(L"");//設置顯示的文字

    text->setCharacterSize(15);

    text->setDataVariance(osg::Object::DYNAMIC);//一定要設置字體爲動態,否則程序會卡住,死在那裏。(參照osgcatch

 

    //幾何體節點

    osg::Geode* geode = new osg::Geode();

    geode->addDrawable( text );//將文字Text作這drawable加入到Geode節點中

    //設置狀態

    osg::StateSet* stateset = geode->getOrCreateStateSet(); 

    stateset->setMode(GL_LIGHTING,osg::StateAttribute::OFF);//關閉燈光

    stateset->setMode(GL_DEPTH_TEST,osg::StateAttribute::OFF);//關閉深度測試

    //打開GL_BLEND混合模式(以保證Alpha紋理正確)

    stateset->setMode(GL_BLEND,osg::StateAttribute::ON);

 

    //相機

    osg::Camera* camera = new osg::Camera;

    //設置透視矩陣

    camera->setProjectionMatrix(osg::Matrix::ortho2D(0,600,0,600));//正交投影   

    //設置絕對參考座標系,確保視圖矩陣不會被上級節點的變換矩陣影響

    camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);

    //視圖矩陣爲默認的

    camera->setViewMatrix(osg::Matrix::identity());

 

    //設置背景爲透明,否則的話可以設置ClearColor 

    camera->setClearMask(GL_DEPTH_BUFFER_BIT);

    camera->setAllowEventFocus( false);//不響應事件,始終得不到焦點

 

    //設置渲染順序,必須在最後渲染

    camera->setRenderOrder(osg::CameraNode::POST_RENDER); 

 

    camera->addChild(geode);//將要顯示的Geode節點加入到相機

 

    return camera; 

};

 

 

int main( int argc, char **argv )

{

    osgViewer::Viewer viewer; 

 

    osg::ref_ptr< osg::Node> model = osgDB::readNodeFile("fountain.osg");// glider nathan

   

    osg::Matrix m;

    m.setTrans( 200, 0, 0);

    osg::ref_ptr< osg::MatrixTransform> pmt= new osg::MatrixTransform();

    pmt->setMatrix( m);

    pmt->addChild( model.get());

 

    osg::ref_ptr<osg::Group> root= new osg::Group; 

    //root->addChild( model.get());//加入某個模型

    root->addChild( pmt.get());//加入某個模型

 

 

    osgText::Text* text = new osgText::Text; 

    root->addChild( createHUD_viewPoint( text));//加入HUD文字

   

    osg::ref_ptr< CHUD_viewPoint> pHUD= new CHUD_viewPoint( text);

    viewer.addEventHandler( pHUD.get());

 

 

    //GraphicsContext設備上下文關鍵參數

    osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits ;

    traits->x = 200; 

    traits->y = 200; 

    traits->width = 600;

    traits->height = 600; 

    traits->windowDecoration = true

    traits->doubleBuffer = true;

    traits->sharedContext = 0; 

 

    osg::ref_ptr<osg::GraphicsContext> gc = osg::GraphicsContext::createGraphicsContext(traits.get());

    //gc->setClearColor( osg::Vec4f( 0.2f,0.2f,0.2f,1.0f));

    gc->setClearColor( osg::Vec4f( 0.0f, 1.0f, 0.0f, 1.0f)); //設置整個windows窗口顏色

    gc->setClearMask( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

   

    //主相機

    osg::ref_ptr<osg::Camera> cameraMaster = viewer.getCamera();

    cameraMaster->setGraphicsContext(gc.get());//設置GraphicsContext設備上下文

    //相機視口設置

    cameraMaster->setViewport(new osg::Viewport( 100, 100, traits->width, traits->height));/**/

 

   

    g_grpMouse= new osg::Group();

    //設置狀態

    osg::StateSet* stateset = g_grpMouse->getOrCreateStateSet(); 

    stateset->setMode( GL_LIGHTING,osg::StateAttribute::OFF);//關閉燈光

    //stateset->setMode( GL_DEPTH_TEST,osg::StateAttribute::OFF);//關閉深度測試

    root->addChild( g_grpMouse.get());

 

    //viewer.setUpViewInWindow( 0, 0, 600, 600);//設置窗口大小

          

 

    viewer.setSceneData( root.get());

    viewer.realize();

    viewer.run() ;  

   

    return 0;

}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章