查看: 1658|回复: 4

【求助】急,请问怎样实现拖拽鼠标创建物体

[复制链接]

该用户从未签到

发表于 2012-4-6 12:28:09 | 显示全部楼层 |阅读模式
本帖最后由 pplly 于 2012-4-6 12:42 编辑

比如创建一个rectangle,左键单击后拖动鼠标,然后释放,单击和释放的时候确定了rectangle的两个角点
这个问题的重点就是如何在点击和释放鼠标的时候,正确获得在世界坐标中对应的点的位置,才能做到物体创建的大小能符合在视口上随着鼠标的拖动而创建

像3DSMAX一样,但是也分情况

1、某一平面视口下(如X-Z Y-Z XY 平面),这个就比较简单了,把屏幕2D坐标转换到 某一平面上对应的世界坐标(如X-Z平面,Y=0),这个转换我的思路如下:

  1. osg::Matrix MVPW( camera->getViewMatrix() *
  2.                        camera->getProjectionMatrix() *
  3.                        camera->getViewport()->computeWindowMatrix());

  4. osg::Matrixd inverseMVPW = osg::Matrixd::inverse(MVPW);
复制代码
得到屏幕坐标到世界坐标的转换矩阵
然后计算X-Z平面在camera的投影视椎体中near 和 far平面之间的一个比例 factor
  1. osg::Vec3 point = osg::Vec3(x,y,factor) * inverseMVPW;
复制代码
来求得对应在世界坐标系下的坐标。

2、在透视视图(如3dsmax 的perpective视口)下(因为此时比如X-Z平面并不是垂直于视线方向的,所以不好用1的方法)
这个我一直想不到好的解决方法。之前有想过一个方法,也是一个通用的办法。那就是通过相交求交点的方法。那就是在对应的平面上创建一个平面物体,在鼠标单击或者释放的时候使用
  1. view->computeIntersections(x,y,intersections)
复制代码
求得与那个平面物体的交点,那就是所求的世界坐标系下的点的位置。
但是这个方法得先创建一个平面物体,那么就还要涉及什么显示隐藏这个物体,而且感觉效率也不高,因为求交的话可能会得到很多个物体的交点,还要判断是不是那个平面上的交点。= =因为刚接触osg不到一星期。。。。实在是对osg的文档缺乏太不习惯了(可能习惯了QT的关系。。。QT的文档对初学者来讲实在是太方便了)。

所以请问对于上述的问题有没有一个好的解决方案呢?(不一定要根据我的思路来讲,如果有其他的实现方式也麻烦跟我说一说吧)请教各位啦~谢啦

###########################################################################
发完这个帖子后又想到了一个方案,在这写出来大家看看可不可行
还是根据(1)中得到的那个世界坐标下的点坐标,然后又已知摄像机的眼睛坐标(其实就是摄像机坐标),那么两个点确定了一个直线方程,直接解这个直线方程和对应平面的交点就可以了(顺便请问osg有求解直线和平面交点的函数么?没有只能自己写了)。不知道这个方法行不行,我去试验看看了,还请各位继续帮忙解决一下。

该用户从未签到

 楼主| 发表于 2012-4-6 14:22:38 | 显示全部楼层
本帖最后由 pplly 于 2012-4-6 14:23 编辑

1的情况下,X-Z平面,可以实现想要的效果(在鼠标点击位置创建一个球体)
QQ截图20120406141531.jpg

但是坐标位置仍旧不是很精确,再找原因,按理说应该Y上的值应该很接近0才对(误差也不应该会偏差那么大)
我factor的值是用这个方法算的
  1. double fovy,aspectRatio,zNear,zFar;
  2. viewer->getCamera()->getProjectionMatrixAsPerspective(fovy,aspectRatio,zNear,zFar);
  3. float factor=(eye.y()-zNear)/(zFar-zNear);
复制代码
从截图上可以看到点坐标的Y值是0.16+

该用户从未签到

 楼主| 发表于 2012-4-6 14:38:32 | 显示全部楼层
pplly 发表于 2012-4-6 14:22
1的情况下,X-Z平面,可以实现想要的效果(在鼠标点击位置创建一个球体)

额= =突然觉得也可能是误差的关系,因为我的相对值都设得太小了,球的半径为1.0f,中间那个长方体是(1.0f,2.0f,3.0f)
摄像机 eye(0.0f,10.0f,0.0f) center(0.0f,0.0f,0.0f) up(0.0f,0.0f,1.0f)
屏幕坐标上都是像素单位,整型,计算方法应该没啥问题,那就是误差了
那说明1的方法没有问题,是可以实现这种简单的情况下屏幕2D坐标变换到对应的世界坐标下

难就难在一般情况下了(相机不是在这么特殊的一个角度),请问高手们有没有啥更好的解决办法?

该用户从未签到

 楼主| 发表于 2012-4-6 15:43:25 | 显示全部楼层
本帖最后由 pplly 于 2012-4-6 16:00 编辑

= =好了。。可以结贴了。。。。。汗。。。
不好意思了,呵呵,把论坛当成了一个梳理自己思路的地方= =囧~
就是用我1楼最后说的那个方法,因为平面是特殊的,所以交点的计算十分简单。用不着其他复杂的类
就是一个直线方程和平面方程联立求解的过程,这样无论是透视视口还是特殊的平面视口下都可以解决了
感谢^_^
QQ截图20120406154057.jpg

可以看到cmd窗口的左下角有两行,第一行坐标是第一种方法求得的,第二行的坐标是求解方程求得的。
因为求解方程时就是把Y=0带入,所以在Y方向上就不会存在误差了

透视视口下(原来的方法就比较难实现这种效果):
QQ截图20120406155616.jpg
  1. osg::Vec3f x1=eye;
  2. osg::Vec3f x2=osg::Vec3f(x,y,1.0f)*inverseMVPW;
  3. osg::Vec3f dir=x2-x1;
  4. dir.normalize();
  5. osg::Vec3f point1(-x1.y()/dir.y()*dir.x()+x1.x(),0,-x1.y()/dir.y()*dir.z()+x1.z());
复制代码
附上Y=0平面情况下的求解方法(= =其实很简单,情况特殊,简单带入就行),在不同平面创建物体的话就作相应的变化就可以。

该用户从未签到

发表于 2012-4-7 22:03:47 | 显示全部楼层
整完了写个教材或者代码贴出来福利下大家啊
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

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

联系我们

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