查看: 2315|回复: 12

动画的碰撞检测

[复制链接]

该用户从未签到

发表于 2011-7-4 18:54:17 | 显示全部楼层 |阅读模式
实现这样一个功能:飞机在盘旋,按下键盘左键,飞机释放小飞机,给小飞机一个路径,垂直向下,当小飞机碰到地面后,消失。
问题是:1。碰撞检测从开始释放小飞机,iv.hits()的返回值就为true,就是一直都是碰撞状态,明明离地面200多,不知道什么原因。
           2. 如何得到碰撞到地面的位置?
代码如下:
  1. osg::ref_ptr<osg::AnimationPath> createAnimationPath(osg::Vec3& center,float radius,float looptime)
  2. {
  3. //创建一个path对象
  4. osg::ref_ptr<osg::AnimationPath> animationPath = new osg::AnimationPath();
  5. //设置动画模式为循环(LOOP)。LOOP:循环,SWING:单摆,NO_LOOPING:不循环
  6. animationPath->setLoopMode(osg::AnimationPath::LOOP);
  7. //关键点数
  8. int numPoint = 60;
  9. //每次偏移角度
  10. float yaw = 0.0f;
  11. float yaw_delta = 2.0f*osg::PI/((float)(numPoint-1.0f));
  12. //倾斜角度
  13. float roll = osg::inDegrees(45.0f);
  14. //时间偏移
  15. float time = 0.0f;
  16. float time_delta = looptime/((float)numPoint);
  17. for(int i = 0;i<numPoint;i++)
  18. {
  19.   //关键点位置
  20.   osg::Vec3 position(center+osg::Vec3(sinf(yaw)*radius,cosf(yaw)*radius,0.0f));
  21.   //关键点角度
  22.   osg::Quat rotation(osg::Quat(roll,osg::Vec3(0.0,1.0,0.0))*osg::Quat(-(yaw+osg::inDegrees(90.0f)),osg::Vec3(0.0,0.0,1.0)));
  23.   //插入path,把关键点与时间压入形成path
  24.   animationPath->insert(time,osg::AnimationPath::ControlPoint(position,rotation));
  25.   yaw += yaw_delta;
  26.   time += time_delta;
  27. }
  28. return animationPath.get();
  29. }
  30. osg::ref_ptr<osg::AnimationPath> createAnimationPath1(osg::Vec3& pos)
  31. {
  32. osg::ref_ptr<osg::AnimationPath> animationPath = new osg::AnimationPath();
  33. animationPath->setLoopMode(osg::AnimationPath::LOOP);
  34. int numPoint = 60;
  35. float yaw = 0.0f;
  36. float yaw_delta = 2.0f;
  37. float roll = osg::inDegrees(45.0f);
  38. float time = 0.0f;
  39. float time_delta = 0.5f;
  40. for(int i=0;i<numPoint;i++)
  41. {
  42.   osg::Vec3 position(pos+osg::Vec3(0.0f,0.0f,-yaw));
  43.   osg::Quat rotation(osg::Quat(roll,osg::Vec3(0.0,1.0,0.0)));
  44.   animationPath->insert(time,osg::AnimationPath::ControlPoint(position,rotation));
  45.   yaw += yaw_delta;
  46.   time += time_delta;
  47. }
  48. return animationPath.get();
  49. }
  50. class CheckPengEventHandler : public osg::NodeCallback
  51. {
  52. public:
  53. CheckPengEventHandler()  
  54. {
  55.   
  56. }
  57. virtual void operator()(osg::Node* node,osg::NodeVisitor* nv)
  58. {  
  59.   osg::PositionAttitudeTransform* pat = dynamic_cast<osg::PositionAttitudeTransform*>(node);  
  60.   osgUtil::IntersectVisitor iv;   
  61.   osg::ref_ptr<osg::LineSegment> lineZ = new osg::LineSegment(pat->getPosition()+osg::Vec3(0.0f,0.0f,2.0f),pat->getPosition()+osg::Vec3(0.0f,0.0f,-2.0f));
  62.   iv.addLineSegment(lineZ.get());  
  63.   if(iv.hits())
  64.   {
  65.    node->setNodeMask(0);
  66.   }   
  67. }
  68. };

  69. class UseEventHandler:public osgGA::GUIEventHandler
  70. {
  71. public:
  72. UseEventHandler(osg::ref_ptr<osg::PositionAttitudeTransform> pat,osg::ref_ptr<osg::AnimationPath> animationPath
  73.   ,osg::ref_ptr<osg::PositionAttitudeTransform> pat1)  
  74.   :pat(pat),animationPath(animationPath),pat1(pat1)
  75. {
  76.   
  77. }
  78. virtual bool handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter& aa)
  79. {
  80.   osgViewer::Viewer* viewer = dynamic_cast<osgViewer::Viewer*>(&aa);
  81.   if(!viewer) return false;
  82.   osg::ref_ptr<osg::Group> group = dynamic_cast<osg::Group*>(viewer->getSceneData());  
  83.   switch(ea.getEventType())
  84.   {
  85.   case osgGA::GUIEventAdapter::KEYDOWN:
  86.    {
  87.     if(ea.getKey()==0xFF51)
  88.     {
  89.      pat->setUpdateCallback(new osg::AnimationPathCallback(animationPath.get(),0.0f,1.0f));
  90.     }
  91.     if(ea.getKey() == 0xFF53)
  92.     {   
  93.      osg::Vec3 position = pat->getPosition();
  94.      group->addChild(pat1.get());
  95.      group->getChild(0)->asGroup()->removeChild(pat1);
  96.      pat1->setNodeMask(1);
  97.      osg::ref_ptr<osg::AnimationPath> animationPath1 = new osg::AnimationPath();
  98.                  animationPath1 = createAnimationPath1(position);
  99.      pat1->addUpdateCallback(new osg::AnimationPathCallback(animationPath1.get(),0.0f,1.0f));
  100.      pat1->addUpdateCallback(new CheckPengEventHandler());
  101.     }
  102.    }
  103.    break;  
  104.   default:
  105.    break;
  106.   }
  107.   return false;
  108. }
  109. private:
  110. osg::ref_ptr<osg::PositionAttitudeTransform> pat,pat1;
  111. osg::ref_ptr<osg::AnimationPath> animationPath;
  112. };

  113. int _tmain(int argc, _TCHAR* argv[])
  114. {
  115. osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer();
  116. osg::ref_ptr<osg::Group> root = new osg::Group();
  117. osg::ref_ptr<osg::Node> cessna = osgDB::readNodeFile("cessna.osg");  
  118. osg::ref_ptr<osg::Node> node = osgDB::readNodeFile("lz.osg");
  119. osg::ref_ptr<osg::Node> glider = osgDB::readNodeFile("glider.osg");
  120. //得到包围盒,来确定动画旋转中心
  121. const osg::BoundingSphere& bs = cessna->getBound();
  122. osg::Vec3 position = bs.center() + osg::Vec3(0.0f,0.0f,200.0f);
  123. //缩放
  124. float size = 100.0f/bs.radius()*0.3f;
  125. //创建路径
  126. osg::ref_ptr<osg::AnimationPath> animationPath = new osg::AnimationPath();
  127. animationPath = createAnimationPath(position,200.0f,30.0f);
  128. osg::ref_ptr<osg::MatrixTransform> mt = new osg::MatrixTransform();
  129. osg::ref_ptr<osg::MatrixTransform> mt1 = new osg::MatrixTransform();
  130. osg::ref_ptr<osg::MatrixTransform> mtTerr = new osg::MatrixTransform();
  131. //OSG确保只有STATIC数据可以进行图形渲染
  132. mt->setDataVariance(osg::Object::STATIC);
  133. mt1->setDataVariance(osg::Object::STATIC);
  134. //进行适当的变换
  135. mtTerr->setMatrix(osg::Matrix::translate(0.0f,0.0f,0.0f));
  136. mtTerr->addChild(node.get());
  137. mt->setMatrix(osg::Matrix::translate(bs.center())*
  138.   osg::Matrix::scale(size,size,size));
  139. mt->addChild(cessna.get());
  140. mt1->setMatrix(osg::Matrix::scale(0.2,0.2,0.2)*osg::Matrix::rotate(osg::inDegrees(90.0f),1.0f,0.0f,0.0f));
  141. mt1->addChild(glider.get());
  142. osg::ref_ptr<osg::PositionAttitudeTransform> pat = new osg::PositionAttitudeTransform();
  143. osg::ref_ptr<osg::PositionAttitudeTransform> pat1 = new osg::PositionAttitudeTransform();
  144. pat->addChild(mt.get());
  145. pat1->addChild(mt1.get());
  146. pat1->setNodeMask(0);
  147. pat->addChild(pat1.get());
  148. root->addChild(pat.get());
  149. root->addChild(mtTerr.get());
  150. osgUtil::Optimizer optimizer;
  151. optimizer.optimize(root.get());
  152. viewer->setSceneData(root.get());
  153. viewer->addEventHandler(new UseEventHandler(pat,animationPath,pat1));
  154. viewer->realize();
  155. viewer->run();
  156. return 0;
  157. }
复制代码

该用户从未签到

发表于 2011-7-4 20:30:44 | 显示全部楼层
您可以使用osgUtil:ineSegmentIntersector获取位置信息,另外,发帖时请给出精简代码,勿全部贴出,相信很少有人能够全部仔细查看您的代码

该用户从未签到

 楼主| 发表于 2011-7-4 21:54:54 | 显示全部楼层
前49行可以不用看,是创建路径用的,给出的目的是怕碰撞检测时的位置可能和路径的设置有关系,所以才给出的,不好意思了。还请大侠们看看一直检测碰撞都为true是怎么回事

该用户从未签到

 楼主| 发表于 2011-7-4 22:08:27 | 显示全部楼层
可不可以告诉我,如果检测碰撞为true时,怎么得到和场景中哪个物体发生碰撞了

该用户从未签到

发表于 2011-7-5 01:21:01 | 显示全部楼层
参考osgpick,通过nodepath直接得到节点

该用户从未签到

 楼主| 发表于 2011-7-5 10:02:11 | 显示全部楼层
osgpick好像用的是LineSegmentIntersector,我只能得到起始位置的Vec3的值,而computeIntersections要的是起点和终点的double值,这该怎么办?
我用的是IntersectVisitor,这个有没有可以得到碰撞节点的方法?

该用户从未签到

发表于 2011-7-5 15:51:03 | 显示全部楼层
请使用IntersectionVisitor,直接设置setStart和setEnd为您需要的起终点

该用户从未签到

 楼主| 发表于 2011-7-5 22:43:40 | 显示全部楼层
碰撞检测的代码这样改了以后,射线的起点是物体的包围球的中心,终点是物体包围球球心加上(0.0,0.0,半径),但是出现的现象是,当物体包围球的球心与地面重合时,碰撞检测才返回true,明显看到当glider进入地面一半的时候才停止,代码如下,不知道哪里没写对。

  1. //已得到包围球bs
  2. osg::ref_ptr<osgUtil::LineSegmentIntersector> inter=new LineSegmentIntersector(bs.center(),bs.center+osg::Vec3(0.0f,0.0f,bs.raduis());
  3.         osg::IntersectionVisitor v(inter.get());
  4.         gnode.accept(v);
  5.         unsigned int size=inter->getIntersections().size();
  6.         if(size>0){
  7.                 Vec3 resultCoord=inter.get()->getIntersections().begin()->getWorldIntersectPoint();
  8.       osg::Vec3 coord;
  9.         coord[0]=resultCoord.x();
  10.         coord[1]=resultCoord.y();
  11.         coord[2]=resultCoord.z();
  12.         }
复制代码

该用户从未签到

发表于 2011-7-6 08:24:24 | 显示全部楼层
代码本身没有看出太多问题来,不过问题是您是否能保证您的物体就是沿着Z轴向上接触地面的

该用户从未签到

 楼主| 发表于 2011-7-6 09:29:34 | 显示全部楼层
下落的路径基本是沿Z轴下落的,在Y轴方向有个45度倾角,代码如下:
  1. osg::ref_ptr<osg::AnimationPath> createAnimationPath1(osg::Vec3& pos)
  2. {
  3. osg::ref_ptr<osg::AnimationPath> animationPath = new osg::AnimationPath();
  4. animationPath->setLoopMode(osg::AnimationPath::LOOP);
  5. int numPoint = 60;
  6. float yaw = 0.0f;
  7. float yaw_delta = 2.0f;
  8. float roll = osg::inDegrees(45.0f);
  9. float time = 0.0f;
  10. float time_delta = 0.5f;
  11. for(int i=0;i<numPoint;i++)
  12. {
  13.   osg::Vec3 position(pos+osg::Vec3(0.0f,0.0f,-yaw));
  14.   osg::Quat rotation(osg::Quat(roll,osg::Vec3(0.0,1.0,0.0)));
  15.   animationPath->insert(time,osg::AnimationPath::ControlPoint(position,rotation));
  16.   yaw += yaw_delta;
  17.   time += time_delta;
  18. }
  19. return animationPath.get();
  20. }
复制代码
如果这个不是沿Z轴垂直下落的,那这个检测线段该如何写,写多条吗?

该用户从未签到

 楼主| 发表于 2011-7-6 09:44:08 | 显示全部楼层
把检测线段改了一下,好了,改成
  1. LineSegmentIntersector(bs.center()-osg::Vec3(0.0f,0.0fbs.raduis()),bs.center+osg::Vec3(0.0f,0.0f,bs.raduis());
复制代码
虽然可以了,但还是不明白为什么这么改就对了

该用户从未签到

发表于 2011-7-6 11:21:18 | 显示全部楼层
之前的
  1. bs.center(), bs.center+osg::Vec3(0.0f,0.0f,bs.raduis()
复制代码
这个起止点的意思是从中心向Z上方向发射一条线段;如果您的物体是下落的,那么显然您在这里犯了错误

该用户从未签到

发表于 2012-7-27 14:08:52 | 显示全部楼层
可能你一开始设置的线段是会和大飞机相交的。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

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

联系我们

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