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

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. lock free数据结构内存回收技术-hazard pointer

    lock free数据结构一般来说拥有比基于lock实现的数据结构更高的性能,但是其实现比基于lock的实现更为复杂,需要处理的难题包括预防ABA问题,内存如何重用和回收等.通常,最简单最有效的处理A ...

  2. MySQL Group Replication配置

    MySQL Group Replication简述 MySQL 组复制实现了基于复制协议的多主更新(单主模式). 复制组由多个 server成员构成,并且组中的每个 server 成员可以独立地执行事 ...

  3. 3. 跟踪标记 (Trace Flag) 1204, 1222 抓取死锁信息

    跟踪标记:1204/1222 功能及用途: 捕获SQL Server死锁信息,并自动存放到错误日志(ERRORLOG)中. 举例: USE tempdb GO CREATE TABLE t1(id i ...

  4. UIButton的两种block传值方式

    UIButton的两种block传值方式 方式1 - 作为属性来传值 BlockView.h 与 BlockView.m // // BlockView.h // Block // // Create ...

  5. [控件] 创建出条形间隔效果的背景LineBackgroundView

    创建出条形间隔效果的背景LineBackgroundView 效果: 使用: // // ViewController.m // LineBackgroundView // // Created by ...

  6. [C++] 用Xcode来写C++程序[6] Name visibility

    用Xcode来写C++程序[6] Name visibility 此小结包括了命名空间的一些使用细节 命名空间 #include <iostream> using namespace st ...

  7. 2018年阿里巴巴关于java重要开源项目汇总

    1.分布式应用服务开发的一站式解决方案 Spring Cloud Alibaba Spring Cloud Alibaba 致力于提供分布式应用服务开发的一站式解决方案.此项目包含开发分布式应用服务的 ...

  8. zabbix的日常监控-分布式监控(十)

    参考博文:http://blog.51cto.com/jinlong/2051966 zabbix proxy 可以代替 zabbix server 检索客户端的数据,然后把数据汇报给 zabbix ...

  9. Basestation函数解析(二)

    ---恢复内容开始--- 这部分从Basestation的RecvDataThread开始,流程为 RecvDataThread->RecvData->Decoder->PostDa ...

  10. 打印pdf

    #include "pdf_print_helper.h" pdf_print_helper::pdf_print_helper(){ } pdf_print_helper::~p ...