一、默认的相机和所有模型求交的方式

1.1 传统的模型与屏幕点求交的方法如下:

         osgViewer::View* viewer = dynamic_cast<osgViewer::View*>(&aa);
if ( viewer )
{
osg::ref_ptr<osgUtil::LineSegmentIntersector> intersector =
new osgUtil::LineSegmentIntersector(osgUtil::Intersector::WINDOW, ea.getX(), ea.getY());
osgUtil::IntersectionVisitor iv( intersector.get() );
viewer->getCamera()->accept( iv ); if ( intersector->containsIntersections() )
{
osgUtil::LineSegmentIntersector::Intersection result = *(intersector->getIntersections().begin());
doUserOperations( result );
}
}

从上面可以知道通过点击屏幕上一点其实就是构造一根线,然后将这条线和场景中的模型进行碰撞检测,会生成一个结果集,通过遍历结果集就可以处理相交的点,默认结果集中第一个点就是最近的相交点

但是在osg和点云结合的程序中,通过线和点云求交是几乎没有交点的,所以我们需要重写与点云模型的求交器,下面的PointIntersector求交器就是派生自osgUtil::LineSegmentIntersector,然后重写求交逻辑的点云模型求交器,主要参考的就是OpenSceneGraph Cookbook,下面就是点云模型和屏幕点求交的用法:

1.2、OSG中与点云模型选点的方法:

     osg::ref_ptr<PointIntersector> intersector = new PointIntersector(osgUtil::Intersector::WINDOW, ea.getX(), ea.getY());
osgUtil::IntersectionVisitor iv(intersector.get());
viewer->getCamera()->accept(iv); if (intersector->containsIntersections())
{
//osg::Vec3d worldpoint = CRealInteractionUtil::getNeartestPoint(intersector, osg::Vec2f(ea.getX(), ea.getY()), transformMatrix*vpw);
PointIntersector::Intersection result = *intersector->getIntersections().begin();
      //....
9   }

以上通过osg里面重写的求交器可以与场景中的点云模型进行求交,然后求得相交点的坐标,求交的原理大概就是PointIntersector求交器首先构造一个管状空间,此空间参数可以设置,默认半径是两米,所以求交的结果集是屏幕点生成线,然后通过线扩充成圆柱,根据此圆柱和点云模型求得结果集,结果集会包括屏幕点附近的点,此时如何知道结果集中哪个点时认为认为的选中点呢?默认结果集中第一个结果就是最近的相交点

二、指定的模型节点和相机求交的方式

通过以上方式也可以求得和点云求交选中点的坐标,但如果是单独与osg中的点云节点求交,此时就不能通过屏幕点构造求交器了,原因如下:

camera中的点都是基于屏幕的二维坐标,用屏幕点构造求交器也是二维坐标,所以两者可以进行求交得出碰撞点

特定节点中的点可能是基于世界坐标系的三维点,所以求交器也得是世界坐标系的三维点来构造的,如果用屏幕点构造求交器去求交就会导致没结果,因为坐标系没有统一起来

所以需要先构造三维场景中的一个开始点和一个结束点构造求交器,如下:

       osgViewer::View* viewer = dynamic_cast<osgViewer::View*>(&aa);
if (!viewer)
{
return false;
}
osg::Matrixd Matrix_V = viewer->getCamera()->getViewMatrix();//观察矩阵-将对象由世界坐标变换为像机坐标
osg::Matrixd Matrix_P = viewer->getCamera()->getProjectionMatrix();//投影矩阵-投影到屏幕
osg::Matrixd Matrix_W = viewer->getCamera()->getViewport()->computeWindowMatrix();//视口矩阵-将投影坐标变换到二维视口
osg::Matrixd vwp = Matrix_V*Matrix_P*Matrix_W; //求得 世界到屏幕的矩阵
osg::Matrixd inverseVPW = osg::Matrixd::inverse(vwp);
osg::Vec3d world_sta = osg::Vec3d(ea.getX(), ea.getY(), )*inverseVPW;//屏幕坐标转成世界坐标
osg::Vec3d world_end = osg::Vec3d(ea.getX(), ea.getY(), )*inverseVPW;
osg::ref_ptr<PointIntersector> intersector = new PointIntersector(world_sta, world_end);
osgUtil::IntersectionVisitor iv(intersector.get());
m_pDataManagerSingleton->getVectorNode()->accept(iv);
if (!intersector->containsIntersections())
{
return false;
}
osg::Vec3d worldpoint = CRealInteractionUtil::getNeartestPoint(intersector, osg::Vec2f(ea.getX(), ea.getY()), vwp);
PointIntersector::Intersection result = *(intersector->getIntersections().begin());
 osg::Vec3d CRealInteractionUtil::getNeartestPoint(PointIntersector* intersector, osg::Vec2f& curScreenXY, osg::Matrixd& vpw)
{
vector<osg::Vec3d> points;
for (osgUtil::LineSegmentIntersector::Intersections::iterator iter = intersector->getIntersections().begin(); iter != intersector->getIntersections().end(); iter++)
{
points.push_back(iter->getWorldIntersectPoint());
}
float distance = ;
osg::Vec3d curNeartestPoint;
for (int i = ; i < points.size(); i++)
{
osg::Vec3d tempPoint = points[i] * vpw;
osg::Vec2f tempScreenXY = osg::Vec2f(tempPoint[], tempPoint[]);
float lenth = (tempScreenXY - curScreenXY).length2();
if (lenth < distance)
{
distance = lenth;
curNeartestPoint = points[i];
}
}
return curNeartestPoint;
}

以上代码就是通过三维中的一个开始点和一个结束点构造一个柱状空间与点云模型求交,此时会求出很多个相交的点结果,如果我们默认也认为结果集的第一个就是正确的点,那就错了,开始我也是如此使用的,但是始终觉得会选偏,就是选不准,返回的第一个点总是在屏幕点附近,而不是正中心的那个点,即使我把半径设为很小,还是会偏,因为求交的结果集是在一个圆柱里面的,都是杂乱无章的,我们是无法判断哪个是正确的那个点的,此时我们可以将结果集的三维点先投影到屏幕中,通过与屏幕点的点再次求一个最近点,此时这个点的三维坐标就是正确的点云求交点了

OSG选取点云坐标不准的解决办法的更多相关文章

  1. PHP下的浮点运算不准的解决办法

    首先看一段代码: 首先看一段代码: <?php $a = 0.1; $b = 0.7; var_dump(($a + $b) == 0.8); 打印出来的值居然为 boolean false P ...

  2. pod导入融云路径报错解决办法

    build Settings中搜索sear Search Patchs下点开Library Search Paths 将$(inherited)"$(SRCROOT)/Pods"分 ...

  3. 利用jink调试程序,时间不准的解决办法

    前几天,做工程,遇到了利用jlink的SWD的模式调试程序,定时器延时不准的问题,上网搜了好多,终于找到了问题所在,感谢万能的网友.时间不对是因为Keil的设置问题. 以下是转自网友: 一.先说说仿真 ...

  4. WInforn中设置ZedGraph的焦点显示坐标格式化以及显示三个坐标数的解决办法

    场景 Winforn中设置ZedGraph曲线图的属性.坐标轴属性.刻度属性: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/10 ...

  5. 阿里云服务器被挖矿minerd入侵的解决办法

    上周末,更新易云盘的时候,发现阿里云服务器CPU很高,执行 top 一看,有个进程minerd尽然占用了90%多的CPU, 赶紧百度一下,查到几篇文章都有人遇到同样问题 Hu_Wen遇到的和我最相似, ...

  6. 阿里云vps上mysql挂掉的解决办法

    阿里云vps上mysql挂掉的解决办法 4条回复 用阿里云的vps用作blog服务器,系统很稳定,已经100多天一直运行正常,大概从上个月开始发现blog的mysql会有时挂掉,会收到短信通知.之前没 ...

  7. 【地图API】为何您的坐标不准?如何纠偏?

    原文:[地图API]为何您的坐标不准?如何纠偏? 摘要:各种坐标体系之间如何转换?到底有哪些坐标体系?什么是火星坐标?为什么我的坐标,在地图上显示会有偏移?本文详细解答以上问题.最后给出坐标拾取工具. ...

  8. 在阿里云服务器上安装完成并启动Tomcat后,通过http不能访问--解决办法

    在阿里云服务器上安装完成并启动Tomcat后,通过http不能访问的原因是阿里云平台为了安全设置了安全组策略,必须我们授权的端口,其他计算机才能通过http访问 解决办法:(这里以阿里轻量应用服务器为 ...

  9. 阿里云安装mysql后查看不到初始密码的解决办法

    在阿里云安装mysql后用grep 'A temporary password' /var/log/mysqld.log命令查看MySQL初始密码,毛线都没有看到,然后直接到/var/log/mysq ...

随机推荐

  1. 浅谈Java——泛型DAO

    首先解释一下为什么要学习泛型DAO.平时在写DAO的时候是一个接口对应一个实现类,实现类里面要写很多的操作数据库的方法.当我们有很多的javaben的时候我们会写很多的接口和实现类,并且里面的代码都是 ...

  2. 设置 ExpressRoute 和站点到站点并存连接

    配置站点到站点 VPN 和 ExpressRoute 共存连接具有多项优势. 可以将站点到站点 VPN 配置为 ExressRoute 的安全故障转移路径,或者使用站点到站点 VPN 连接到不是通过 ...

  3. Winform 多个窗口编辑同一条数据同步的实现

    场景: 一个主窗口中,可以在列表(DataGridView)里选中一条记录编辑,打开一个编辑窗口(非模态窗口),编辑窗口保存后需要刷新父窗口,由于编辑窗口是非模态窗口,如果打开了多个窗口,并且都是编辑 ...

  4. 安装Window Server 2008的些配置

    上次安装window server2008,由于server2008需要设置很多东西,不然用起来很不爽,就说IE吧,每次随便打开一个网页都要弹出n多窗口出来叫你添加到信任域里面!太烦人了![下面有解决 ...

  5. iOS设计模式 - 责任链

    iOS设计模式 - 责任链 原理图 说明 在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链.请求在这个链上传递,直到链上的某一个对象决定处理此请求.发出这个请求的客户端并不知道链 ...

  6. HTML-head头部浅析

    HTML结构 在sublime或HBuildr新建HTML文件,输入html:5,按下tab键后,自动生成的代码大致如下: <!DOCTYPE html> <html lang=&q ...

  7. 生成器-yield初接触

    什么是生成器? 生成器的实质就是迭代器 在python中有三种方式来获取生成器 1. 通过生成器函数 2. 通过各种推导式实现生成器 3. 通过数据的转换也可以获取生成器 将函数中的return换成y ...

  8. QQ邮箱验证码

    人的记忆有时候跟鱼一样,只有七秒钟,短暂的时间! .NET  Web窗体实现忘记密码,使用QQ邮箱验证修改 一.首先设置一下发送个人或企业发送的邮箱 二.登录邮箱进行设置,如图:  三.关闭邮箱 四. ...

  9. 团队作业1——团队展示&教辅宝

    1.队名:PHILOSOPHER 2.队员学号: [组长]金盛昌(201421122043).刘文钊(20142112255).陈笑林(201421122042). 张俊逸(201421122044) ...

  10. Spring-IOC 在非 web 环境下优雅关闭容器

    当我们设计一个程序时,依赖了Spring容器,然而并不需要spring的web环境时(Spring web环境已经提供了优雅关闭),即程序启动只需要启动Spring ApplicationContex ...