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 ...
随机推荐
- 从本机构建Linux应用程序VHD映像
下图描述了总体的虚拟机映像的VHD生成,上传以及发布到 Azure 镜像市场的全过程: 具体步骤如下: 在本地计算机(Windows平台)上安装Hyper-V,并安装您所需要的虚拟机操作系统 在此操作 ...
- [WINCE|VS2008] 用在PC上调试WINCE程序
http://www.danielmoth.com/Blog/deploy-to-my-computer.aspx 作者:The Moth 步骤: 1. 在VS2008中打到 Device Optio ...
- Java中简单提示异常代码的行号,类名等
public class Test1 { public static void main(String args[]) { System.out.println(getLineInfo()); get ...
- Oracle GoldenGate DDL 详细说明 使用手册(较早资料)
一. 概述 DDL 相关的参数包括:DDL.DDLERROR.DDLOPTIONS.DDLSUBST.DDLTABLE.GGSCHEMA. PURGEDDLHISTORY.PURGEMARKERHIS ...
- flask的g对象
故名思议我们可以理解这个g对象是一个全局的对象,这个对象存储的是我们这一次请求的所有的信息,只是存储这一次的请求 g:global 1. g对象是专门用来保存用户的数据的. 2. g对象在一次请求中 ...
- WinPE ISO制作
1.安装ADK,然后导出winPE镜像文件和启动文件: 打开 部署和映像工具环境,cd "Windows Preinstallation Environment",运行 copyp ...
- nodepad++添加新主题
https://www.cnblogs.com/d0main/p/6915460.html
- spring4声明式事务--01注解方式
1.在spring配置文件中引入 tx 命名空间 xmlns:tx="http://www.springframework.org/schema/tx" 2.配置事务管理器 < ...
- IKVM.NET入门(1)
IKVM.NET是一个针对Mono和微软.net框架的java实现,其设计目的是在.NET平台上运行java程序.本文将比较详细的介绍这个工具的原理.使用入门(如何java应用转换为.NET应用.如何 ...
- python多进程(二)
之前实现的数据共享的方式只有两种结构Value和Array.Python中提供了强大的Manager专门用来做数据共享的,Manager是进程间数据共享的高级接口. Manager()返回的manag ...