OSG鼠标选择求交

 转自:http://blog.csdn.net/tmljs1988/article/details/7814167

 

求交方法一:(用WINDOW坐标值,在相机下求交)
//osg::ref_ptr<osgUtil::LineSegmentIntersector > picker = newosgUtil::LineSegmentIntersector(osgUtil::Intersector::WINDOW,ea.getX(), ea.getY());
//osgUtil::IntersectionVisitoriv( 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::IntersectionVisitoriv( picker.get());
g_grpMouse->getParent(0)->getChild( 0)->asGroup()->getChild( 0)->accept( iv);//模型求交

//求最前交点方法一:
if(picker->containsIntersections())
{ //获取最前的交点。
 osg::Vec3 ptWorldIntersectPointFirst= picker->getFirstIntersection().getWorldIntersectPoint();
 cout<<"worldcoords vertex("<<ptWorldIntersectPointFirst.x()<<","
  <<ptWorldIntersectPointFirst.y()<< ","<<ptWorldIntersectPointFirst.z()<<")"<<std::endl;
}

/*下面方法也可以计算求出最前的交点:*/
//求最前交点方法二:
/*doubledLen2Shortest= DBL_MAX, dLenTmp; osgUtil::LineSegmentIntersector::Intersections::iteratorhitrShortest;
osgUtil::LineSegmentIntersector::Intersectionsintersections= 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::Vec3ptEye= 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: publicosgGA::GUIEventHandler
{
public:
 /**构造函数*/
 CHUD_viewPoint(osgText::Text*updateText):
 m_text(updateText){}
 ~CHUD_viewPoint(){}
 virtual bool handle(constosgGA::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(constosgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter& aa)
{
 switch(ea.getEventType())
 {
  //case(osgGA::GUIEventAdapter::FRAME):
  // {
  // osgViewer::Viewer*viewer = dynamic_cast<osgViewer::Viewer*>(&aa);
  // if(viewer)
  // {
 // osg::Vec3vCenter, vUp;
  // viewer->getCamera()->getViewMatrixAsLookAt(m_vPosEye, vCenter, vUp);//获取视点信息
 // UpdateText(viewer, ea);//更新文字信息
  // }
  // returntrue;
  // }
 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::Vec3p tEye= 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 = newosg::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::BoundingSpherebs( ptCnt, 100);
    geode->setInitialBound(bs);
    g_grpMouse->removeChildren(0, g_grpMouse->getNumChildren());
    g_grpMouse->addChild(geode);
    //获取从根节点到当前节点的路径向量
    osg::Node PathListparentNodePaths = geode->getParentalNodePaths();
    if( !parentNodePaths.empty())
    {
     osg::Matrixd mt= computeWorldToLocal( parentNodePaths[ 0]);
    }

    求交
    //osg::ref_ptr<osgUtil::LineSegmentIntersector > picker = newosgUtil::LineSegmentIntersector(
    // osgUtil::Intersector::WINDOW,ea.getX(), ea.getY());
    //osgUtil::IntersectionVisitoriv( 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::IntersectionVisitoriv( 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())
    //{
    // doubledLen2Shortest= DBL_MAX, dLenTmp;
    // osgUtil::LineSegmentIntersector::Intersections::iteratorhitrShortest;
    // osgUtil::LineSegmentIntersector::Intersectionsintersections= 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<<"worldcoords vertex("<< hitrShortest->getWorldIntersectPoint().x()<<","
        // <<hitrShortest->getWorldIntersectPoint().y()<<","
    // <<hitrShortest->getWorldIntersectPoint().z()<<")"<<std::endl;
    // //高亮此点
    // doubledPointRadius= 15.0f;
    // osg::ShapeDrawable*pShd= new osg::ShapeDrawable(
    // newosg::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<<"worldcoords vertex("<<ptWorldIntersectPointFirst.x()<<","
      <<ptWorldIntersectPointFirst.y()<< ","<<ptWorldIntersectPointFirst.z()<<")"<<std::endl;
     //高亮此点
     doubled PointRadius= 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::stringfont("fonts/arial.TTF");//此处设置的是汉字字体"fonts/STCAIYUN.TTF"
 text->setFont(font);
 //设置文字显示的位置(左下为(0,0),X正向朝右,Y正向朝上)
 osg::Vec3position( 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= newosg::MatrixTransform();
 pmt->setMatrix(m);
 pmt->addChild(model.get());
 osg::ref_ptr<osg::Group>root= new osg::Group;
 root->addChild(pmt.get());//加入某个模型
 osgText::Text*text = new osgText::Text;
 root->addChild(createHUD_viewPoint( text));//加入HUD文字
 osg::ref_ptr<CHUD_viewPoint> pHUD= newCHUD_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(newosg::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;
}


 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要实现 osg 鼠标点击获取经纬度,可以通过以下步骤: 1. 获取鼠标点击事件。 2. 将鼠标点击事件中的坐标转换为屏幕坐标系下的坐标。 3. 将屏幕坐标系下的坐标转换为地球坐标系下的坐标。 4. 将地球坐标系下的坐标转换为经纬度。 下面是一个实现 osg 鼠标点击获取经纬度的示例代码: ``` void handleMouseClick(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa) { if (ea.getEventType() == osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON && ea.getButtonMask() == osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON) { osgViewer::Viewer* viewer = dynamic_cast<osgViewer::Viewer*>(&aa); if (viewer) { osg::Vec3d worldCoords; osg::Vec3d eye, center, up; viewer->getCamera()->getViewMatrixAsLookAt(eye, center, up); osg::Matrixd viewMatrix = viewer->getCamera()->getViewMatrix(); osg::Matrixd projMatrix = viewer->getCamera()->getProjectionMatrix(); osg::Viewport* viewport = viewer->getCamera()->getViewport(); osg::Vec3d mouseCoords(ea.getX(), ea.getY(), 0); mouseCoords = mouseCoords * osg::Matrixd::inverse(projMatrix); mouseCoords = mouseCoords * osg::Matrixd::inverse(viewMatrix); mouseCoords = mouseCoords + eye; osg::EllipsoidModel* ellipsoid = new osg::EllipsoidModel(); osg::Vec3d latLonAlt; ellipsoid->convertXYZToLatLongHeight(mouseCoords, latLonAlt.x(), latLonAlt.y(), latLonAlt.z()); std::cout << "Latitude: " << osg::RadiansToDegrees(latLonAlt.x()) << "\n" << "Longitude: " << osg::RadiansToDegrees(latLonAlt.y()) << std::endl; } } } ``` 这段代码中,handleMouseClick 函数用于处理鼠标点击事件,首先判断是否是鼠标左键点击事件,然后获取当前的 Viewer 对象。接着通过 Viewer 对象获取当前的相机位置和视角信息,以及当前的视口信息。然后将鼠标点击坐标转换为地球坐标系下的坐标,最后将地球坐标系下的坐标转换为经纬度。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值