查看: 2278|回复: 12

如何获得鼠标的远近点

[复制链接]

该用户从未签到

发表于 2010-2-1 10:38:37 | 显示全部楼层 |阅读模式
本帖最后由 shypzms 于 2010-2-1 10:40 编辑

我希望获得鼠标的远近点,尝试用屏幕坐标乘以inverseMVPW
  1. osg::Vec3d nearPoint = osg::Vec3d(ea_x,ea_y,0.0)*_inverseMVPW;
  2. osg::Vec3d farPoint = osg::Vec3d(ea_x,ea_y,1.0)*_inverseMVPW;
复制代码
不过结果似乎不对。我是这样求的MVPW
  1. osg::Camera* camera = viewer->getCamera();
  2. _MVPW = camera->getViewMatrix() * camera->getProjectionMatrix();
  3. if (camera->getViewport()) _MVPW.postMult(camera->getViewport()->computeWindowMatrix());
  4. _inverseMVPW.invert(_MVPW);
复制代码
是不是不对?
另外所需的屏幕坐标应该是使用在分辨率下的还是在[-1,1]的?

该用户从未签到

发表于 2010-2-1 14:16:09 | 显示全部楼层
这样计算应该是没有问题的,您可以解释一下为什么您觉得不对

该用户从未签到

 楼主| 发表于 2010-2-2 09:16:31 | 显示全部楼层
我计算出来的—MVPW是
1230.7692759135789        0.00000000000000000        0.00000000000000000        0.00000000000000000       
0.00000000000000000        1153.8461961689800        0.00000000000000000        0.00000000000000000       
-400.00000000000000        -300.00000000000000        -1.0001000100010002        -1.0000000000000000       
0.00000000000000000        0.00000000000000000        -1.0001000100010000        0.00000000000000000       

而近点远点计算出来是
[-0.32475115995835507        -0.25973710157643420        -0.99999999999999978]
[-3247.5115995803035        -2597.3710157617452        -9999.9999999899992]
我应该是基本从Z轴正方向向下观察,XY坐标至少不应该差这么多吧

该用户从未签到

发表于 2010-2-2 12:04:55 | 显示全部楼层
您可以用射线求出一个交点,然后判断一下交点是否在远近点的连线之上,并以此作为判断的依据。只是根据想象去臆断,这往往容易使您的代码检查工作陷入歧途。

该用户从未签到

 楼主| 发表于 2010-2-3 09:20:02 | 显示全部楼层
我分别以远近点为圆心画了两个球,可以看出明显不在鼠标所在位置
而且这两个点的位置似乎还并不以我的观察点改变而改变,旋转过视角之后点击鼠标,两个球的位置并没有改变。

该用户从未签到

 楼主| 发表于 2010-2-3 10:05:05 | 显示全部楼层
可以把测试用的代码打包发一下么?我对比看看
另外osg::Vec3d(ea_x,ea_y,0.0)这里的x,y应该哪种坐标系下的,是按照窗口分辨率(800x600)还是[-1,1]?

该用户从未签到

发表于 2010-2-3 10:14:00 | 显示全部楼层
我是直接在自己设计的google地球漫游器里面计算的,整个漫游器工程不能给您。简单来说,就是这样:
  1. osg::Camera* camera = viewer->getCamera();
  2. osg::Matrix _inverseMVPW, _MVPW = camera->getViewMatrix() * camera->getProjectionMatrix();
  3. //if (camera->getViewport()) _MVPW.postMult(camera->getViewport()->computeWindowMatrix());
  4. _inverseMVPW.invert(_MVPW);

  5. osg::Vec3 near = osg::Vec3(ea.getXnormalized(), ea.getYnormalized(), 0) * _inverseMVPW;
  6. osg::Vec3 far = osg::Vec3(ea.getXnormalized(), ea.getYnormalized(), 1) * _inverseMVPW;
  7. osg::Vec3 v1 = (intersectPoint-near); v1.normalize();
  8. osg::Vec3 v2 = (far-intersectPoint); v2.normalize();
复制代码
比较v1和v2即可,intersectPoint是射线与场景模型求交的结果

注意,如果您级联了WindowMatrix矩阵,那么传入的坐标应当是按照窗口分辨率,即getX,getY;否则传入的值应当限制在[-1,1],就如我的示例代码所示

该用户从未签到

 楼主| 发表于 2010-2-3 10:26:43 | 显示全部楼层
本帖最后由 shypzms 于 2010-2-3 10:31 编辑

这个near和far点应该就是图中的近点远点吧,这条线是不是理论上过眼睛和鼠标呢?
OSG中Dragger系统架构与算法分析.jpg

该用户从未签到

发表于 2010-2-3 10:30:05 | 显示全部楼层
“这条线是不是理论上过眼睛和鼠标呢”,我不明白您的意思

该用户从未签到

 楼主| 发表于 2010-2-3 10:40:03 | 显示全部楼层
就是说假如能够把这条线在现实中画出来的话应该是从眼睛所在的观察点与鼠标的连线吧,屏幕的远平面和近平面与这条线的交点就是远点和近点?

该用户从未签到

发表于 2010-2-3 10:45:53 | 显示全部楼层
我想不是您说的那样。

近平面中心点p1,远平面中心点p2,以及视点是成一条直线的。对于[-1,1]范围的屏幕,p1 = (0,0,0) * invMVP,p2 = (0,0,1) * invMVP;对于800x600的屏幕,p1 = (400,300,0) * invMVPW,p2 = (400,300,1) * invMVPW

鼠标点击屏幕位置(ex, ey),那么它在近平面上的位置是(ex,ey,0)*invMVPW,远平面则是(ex,ey,1)*invMVPW

鼠标点击屏幕位置与视点位置没有直接关系

该用户从未签到

 楼主| 发表于 2010-2-3 11:14:24 | 显示全部楼层
本帖最后由 shypzms 于 2010-2-3 11:15 编辑

我觉得应该是过视点的吧,既然要与_MVPW相乘就应该与viewPoint相关吧
OSG中Dragger系统架构与算法分析.jpg
视点和鼠标两点来确定了一条直线吧

该用户从未签到

发表于 2010-2-3 12:25:03 | 显示全部楼层
我想我之前被您的话绕得有些糊涂。楼上的图没有错,鼠标点击位置将得到远近平面各一个空间点,并且它们与视点的连线是同一条直线。

您同样可以用我的代码片段来论证MVPW矩阵的正确性,我已经验证过了,依然没有任何问题:
  1. osg::Vec3 near = osg::Vec3(ea.getX(), ea.getY(), 0) * _inverseMVPW;
  2. osg::Vec3 far = osg::Vec3(ea.getX(), ea.getY(), 1) * _inverseMVPW;
  3. osg::Vec3 v1 = (eye-near); v1.normalize();
  4. osg::Vec3 v2 = (eye-far); v2.normalize();
复制代码
您需要登录后才可以回帖 登录 | 注册

本版积分规则

OSG中国官方论坛-有您OSG在中国才更好

网站简介:osgChina是国内首个三维相关技术开源社区,旨在为国内更多的技术开发人员提供最前沿的技术资讯,为更多的三维从业者提供一个学习、交流的技术平台。

联系我们

  • 工作时间:09:00--18:00
  • 反馈邮箱:1315785073@qq.com
快速回复 返回顶部 返回列表