查看: 2102|回复: 10

检测碰撞路径动画控制小车移动

[复制链接]

该用户从未签到

发表于 2011-9-25 18:51:55 | 显示全部楼层 |阅读模式
我想实现一个鼠标事件响应器,里面有个事件是,当鼠标单击大平面的某个点时,检测到鼠标和面的交点。然后使用路径动画,将平面上的小车可以移动到指定点。现在实现小车移动到指定点的功能了,但是车转向一直不知道怎么实现。因为当点击一个点时,车首先应该转向,然后才是朝着指定点移动。就是这个转向,在carnode->setUpdateCallback(new osg::AnimationPathCallback(path.get()));这里的path里,只能设置世界坐标系的旋转角度。因为要实现车到达指定点,当再次点击下一点时,可以从此点继续转动和移动。如果使用一个旋转变量记录小车的上一次的旋转角度的话,就会彻底乱套了。因为下面使用的方法是,有个缺点是,每次计算旋转角度,都需要记录上次坐标系的旋转。就是需要使用上次坐标系的旋转坐标系。导致逻辑比较乱。

我想问下,可不可以在path中比较容易的使用小车的局部坐标系,这样旋转的话比较容易处理。。。或者有什么其他的办法实现这个功能也可以,那我就换个思路,谢谢了。如果大家有什么比较好的思路的话,最好了。我不知道该怎么实现了。下面这个程序写的不好,拿上来就是为了可以明白点我说的意思。



就是类似于中视典http://news.sina.com.cn/pc/2010-09-30/27/5732.html这里面这个小人的操作。点哪,他就往哪跑。



osg::ref_ptr<osg::Group>m_root;
double rotz0,rotz;//绕z旋转角度的弧度值,当前位置的角度和目标位置的角度,是通过坐标变换后的新坐标系中确定的旋转角度值
double posx0,posy0,posz0;//当前位置
double posx,posy,posz;//目标位置
osg::ref_ptr<osg::MatrixTransform> carnode;
//double rotscale;
double newposx0,newposy0,newposz0;//新坐标系下的当前坐标值
double newposx,newposy,newposz;//新坐标系下的目标坐标值
int firstflag ;
double rotnum;//新坐标系相对于前坐标系的旋转角度
double rott;



class keyhandler : public osgGA::GUIEventHandler
{
public : virtual bool handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter& aa,osg::Object*,osg::NodeVisitor*)
   {
    osgViewer::Viewer* viewer = dynamic_cast<osgViewer::Viewer*>(&aa);
    switch (ea.getEventType())
    {
    case osgGA::GUIEventAdapter:USH:
     if(ea.getButton()==osgGA::GUIEventAdapter:EFT_MOUSE_BUTTON)
     {
      osgUtil::LineSegmentIntersector::Intersections intersections;

      float x=ea.getX();
      float y=ea.getY();
    if(  viewer->computeIntersections(x,y,intersections))
    {
      osgUtil::LineSegmentIntersector::Intersections::iterator hitr=intersections.begin();
       posx=hitr->getWorldIntersectPoint().x();
       posy=hitr->getWorldIntersectPoint().y();
       posz=hitr->getWorldIntersectPoint().z();
double rotscale=0;//每次需要旋转的度数

double rottime=0;//每次旋转需要的时间
double transtime=0;//每次移动需要的时间

//四个象限方向的判断
if(firstflag==0)
{ if ((posx-posx0)>0&&(posy-posy0)>=0)
{
  rotscale=atan(fabs(posy-posy0)/fabs(posx-posx0));
  rotscale=-(osg::PI_2-rotscale);
};
if ((posx-posx0)<=0&&(posy-posy0)>0)
{
  rotscale=atan(fabs(posy-posy0)/fabs(posx-posx0));
  rotscale=(osg::PI_2-rotscale);
};
if ((posx-posx0)<0&&(posy-posy0)<=0)
{
  rotscale=atan(fabs(posy-posy0)/fabs(posx-posx0));
  rotscale=(osg::PI_2+rotscale);
};
if ((posx-posx0)>=0&&(posy-posy0)<0)
{
  rotscale=atan(fabs(posy-posy0)/fabs(posx-posx0));
  rotscale=-(osg::PI_2+rotscale);
};
rott=rotscale;
firstflag++;
}
else{
newposx=posx*cos(rotnum)-posy*sin(rotnum);
newposy=posx*sin(rotnum)+posy*cos(rotnum);

newposx0=posx0*cos(rotnum)-posy0*sin(rotnum);
newposy0=posx0*sin(rotnum)+posy0*cos(rotnum);

if ((newposx-newposx0)>0&&(newposy-newposy0)>=0)
{
rotscale=atan(fabs(newposy-newposy0)/fabs(newposx-newposx0));
rotscale=-(osg::PI_2-rotscale);
rotnum=osg::PI_2-rotscale;
};
if ((newposx-newposx0)<=0&&(newposy-newposy0)>0)
{
rotscale=atan(fabs(newposy-newposy0)/fabs(newposx-newposx0));
rotscale=(osg::PI_2-rotscale);
rotnum=osg::PI_2+rotscale;
};
if ((newposx-newposx0)<0&&(newposy-newposy0)<=0)
{
rotscale=atan(fabs(newposy-newposy0)/fabs(newposx-newposx0));
rotscale=(osg::PI_2+rotscale);
rotnum=-(osg::PI_2+rotscale);
};
if ((newposx-newposx0)>=0&&(newposy-newposy0)<0)
{
rotscale=atan(fabs(newposy-newposy0)/fabs(newposx-newposx0));
rotscale=-(osg::PI_2+rotscale);
rotnum=-(osg::PI_2-rotscale);
};


rott=rotscale;
};

rotz=rotz+rott;
rottime=fabs(rott);
transtime=sqrt(pow((posx-posx0),2)+pow((posy-posy0),2));
osg::ref_ptr<osg::AnimationPath> path =new osg::AnimationPath;
path->setLoopMode(osg::AnimationPath::NO_LOOPING);
path->insert(0.0,osg::AnimationPath::ControlPoint(osg::Vec3(posx0,posy0,posz0),osg:uat(rotz0,osg::Vec3(0.0,0.0,1.0))));
path->insert(rottime,osg::AnimationPath::ControlPoint(osg::Vec3(posx0,posy0,posz0),osg::Quat(rotz,osg::Vec3(0.0,0.0,1.0))));
path->insert((rottime+transtime),osg::AnimationPath::ControlPoint(osg::Vec3(posx,posy,posz),osg::Quat(rotz,osg::Vec3(0.0,0.0,1.0))));

carnode->setUpdateCallback(new osg::AnimationPathCallback(path.get()));

rotz0=rotz;
posx0=posx;
posy0=posy;
posz0=posz;
    }


     }
    }
    return false;
   }

};

该用户从未签到

发表于 2011-9-26 08:36:27 | 显示全部楼层
在carnode->setUpdateCallback(new osg::AnimationPathCallback(path.get()));这里的path里,只能设置世界坐标系的旋转角度
您是如何得到这一结论的?它显然是跟从当前节点的坐标系统而非世界的

该用户从未签到

 楼主| 发表于 2011-9-26 14:47:51 | 显示全部楼层
回复 2# array


    关于path里是当前物体坐标系还是世界坐标系,我确实有点糊涂。但是,我程序里实现的时候是把这个path考虑成世界坐标系(程序里没有坐标系的设置,有关于这个方面的设置吗?)。然后,实现小车的连续控制了。您可以看看。就是鼠标点哪,小车就会往哪转、往哪走。(程序还不是很完善)。我仅仅是想实现这么个功能。还有其他方法或者思路没?谢谢


#include "stdafx.h"
#include <osg/MatrixTransform>
#include <osg/Group>
#include <osg/Node>
#include <osgUtil/Optimizer>
#include <osg/LineSegment>
#include <osgDB/Registry>
#include <osgDB/ReadFile>
#include <osgGA/TrackballManipulator>
#include <osgViewer/Viewer>
#include <math.h>
osg::ref_ptr<osg::Group>m_root;
double rotz0,rotz;//绕z旋转角度的弧度值,当前位置的角度和目标位置的角度,是通过坐标变换后的新坐标系中确定的旋转角度值
double posx0,posy0,posz0;//当前位置,每次都会记录上次小车的位置坐标
double posx,posy,posz;//目标位置
osg::ref_ptr<osg::MatrixTransform> carnode;
double newposx0,newposy0,newposz0;//新坐标系下的当前坐标值
double newposx,newposy,newposz;//新坐标系下的目标坐标值
int firstflag ;//鼠标第一次点击标志
double zbrot;//新坐标系相对于世界坐标系的旋转角度,是一个累加值。会一直累加车的旋转角度

class keyhandler : public osgGA::GUIEventHandler
{
public : virtual bool handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter& aa,osg::Object*,osg::NodeVisitor*)
   {
    osgViewer::Viewer* viewer = dynamic_cast<osgViewer::Viewer*>(&aa);
    switch (ea.getEventType())
    {
    case osgGA::GUIEventAdapter:USH:
     if(ea.getButton()==osgGA::GUIEventAdapter:EFT_MOUSE_BUTTON)
     {
      osgUtil::LineSegmentIntersector::Intersections intersections;
      float x=ea.getX();
      float y=ea.getY();
    if(  viewer->computeIntersections(x,y,intersections))
    {
      osgUtil::LineSegmentIntersector::Intersections::iterator hitr=intersections.begin();
       posx=hitr->getWorldIntersectPoint().x();
       posy=hitr->getWorldIntersectPoint().y();
       posz=hitr->getWorldIntersectPoint().z();
double rotscale=0;//每次需要旋转的度数,计算每次小车需要的旋转角度
double rottime=0;//每次旋转需要的时间
double transtime=0;//每次移动需要的时间
if(firstflag==0)//鼠标第一次点击时,会计算出小车到达目标地点的旋转角度。
{
rotscale=(-(posx-posx0)/fabs(posx-posx0))*(osg::PI_2-((posy-posy0)/fabs(posy-posy0))*atan(fabs(posy-posy0)/fabs(posx-posx0)));
rotz=rotscale+rotz;
if(posx-posx0>=0){zbrot=-rotscale;}
else{zbrot=-rotscale;};
firstflag++;
}
else{     //以后再点击时,会考虑xy坐标的坐标系转换。得到所需的旋转角度
  newposx=posx*cos(zbrot)-posy*sin(zbrot);
  newposy=posx*sin(zbrot)+posy*cos(zbrot);
  newposx0=posx0*cos(zbrot)-posy0*sin(zbrot);
  newposy0=posx0*sin(zbrot)+posy0*cos(zbrot);
  rotscale=(-(newposx-newposx0)/fabs(newposx-newposx0))*(osg::PI_2-((newposy-newposy0)/fabs(newposy-newposy0))*atan(fabs(newposy-newposy0)/fabs(newposx-newposx0)));
  rotz=rotscale+rotz;
  if(newposx-newposx0>=0){zbrot=-rotscale+zbrot;}
  else{zbrot=-rotscale+zbrot;};
};


rottime=fabs(rotscale);
transtime=sqrt(pow((posx-posx0),2)+pow((posy-posy0),2));
osg::ref_ptr<osg::AnimationPath> path =new osg::AnimationPath;
path->setLoopMode(osg::AnimationPath::NO_LOOPING);
path->insert(0.0,osg::AnimationPath::ControlPoint(osg::Vec3(posx0,posy0,posz0),osg:uat(rotz0,osg::Vec3(0.0,0.0,1.0))));
path->insert(rottime,osg::AnimationPath::ControlPoint(osg::Vec3(posx0,posy0,posz0),osg::Quat(rotz,osg::Vec3(0.0,0.0,1.0))));
path->insert((rottime+transtime),osg::AnimationPath::ControlPoint(osg::Vec3(posx,posy,posz),osg::Quat(rotz,osg::Vec3(0.0,0.0,1.0))));
carnode->setUpdateCallback(new osg::AnimationPathCallback(path.get()));

rotz0=rotz;
posx0=posx;
posy0=posy;
posz0=posz;
    }

     }
    }
    return false;
   }
};
int main( )
{
rotz0=0;rotz=0;
posx0=0;posy0=0;posz0=0;
posx=0;posy=0;posz=0;
firstflag=0;
zbrot=0;

carnode=new osg::MatrixTransform();
osg::ref_ptr<osgViewer::Viewer>viewer=new osgViewer::Viewer();
m_root =new osg::Group();
osg::ref_ptr<osg::Node>node= osgDB::readNodeFile("qiangti.osg");//随便一个面的模型。
m_root->addChild(node.get());
osg::ref_ptr<osg::Node>node0= osgDB::readNodeFile("car.osg");
carnode->addChild(node0.get());

m_root->addChild(carnode.get());
viewer->addEventHandler(new keyhandler());
viewer->setSceneData(m_root.get());
viewer->realize();
viewer->run();
return 0;
}

该用户从未签到

发表于 2011-9-29 14:37:31 | 显示全部楼层
请问您的控制小车移动的详细源代码能否借我看一下,最近我也在搞这个,目前还没怎么有头绪~~谢谢啊

该用户从未签到

 楼主| 发表于 2011-9-30 18:13:47 | 显示全部楼层
回复 4# glk

  1. #include "stdafx.h"

  2. #include <osg/Notify>
  3. #include <osg/MatrixTransform>
  4. #include <osg/PositionAttitudeTransform>
  5. #include <osg/Group>
  6. #include <osg/Geode>
  7. #include <osg/Node>

  8. #include <osgUtil/Optimizer>
  9. #include <osg/LineSegment>

  10. #include <osgDB/Registry>
  11. #include <osgDB/ReadFile>

  12. #include <osgGA/TrackballManipulator>
  13. #include <osgGA/FlightManipulator>
  14. #include <osgGA/DriveManipulator>
  15. #include <osgParticle/ExplosionDebrisEffect>
  16. #include <osgParticle/ExplosionEffect>
  17. #include <osgParticle/SmokeEffect>
  18. #include <osgParticle/FireEffect>
  19. #include <osgSim/OverlayNode>

  20. #include <osgViewer/Viewer>
  21. #include <iostream>
  22. #include<sstream>
  23. #include <math.h>

  24. osg::ref_ptr<osg::Group>m_root;
  25. double rotz0,rotz;//绕z旋转角度的弧度值,当前位置的角度和目标位置的角度,是通过坐标变换后的新坐标系中确定的旋转角度值
  26. double posx0,posy0,posz0;//当前位置
  27. double posx,posy,posz;//目标位置
  28. osg::ref_ptr<osg::MatrixTransform> carnode;
  29. //double rotscale;
  30. double newposx0,newposy0,newposz0;//新坐标系下的当前坐标值
  31. double newposx,newposy,newposz;//新坐标系下的目标坐标值
  32. int firstflag ;
  33. //double rotnum;//新坐标系相对于前坐标系的旋转角度
  34. //double rott;
  35. double carrot;//rotz;
  36. double zbrot;
  37. osg::Quat rtquat;
  38. osg::Vec3 rtpos;
  39. double nowposx,nowposy,nowposz;
  40. double nowrot;//当前相对世界坐标系的旋转角度,可以赋值给zbrot
  41. osg::Vec3 vec;
  42. osg::ref_ptr<osg::Node>node0;


  43. class keyhandler : public osgGA::GUIEventHandler
  44. {
  45. public : virtual bool handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter& aa,osg::Object*,osg::NodeVisitor*)
  46.                  {
  47.                          osgViewer::Viewer* viewer = dynamic_cast<osgViewer::Viewer*>(&aa);
  48.                          switch (ea.getEventType())
  49.                          {
  50.                          case osgGA::GUIEventAdapter::PUSH:
  51.                                  if(ea.getButton()==osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON)
  52.                                  {
  53.                                          osgUtil::LineSegmentIntersector::Intersections intersections;

  54.                                          float x=ea.getX();
  55.                                          float y=ea.getY();
  56.                                 if(         viewer->computeIntersections(x,y,intersections))
  57.                                 {
  58.                                          osgUtil::LineSegmentIntersector::Intersections::iterator hitr=intersections.begin();
  59.                                           posx=hitr->getWorldIntersectPoint().x();
  60.                                           posy=hitr->getWorldIntersectPoint().y();
  61.                                          //posy=hitr->getWorldIntersectPoint().x();
  62.                                          //posx=hitr->getWorldIntersectPoint().y();
  63.                                           posz=hitr->getWorldIntersectPoint().z();
  64.         double rotscale=0;//每次需要旋转的度数

  65.         double rottime=0;//每次旋转需要的时间
  66.         double transtime=0;//每次移动需要的时间
  67.         //osg::ref_ptr<Matrix> mMatrixWorld;//获得当前小车的世界坐标系中的矩阵

  68.         osg::NodePath np = node0->getParentalNodePaths()[0];

  69.         osg::Matrix matrixWorld = osg::computeLocalToWorld(np);

  70.         rtpos=matrixWorld.getTrans();
  71.     rtquat=matrixWorld.getRotate();
  72.         nowposx=rtpos[0];
  73.         nowposy=rtpos[1];
  74.         nowposz=rtpos[2];

  75. //        rtquat.getRotate(nowrot,vec);

  76.        
  77.         posx0=nowposx;
  78.         posy0=nowposy;
  79.   //  zbrot=nowrot;
  80.         //rotz0=nowrot;


  81. //        if(firstflag==0)
  82. //        {
  83. //        rotscale=(-(posx-posx0)/fabs(posx-posx0))*(osg::PI_2-((posy-posy0)/fabs(posy-posy0))*atan(fabs(posy-posy0)/fabs(posx-posx0)));
  84. //        rotz=rotscale+rotz;
  85. //        if(posx-posx0>=0){zbrot=-rotscale;}
  86. //        else{zbrot=-rotscale;};
  87. //firstflag++;
  88. //        }
  89.         //else
  90.        
  91. /*                newposx=posx*cos(zbrot)-posy*sin(zbrot);
  92.                 newposy=posx*sin(zbrot)+posy*cos(zbrot);

  93.                 newposx0=posx0*cos(zbrot)-posy0*sin(zbrot);
  94.                 newposy0=posx0*sin(zbrot)+posy0*cos(zbrot);

  95.                 rotscale=(-(newposx-newposx0)/fabs(newposx-newposx0))*(osg::PI_2-((newposy-newposy0)/fabs(newposy-newposy0))*atan(fabs(newposy-newposy0)/fabs(newposx-newposx0)));
  96.                 rotz=rotscale+zbrot;
  97.                 if(newposx-newposx0>=0){zbrot=-rotscale+zbrot;}
  98.                 else{zbrot=-rotscale+zbrot;};*/
  99.         if(firstflag==0)
  100.         {
  101.                 rotscale=(-(posx-posx0)/fabs(posx-posx0))*(osg::PI_2-((posy-posy0)/fabs(posy-posy0))*atan(fabs(posy-posy0)/fabs(posx-posx0)));
  102.                 rotz=rotscale+rotz;
  103.                 if(posx-posx0>=0){zbrot=-rotscale;}
  104.                 else{zbrot=-rotscale;};
  105.                 firstflag++;
  106.         }
  107.         else{
  108.                 newposx=posx*cos(zbrot)-posy*sin(zbrot);
  109.                 newposy=posx*sin(zbrot)+posy*cos(zbrot);

  110.                 newposx0=posx0*cos(zbrot)-posy0*sin(zbrot);
  111.                 newposy0=posx0*sin(zbrot)+posy0*cos(zbrot);

  112.                 rotscale=(-(newposx-newposx0)/fabs(newposx-newposx0))*(osg::PI_2-((newposy-newposy0)/fabs(newposy-newposy0))*atan(fabs(newposy-newposy0)/fabs(newposx-newposx0)));
  113.                 rotz=rotscale+rotz;
  114.                 if(newposx-newposx0>=0){zbrot=-rotscale+zbrot;}
  115.                 else{zbrot=-rotscale+zbrot;};

  116.         };
  117.        


  118. //rotz=rotz+rotscale;
  119. rottime=fabs(rotscale);
  120. transtime=sqrt(pow((posx-posx0),2)+pow((posy-posy0),2));
  121. osg::ref_ptr<osg::AnimationPath> path =new osg::AnimationPath;
  122. path->setLoopMode(osg::AnimationPath::NO_LOOPING);
  123. path->insert(0.0,osg::AnimationPath::ControlPoint(osg::Vec3(posx0,posy0,posz0),osg::Quat(rotz0,osg::Vec3(0.0,0.0,1.0))));
  124. path->insert(rottime,osg::AnimationPath::ControlPoint(osg::Vec3(posx0,posy0,posz0),osg::Quat(rotz,osg::Vec3(0.0,0.0,1.0))));
  125. path->insert((rottime+transtime),osg::AnimationPath::ControlPoint(osg::Vec3(posx,posy,posz),osg::Quat(rotz,osg::Vec3(0.0,0.0,1.0))));

  126. carnode->setUpdateCallback(new osg::AnimationPathCallback(path.get()));
  127. //carnode->setMatrix(osg::Matrixd::scale(osg::Vec3d(5.0,5.0,5.0)));
  128. rotz0=rotz;
  129. //posx0=posx;
  130. //posy0=posy;
  131. //posz0=posz;
  132.                                 }


  133.                                  }
  134.                          }
  135.                          return false;
  136.                  }

  137. };
  138. int main( )
  139. {
  140.         rotz0=0;rotz=0;
  141.         posx0=0;posy0=0;posz0=0;
  142.         posx=0;posy=0;posz=0;
  143.         firstflag=0;
  144.         zbrot=0;
  145. //        rotnum=0;
  146.     carnode=new osg::MatrixTransform();
  147.         osg::ref_ptr<osgViewer::Viewer>viewer=new osgViewer::Viewer();
  148.         m_root =new osg::Group();
  149.         osg::ref_ptr<osg::Node>node= osgDB::readNodeFile("qiangti.osg");
  150.         m_root->addChild(node.get());
  151.         node0= osgDB::readNodeFile("car.osg");
  152.        
  153.         carnode->addChild(node0.get());
  154. //        carnode->setMatrix(osg::Matrixd::translate(osg::Vec3d(0,0,60.0)));
  155.         m_root->addChild(carnode.get());
  156.         viewer->addEventHandler(new keyhandler());
  157.         viewer->setSceneData(m_root.get());
  158.         viewer->realize();
  159.         viewer->run();
  160.         return 0;
  161. }

复制代码

该用户从未签到

 楼主| 发表于 2011-9-30 18:17:31 | 显示全部楼层
回复 4# glk


    car.osg是一个小车的模型,在xoy平面,车头朝着y的正向。qingti.osg是一个随便的大平面就可以了,在xoy平面,z坐标为0.直接编译就ok了。可以控制车向任何方向移动。车会先转向,然后移动。点哪,车向哪。

该用户从未签到

发表于 2011-10-10 21:55:06 | 显示全部楼层
回复 6# yugang2010


    太感谢您了,呵呵,以后多多交流

该用户从未签到

发表于 2011-10-10 22:50:29 | 显示全部楼层
回复 1# yugang2010


    小车模型应该有个正方向吧,把小车的方向设置为两点间的向量方向不就行了吗?

该用户从未签到

发表于 2011-10-11 13:46:14 | 显示全部楼层
回复 5# yugang2010


    你好,car.osg的模型是自己建的吗?

该用户从未签到

 楼主| 发表于 2011-10-23 21:32:33 | 显示全部楼层
回复 8# wangsli


    小车方向朝y的正向的,您有其他的想法的话,请不吝赐教。谢谢

该用户从未签到

 楼主| 发表于 2011-10-23 21:33:06 | 显示全部楼层
回复 9# knightlixiao


    嗯,车是同学建的。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

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

联系我们

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