• ogre3D学习基础12 --- 让机器人动起来(移动模型动画)


      学了那么长时间,才学会跑起来。My Ogre,动起来。

      第一,还是要把框架搭起来,这里我们用到双端队列deque,前面已经简单介绍过,头文件如下:

    #include  "ExampleApplication.h"
    #include "deque"
    using namespace std;

      第二,是我们的监听器,继承至ExampleFrameListener,构造函数我们使用五个参数,分别为渲染窗口,摄像机,场景节点,实体,行走路线上的位置坐标。

    1     MoveDemoListener(RenderWindow *win,Camera *cam,SceneNode *sn,Entity *ent,std::deque <Vector3> &walk) :ExampleFrameListener(win,cam,false,false),              mNode(sn),mEntity(ent),mWalkList(walk)
    2     {
    3 
    4         // Set default values for variables
    5         mWalkSpeed = 35.0f;//行走 速度设为每秒 35 个单位
    6         mDirection = Vector3::ZERO;//可用来判断机器人是否正在行走,为零时不走
    7 
    8     }

      第三,我们接着完善监听器首先成员函数添加了

     1     Real mDistance;//实体要移动的距离
     2     Vector3 mDirection;//方向
     3     Vector3 mDestination;//目的地
     4 
     5     AnimationState *mAnimationState;//物体的目前的动画状态
     6 
     7     Entity *mEntity;
     8     SceneNode *mNode;
     9     std::deque<Vector3> mWalkList;//要行走的点
    10     Real mWalkSpeed;//物体移动的速度

      然后添加一个函数,bool nextLocation();用来判断是否有下一个方位,确定下一步怎么走。如果返回行走的队列为空,返回false

     1    bool nextLocation()
     2     {
     3         if (mWalkList.empty())
     4             return false;
     5         mDestination = mWalkList.front(); // 取得队列的头部
     6         mWalkList.pop_front(); // 删除已走过的点
     7         mDirection = mDestination - mNode->getPosition();//距离由目的地减去当前位置得到
     8         mDistance = mDirection.normalise();//normalise()作用是将方向向量转换成单位向量,返回向量的原始长度
     9         return ture;
    10     }

       最后我们添加在每一帧前渲染的函数frameStarted(),这函数我们见了好多次,以后我们还会见面的。移动、转向操作等都在这里。

     1     bool frameStarted(const FrameEvent &evt)
     2     {
     3         if (mDirection == Vector3::ZERO)
     4         {
     5             if (nextLocation())//如果行走列表不为空
     6             {
     7                 // 设置行走的动画
     8                 mAnimationState = mEntity->getAnimationState("Walk");//设置动画为走动
     9                 mAnimationState->setLoop(true);//循环执行
    10                 mAnimationState->setEnabled(true);//激活
    11             }
    12         }
    13         else//开始 移动
    14         {
    15             Real move = mWalkSpeed * evt.timeSinceLastFrame;//速度*时间 = 移动距离
    16             mDistance -= move;//更新距离
    17             if (mDistance <= 0.0f)//小于0,说明已经走过目标地点
    18             {
    19                 mNode->setPosition(mDestination);//重新设置为目的地
    20                 mDirection = Vector3::ZERO;//方向为0,不走
    21                 if (! nextLocation())//如果行走列表为空,没有目的地
    22                 {// Set Idle animation
    23                     mAnimationState = mEntity->getAnimationState("Idle");//从网格动画的动画集(Idle)中获取当前的状态
    24                     mAnimationState->setLoop(true);//设置循环
    25                     mAnimationState->setEnabled(true);//激活
    26                 }
    27                 else    //继续走
    28                 {
    29                     Vector3 src = mNode->getOrientation() * Vector3::UNIT_X;//获取实体的当前朝向,这里有向量的乘积,如果俩个向量方向相反,乘积就是-1
    30                     if ((1.0f + src.dotProduct(mDirection)) < 0.0001f)//如果要旋转180度
    31                     {
    32                         mNode->yaw(Degree(180));
    33                     }
    34                     else//如果不是要旋转180度
    35                     {
    36                         Ogre::Quaternion quat = src.getRotationTo(mDirection);//获取方向
    37                         mNode->rotate(quat);//旋转
    38                     } // else
    39                 }
    40             }
    41             else
    42             {
    43                 mNode->translate(mDirection * move);//移动一定距离
    44             } // else
    45         } // if
    46 
    47         mAnimationState->addTime(evt.timeSinceLastFrame);//更新动画状态
    48         return ExampleFrameListener::frameStarted(evt);
    49     }

      我已经把注释写的很详细了。这里说一下第29行Vector3 src = mNode->getOrientation() * Vector3::UNIT_X;这里牵涉到向量乘积的问题,两个向量乘积有以下两种情况 

      向量的积分为数量积和向量积 数量积就是向量的点乘 向量积就是向量的叉乘
      设a(x,y,z) b(m,n,p)
      则 a点乘b=xm+yn+zp
      或 a点乘b=|a||b|*cos<a,b>
      设a=xi+yj+zk b=mi+nj+pk
      则叉乘 a×b=(yp-zn)i+(zm-xp)j+(xn-ym)k

      Vector3 src = mNode->getOrientation() * Vector3::UNIT_X;//这个是点乘,结果是一个数,大小在-1,1之间。两个向量方向相反时,乘积为-1

      还有个老熟人createFrameListener(),我就不解释了,不懂,看前一章。

    void createFrameListener(void)
        {
            mFrameListener = new MoveDemoListener(mWindow,mCamera,mNode,mEntity,mWalkList);
            mFrameListener->showDebugOverlay(true);
            mRoot->addFrameListener(mFrameListener);
        }

      第四,创建场景,如下,都是一些简单的东西,不解释

     1 void createScene(void)
     2     {
     3         mSceneMgr->setAmbientLight( ColourValue( 1.0f, 1.0f, 1.0f ) );
     4         mEntity = mSceneMgr->createEntity( "Robot", "robot.mesh" );
     5         mNode = mSceneMgr->getRootSceneNode( )->createChildSceneNode( "RobotNode", Vector3( 0.0f, 0.0f, 25.0f ) );
     6         mNode->attachObject( mEntity );
     7 
     8         // 创建走动列表
     9         mWalkList.push_back( Vector3( 550.0f, 0.0f, 50.0f ) );
    10         mWalkList.push_back( Vector3(-100.0f, 0.0f, -200.0f ) );
    11 
    12         Entity *ent;
    13         SceneNode *node;
    14         ent = mSceneMgr->createEntity( "Knot1", "knot.mesh" );
    15         node = mSceneMgr->getRootSceneNode( )->createChildSceneNode( "Knot1Node",Vector3( 0.0f, -10.0f, 25.0f ) );
    16         node->attachObject( ent );
    17         node->setScale( 0.1f, 0.1f, 0.1f );
    18         ent = mSceneMgr->createEntity( "Knot2", "knot.mesh" );
    19         node = mSceneMgr->getRootSceneNode( )->createChildSceneNode( "Knot2Node",Vector3( 550.0f, -10.0f, 50.0f ) );
    20         node->attachObject( ent );
    21         node->setScale( 0.1f, 0.1f, 0.1f );
    22         ent = mSceneMgr->createEntity( "Knot3", "knot.mesh" );
    23         node = mSceneMgr->getRootSceneNode( )->createChildSceneNode( "Knot3Node",Vector3(-100.0f, -10.0f,-200.0f ) );
    24         node->attachObject( ent );
    25         node->setScale( 0.1f, 0.1f, 0.1f );
    26 
    27         mCamera->setPosition( 90.0f, 280.0f, 535.0f );
    28         mCamera->pitch( Degree(-30.0f) );
    29         mCamera->yaw( Degree(-15.0f) );
    30     }

     

      好了,完整代码如下

      1 #include  "ExampleApplication.h"
      2 #include "deque"
      3 using namespace std;
      4 
      5 class MoveDemoListener : public ExampleFrameListener
      6 {
      7 public:
      8     MoveDemoListener(RenderWindow *win,Camera *cam,SceneNode *sn,Entity *ent,std::deque <Vector3> &walk)
      9         :ExampleFrameListener(win,cam,false,false),mNode(sn),mEntity(ent),mWalkList(walk)
     10     {    
     11         mWalkSpeed = 35.0f;//行走 速度设为每秒 35 个单位
     12         mDirection = Vector3::ZERO;//可用来判断机器人是否正在行走
     13     }
     14 
     15     bool nextLocation()
     16     {
     17         if (mWalkList.empty())
     18             return false;
     19         mDestination = mWalkList.front(); // 
     20         mWalkList.pop_front(); // 
     21         mDirection = mDestination - mNode->getPosition();
     22         mDistance = mDirection.normalise();
     23         return true;
     24     }
     25     bool frameStarted(const FrameEvent &evt)
     26     {
     27         if (mDirection == Vector3::ZERO)
     28         {
     29             if (nextLocation())//如果行走列表不为空
     30             {
     31                 // 设置行走的动画
     32                 mAnimationState = mEntity->getAnimationState("Walk");//设置动画为走动
     33                 mAnimationState->setLoop(true);//循环执行
     34                 mAnimationState->setEnabled(true);//激活
     35             }
     36         }
     37         else//开始 移动
     38         {
     39             Real move = mWalkSpeed * evt.timeSinceLastFrame;//速度*时间 = 移动距离
     40             mDistance -= move;//更新距离
     41             if (mDistance <= 0.0f)//小于0,说明已经走过目标地点
     42             {
     43                 mNode->setPosition(mDestination);//重新设置为目的地
     44                 mDirection = Vector3::ZERO;//方向为0,不走
     45                 if (! nextLocation())//如果行走列表为空,没有目的地
     46                 {
     47                     mAnimationState = mEntity->getAnimationState("Idle");//从网格动画的动画集(Idle)中获取当前的状态
     48                     mAnimationState->setLoop(true);//设置循环
     49                     mAnimationState->setEnabled(true);//激活
     50                 }
     51                 else    //继续走
     52                 {
     53                     Vector3 src = mNode->getOrientation() * Vector3::UNIT_X;//获取实体的当前朝向,这里有向量的乘积,如果俩个向量方向相反,乘积就是-1
     54                     if ((1.0f + src.dotProduct(mDirection)) < 0.0001f)//如果要旋转180度
     55                     {
     56                         mNode->yaw(Degree(180));
     57                     }
     58                     else//如果不是要旋转180度
     59                     {
     60                         Ogre::Quaternion quat = src.getRotationTo(mDirection);//获取方向
     61                         mNode->rotate(quat);//旋转
     62                     } // else
     63                 }
     64             }
     65             else
     66             {
     67                 mNode->translate(mDirection * move);//移动一定距离
     68             } // else
     69         } // if
     70 
     71         mAnimationState->addTime(evt.timeSinceLastFrame);//更新动画状态
     72         return ExampleFrameListener::frameStarted(evt);
     73     }
     74 protected:
     75     Real mDistance;//实体要移动的距离
     76     Vector3 mDirection;//方向
     77     Vector3 mDestination;//目的地
     78 
     79     AnimationState *mAnimationState;//物体的目前的动画状态
     80 
     81     Entity *mEntity;
     82     SceneNode *mNode;
     83     std::deque<Vector3> mWalkList;//要行走的点
     84     Real mWalkSpeed;//物体移动的速度
     85 
     86 };
     87 
     88 class MoveDemoApplication:public ExampleApplication
     89 {
     90 public:
     91     MoveDemoApplication()
     92     {
     93 
     94     }
     95     ~MoveDemoApplication()
     96     {
     97 
     98     }
     99 protected:
    100     Entity *mEntity;
    101     SceneNode *mNode;
    102     std::deque<Vector3> mWalkList;
    103     void createScene(void)
    104     {
    105         mSceneMgr->setAmbientLight( ColourValue( 1.0f, 1.0f, 1.0f ) );
    106         mEntity = mSceneMgr->createEntity( "Robot", "robot.mesh" );
    107         mNode = mSceneMgr->getRootSceneNode( )->createChildSceneNode( "RobotNode", Vector3( 0.0f, 0.0f, 25.0f ) );
    108         mNode->attachObject( mEntity );
    109 
    110         mWalkList.push_back( Vector3( 550.0f, 0.0f, 50.0f ) );
    111         mWalkList.push_back( Vector3(-100.0f, 0.0f, -200.0f ) );
    112 
    113         Entity *ent;
    114         SceneNode *node;
    115         ent = mSceneMgr->createEntity( "Knot1", "knot.mesh" );
    116         node = mSceneMgr->getRootSceneNode( )->createChildSceneNode( "Knot1Node",Vector3( 0.0f, -10.0f, 25.0f ) );
    117         node->attachObject( ent );
    118         node->setScale( 0.1f, 0.1f, 0.1f );
    119         ent = mSceneMgr->createEntity( "Knot2", "knot.mesh" );
    120         node = mSceneMgr->getRootSceneNode( )->createChildSceneNode( "Knot2Node",Vector3( 550.0f, -10.0f, 50.0f ) );
    121         node->attachObject( ent );
    122         node->setScale( 0.1f, 0.1f, 0.1f );
    123         ent = mSceneMgr->createEntity( "Knot3", "knot.mesh" );
    124         node = mSceneMgr->getRootSceneNode( )->createChildSceneNode( "Knot3Node",Vector3(-100.0f, -10.0f,-200.0f ) );
    125         node->attachObject( ent );
    126         node->setScale( 0.1f, 0.1f, 0.1f );
    127 
    128         mCamera->setPosition( 90.0f, 280.0f, 535.0f );
    129         mCamera->pitch( Degree(-30.0f) );
    130         mCamera->yaw( Degree(-15.0f) );
    131     }
    132 
    133     void createFrameListener(void)
    134     {
    135         mFrameListener = new MoveDemoListener(mWindow,mCamera,mNode,mEntity,mWalkList);
    136         mFrameListener->showDebugOverlay(true);
    137         mRoot->addFrameListener(mFrameListener);
    138     }
    139 
    140 
    141 };
    142 
    143 
    144 #include "windows.h"
    145 
    146 INT WINAPI WinMain(HINSTANCE hInstance,  HINSTANCE hPrevInstance, LPSTR lpCmdLine, INT)
    147 {
    148     MoveDemoApplication app;
    149     app.go();
    150     return 0;
    151 }

      

  • 相关阅读:
    MySql 应用语句
    MySql 存储过程 退出
    MySql 存储过程 光标只循环一次
    MySql获取两个日期间的时间差
    VM VirtualBox 全屏模式 && 自动缩放模式 相互切换
    区分不同操作系统、编译器不同版本的宏
    debian下配置网络 安装无线网卡驱动 Broadcom BCMXX系列
    YII 主题设置
    Unix线程概念、控制原语、属性
    远程IPC种植木马
  • 原文地址:https://www.cnblogs.com/songliquan/p/3317515.html
Copyright © 2020-2023  润新知