查看: 1936|回复: 2

如何在拾取(pick)物体的时候只拾取最近的交点

[复制链接]

该用户从未签到

发表于 2011-7-27 13:36:28 | 显示全部楼层 |阅读模式
osgViewer::View 在拾取交点的时候,默认是获得所有交点。如果模型比较大,因为有很多面,视线一次可能交点会很多。比如一个城市模型在平放的时候可能会有上万的交点。但是如果我们只需要最近的1个交点,那么这会严重地降低性能。下面是我的处理方法:
  1. class ViewForNearestIntersection : public osgViewer::View
  2. {
  3. public:
  4.         // Only get the first (nearest) intersection
  5.         bool computeIntersections(float x,float y, osgUtil::LineSegmentIntersector::Intersections& intersections,osg::Node::NodeMask traversalMask = 0xffffffff);


  6. // computeIntersections 函数与其父类的不同只是加了 LIMIT_ONE 的限制
  7. bool ViewForNearestIntersection::computeIntersections(float x,float y, osgUtil::LineSegmentIntersector::Intersections& intersections, osg::Node::NodeMask traversalMask)
  8. {
  9.         if (!_camera.valid()) return false;

  10.         float local_x, local_y = 0.0;
  11.         const osg::Camera* camera = getCameraContainingPosition(x, y, local_x, local_y);
  12.         if (!camera) camera = _camera.get();


  13.         osgUtil::LineSegmentIntersector::CoordinateFrame cf = camera->getViewport() ? osgUtil::Intersector::WINDOW : osgUtil::Intersector::PROJECTION;
  14.         osg::ref_ptr< osgUtil::LineSegmentIntersector > picker = new osgUtil::LineSegmentIntersector(cf, local_x, local_y);

  15.         picker->setIntersectionLimit(osgUtil::Intersector::LIMIT_ONE);  // LIMIT_ONE seems 10 times faster than LIMIT_NEAREST.
  16.         osgUtil::IntersectionVisitor iv(picker.get());
  17.         iv.setTraversalMask(traversalMask);

  18.         const_cast<osg::Camera*>(camera)->accept(iv);

  19.         if (picker->containsIntersections())
  20.         {
  21.                 intersections = picker->getIntersections();
  22.                 return true;
  23.         }
  24.         else
  25.         {
  26.                 intersections.clear();
  27.                 return false;
  28.         }
  29. }

  30. // 然后跟往常一样写一个这样的类似函数
  31. bool getNearestIntersection(ViewForNearestIntersection* viewer, const osgGA::GUIEventAdapter& ea, osg::Vec3d& v3d);


  32. // 最后在事件处理函数中获得交点可以下面这样写:
  33. if (ea.getEventType() == osgGA::GUIEventAdapter::RELEASE && button == osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON)
  34. {
  35.         osgViewer::View* view1 = dynamic_cast<osgViewer::View*> (&aa);
  36.         ViewForNearestIntersection* view = static_cast<ViewForNearestIntersection*> (view1);
  37.         if(!view)
  38.         {
  39.                 return false;
  40.         }
  41.         osg::Vec3d pointCoordinate;
  42.         getNearestIntersection(view, ea, pointCoordinate);
复制代码
看起来还可以,不知有没有更好的方法。

该用户从未签到

发表于 2011-7-27 19:24:50 | 显示全部楼层
没有太多好的方法,你可以通过优化场景结构来提高求交的性能,另外也可以通过限制求交线段的长度来实现目的

该用户从未签到

发表于 2011-7-28 08:28:51 | 显示全部楼层
intersections是自动按照与近平面的远近距离来排序的,因此第一个值就是最近的交点
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

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

联系我们

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