查看: 1890|回复: 8

咨询:动态几何对象碰撞检测不准确

[复制链接]

该用户从未签到

发表于 2011-2-16 13:28:53 | 显示全部楼层 |阅读模式
我用LineSegmentIntersector和PolytopeIntersector分别作了测试,发现无论是线段求交还是多面体求交,对于场景动态几何对象的求交为空。
比如,一个几何体从高处下落,接触到地面上的设置好射线或者多面体,碰撞检测交集为空。
但是,动态的射线或者动态的多面体,对于静态的几何对象求交是正确的。例如一个移动正方体去撞一面静止的墙体。

我查了一些信息,有人说,几何对象发生位移或旋转会使求交运算不准确。莫非OSG的IntersectionVisitor没办法对动态几何对象求交集吗?
肯定各位指点,对于场景中运动的几何对象怎么进行碰撞检测?


这个问题以前问过,一直没搞清楚,希望大家指点。

该用户从未签到

发表于 2011-2-16 15:31:21 | 显示全部楼层
莫非OSG的IntersectionVisitor没办法对动态几何对象求交集吗
您的说法没有什么根据,请给出可以说明问题的代码段

该用户从未签到

 楼主| 发表于 2011-2-16 17:57:48 | 显示全部楼层
我刚刚做了两个测试:
设定一个碰撞检测线段,然后用一个动态的正方体去碰撞。
但是,区别是一个使用PositionAttitudeTransform的结点回调使正方体运动,另一个采用drawable的更新回调函数update()对正方体的顶点坐标进行设置,从而使正方体运动。如图所示。

PositionAttitudeTransform结点回调

PositionAttitudeTransform结点回调

update动态更新数组

update动态更新数组


结果发现,在PositionAttitudeTransform中,intersectionVisitor对于正方体与线段的碰撞正确,而在update()中,正方体虽然与设置的LineSegmentIntersector碰撞,但是LineSegmentIntersector没有判断出碰撞。

所以请大家帮忙解释一下,为什么两种形式一个起效,一个却失效呢?
需要代码的话,我可以提供。

该用户从未签到

发表于 2011-2-18 10:22:26 | 显示全部楼层
如果您的代码可以限制在100行以内的话,请提供相关的代码以供判断。仅凭您的描述我没有得到什么参考信息

事实上由于GIS软件本身的要求,我天天都在做动态几何对象与线段求交的事情,因此它有问题的话我应当早就发现了~~我猜想还是您的代码存在不妥当的地方

该用户从未签到

 楼主| 发表于 2011-2-18 11:28:31 | 显示全部楼层
首先,创建一个几何体:
  1. int CreateCube()
  2. {
  3.         osg::ref_ptr<osg::Geode> Cube = new osg::Geode;
  4.         Cube->setName("CUBE");

  5.         osg::ref_ptr<osg::Geometry> Cube0 =new  osg::Geometry;
  6.         Cube0->setName("cube0");

  7.         osg::ref_ptr<osg::Vec3Array> v =new osg::Vec3Array;
  8.         v->push_back(osg::Vec3(0.0f,0.0f,0.0f));
  9.         v->push_back(osg::Vec3(1.0f,0.0f,0.0f));
  10.         v->push_back(osg::Vec3(1.0f,1.0f,0.0f));
  11.         v->push_back(osg::Vec3(0.0f,1.0f,0.0f));
  12.         v->push_back(osg::Vec3(0.0f,0.0f,1.0f));
  13.         v->push_back(osg::Vec3(1.0f,0.0f,1.0f));
  14.         v->push_back(osg::Vec3(1.0f,1.0f,1.0f));
  15.         v->push_back(osg::Vec3(0.0f,1.0f,1.0f));

  16.         Cube0->setVertexArray(v.get());

  17.         osg::ref_ptr<osg::DrawElementsUInt> bottom = new osg::DrawElementsUInt(osg::PrimitiveSet::QUADS,0);
  18.         bottom->push_back(0);
  19.         bottom->push_back(1);
  20.         bottom->push_back(2);
  21.         bottom->push_back(3);
  22. //。。。。。。。。。略去//

  23.         Cube0->setUseDisplayList( false );
  24.         Cube0->setUseVertexBufferObjects( true );
  25.         Cube->addDrawable(Cube0.get());

  26.         return osgDB::writeNodeFile(*Cube,"cube.ive");


  27. }
复制代码
然后,创建位移更新访问器。
  1. class MoveVisitor:public osg::NodeVisitor
  2. {
  3. public:
  4.         MoveVisitor():osg::NodeVisitor(TRAVERSE_ALL_CHILDREN)
  5.         {        }

  6.         virtual void apply(osg::Geode& node)
  7.         {

  8.                 osg::Drawable* drawable = node.getDrawable(0);
  9.                
  10.                 osg::Geometry* geom = dynamic_cast<osg::Geometry*>( drawable );

  11.                 if ( !geom ) return;

  12.                 osg::Vec3Array* vertices = dynamic_cast<osg::Vec3Array*>( geom->getVertexArray() );

  13.                 if ( vertices )

  14.                 {
  15.                         for (int i=0;i<vertices->getNumElements();i++)
  16.                         {
  17.                                 osg::Vec3 point = vertices->at(i);
  18.                                
  19.                                 (*vertices)[i].set(point.x(),point.y(),point.z()+1.0f);
  20.                         }
  21.                         osg::Vec3 point = vertices->at(0);
  22.                         if (point.z()>10.0f)
  23.                         {
  24.                                 for (int i=0;i<vertices->getNumElements();i++)
  25.                                 {
  26.                                         osg::Vec3 point3 = vertices->at(i);

  27.                                         (*vertices)[i].set(point3.x(),point3.y(),point3.z()-10.0f);
  28.                                 }

  29.                         }
  30.                         vertices->dirty();
  31.                 }
  32.                 traverse(node);       
  33.         }       
  34. };
复制代码
然后,实现主程序:
  1. int _tmain(int argc, _TCHAR* argv[])
  2. {

  3. //读立方体文件
  4.         osg::ref_ptr<osg::Group> root = new osg::Group;

  5.         CreateCube();
  6.         osg::ref_ptr<osg::Node> model = new osg::Node;
  7.         model = osgDB::readNodeFile("cube.ive");
  8.         MoveVisitor mv;//创建结点位移访问器
  9.        
  10. //画一条线
  11.         osg::ref_ptr<osg::Geometry> line = new osg::Geometry;
  12.         osg::ref_ptr<osg::Vec3Array> lineVertices = new osg::Vec3Array;
  13.         osg::Vec3 startp(0.5f,0.5f,9.0f);
  14.         osg::Vec3 endp(0.5f,0.5f,10.0f);
  15.         line->setVertexArray(lineVertices.get());

  16.         lineVertices->push_back(startp);
  17.         lineVertices->push_back(endp);

  18.         line->addPrimitiveSet(new osg::DrawArrays(osg::DrawArrays::LINES,0,2));

  19.         osg::ref_ptr<osg::Geode> lineNode = new osg::Geode;
  20.         lineNode->addDrawable(line.get());

  21.         root->addChild(lineNode.get());
  22.         root->addChild(model.get());

  23. //线段测试内容
  24.         osgUtil::IntersectionVisitor iv;
  25.         osgUtil::LineSegmentIntersector* lineTest = new osgUtil::LineSegmentIntersector(startp,endp);
  26.         iv.setIntersector(lineTest);


  27.         osgViewer::Viewer viewer;
  28.         viewer.setCameraManipulator(new osgGA::TrackballManipulator);
  29.         viewer.setSceneData(root.get());

  30.         viewer.realize();
  31. //主循环
  32.         while(!viewer.done())
  33.         {

  34.                 viewer.frame();
  35.                 model->accept(mv);
  36.                 model->accept(iv);
  37.                 if (lineTest->containsIntersections())
  38.                 {
  39.                         cout<<"The Intersection exists!"<<endl;
  40.                 }
  41. //时间控制,用于降低帧速
  42.                 osg::Timer_t start = osg::Timer::instance()->tick();
  43.                 osg::Timer_t end = osg::Timer::instance()->tick();       
  44.                 while (osg::Timer::instance()->delta_s(start,end)<0.1&&!viewer.done())
  45.                 {
  46.                         end = osg::Timer::instance()->tick();

  47.                 }

  48.         }       

  49.         return 0;
  50. }
复制代码
这个程序中,求交判断结果为false,请各位帮忙看看是哪里的问题。
多谢!

该用户从未签到

发表于 2011-2-18 12:17:53 | 显示全部楼层
您在什么地方dirtyBound()了?

该用户从未签到

 楼主| 发表于 2011-2-18 12:24:25 | 显示全部楼层
原来线段求交是基于包围盒的,我没研究过这个算法。
但是,听你这么一说,我恍然大悟了。
我改改再试试,先谢谢Array!

该用户从未签到

发表于 2011-2-18 12:51:25 | 显示全部楼层
了解系啊~

该用户从未签到

 楼主| 发表于 2011-2-18 13:11:11 | 显示全部楼层
果然没问题了,3ku!
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

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

联系我们

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