OSG选取点云坐标不准的解决办法
一、默认的相机和所有模型求交的方式
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选取点云坐标不准的解决办法的更多相关文章
- PHP下的浮点运算不准的解决办法
首先看一段代码: 首先看一段代码: <?php $a = 0.1; $b = 0.7; var_dump(($a + $b) == 0.8); 打印出来的值居然为 boolean false P ...
- pod导入融云路径报错解决办法
build Settings中搜索sear Search Patchs下点开Library Search Paths 将$(inherited)"$(SRCROOT)/Pods"分 ...
- 利用jink调试程序,时间不准的解决办法
前几天,做工程,遇到了利用jlink的SWD的模式调试程序,定时器延时不准的问题,上网搜了好多,终于找到了问题所在,感谢万能的网友.时间不对是因为Keil的设置问题. 以下是转自网友: 一.先说说仿真 ...
- WInforn中设置ZedGraph的焦点显示坐标格式化以及显示三个坐标数的解决办法
场景 Winforn中设置ZedGraph曲线图的属性.坐标轴属性.刻度属性: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/10 ...
- 阿里云服务器被挖矿minerd入侵的解决办法
上周末,更新易云盘的时候,发现阿里云服务器CPU很高,执行 top 一看,有个进程minerd尽然占用了90%多的CPU, 赶紧百度一下,查到几篇文章都有人遇到同样问题 Hu_Wen遇到的和我最相似, ...
- 阿里云vps上mysql挂掉的解决办法
阿里云vps上mysql挂掉的解决办法 4条回复 用阿里云的vps用作blog服务器,系统很稳定,已经100多天一直运行正常,大概从上个月开始发现blog的mysql会有时挂掉,会收到短信通知.之前没 ...
- 【地图API】为何您的坐标不准?如何纠偏?
原文:[地图API]为何您的坐标不准?如何纠偏? 摘要:各种坐标体系之间如何转换?到底有哪些坐标体系?什么是火星坐标?为什么我的坐标,在地图上显示会有偏移?本文详细解答以上问题.最后给出坐标拾取工具. ...
- 在阿里云服务器上安装完成并启动Tomcat后,通过http不能访问--解决办法
在阿里云服务器上安装完成并启动Tomcat后,通过http不能访问的原因是阿里云平台为了安全设置了安全组策略,必须我们授权的端口,其他计算机才能通过http访问 解决办法:(这里以阿里轻量应用服务器为 ...
- 阿里云安装mysql后查看不到初始密码的解决办法
在阿里云安装mysql后用grep 'A temporary password' /var/log/mysqld.log命令查看MySQL初始密码,毛线都没有看到,然后直接到/var/log/mysq ...
随机推荐
- 用Use Case获取需求的方法是否有缺陷,还有哪些地方需要改进
(提示:是否对所有应用领域都适用?使用的方便性?......) Use Case使用原则: 1.通过讲简单的故事来传递消息 讲故事是最有效的人与人交流信息的途径.通过讲故事(Use Case),团队成 ...
- spring boot 在jdk 1.7下使用 commandLineRunner
在spring boot 中有一段代码,使用的是java 1.8的语法: @Bean public CommandLineRunner commandLineRunner(ApplicationCon ...
- [C++] 用Xcode来写C++程序[6] Name visibility
用Xcode来写C++程序[6] Name visibility 此小结包括了命名空间的一些使用细节 命名空间 #include <iostream> using namespace st ...
- CentOS针对磁盘IO[jdb2进程]的优化
CentOS的jdb2进程总是沾满io,查了一些资料后才知道,这个问题源自系统bug,在此记录一下解决办法: 将高IO的磁盘,用以下参数remount即可 mount -t ext4 -o remou ...
- PSR规范学习笔记
PSR已经经历了5次变革,如今PSR4就是最新的标准,但是还是有必要了解下5个版本的内容的,于是去php-fig网站看了下英文原版: 大概看了遍,发现这规范很多的必须很多时候只是建议,但是PHP解析器 ...
- Nexus 3.X(Maven仓库私服)仓库迁移与备份
Linux 仓库迁移 Nexus的构件仓库都保存在sonatype-work目录中,该目录的位置由nexus/conf/nexus.properties配置文件指定.仓库迁移需要两个过程:备份和还原 ...
- 铁乐学python_Day42_锁和队列
铁乐学python_Day42_锁和队列 例:多个线程抢占资源的情况 from threading import Thread import time def work(): global n tem ...
- idea+maven+spring+cxf创建webservice应用(二)生成客户端程序
idea+maven+spring+cxf创建webservice应用(二)生成客户端程序,以上一篇为基础"idea+maven+spring+cxf创建webservice应用" ...
- September 21st 2017 Week 38th Thursday
What fire does not destroy, it hardens. 烈火摧毁不了的东西,只会变得更坚固. The true gold can stand the test of fire, ...
- int to string & string to int
#include "stdafx.h" #include <string> #include <sstream> using namespace std; ...