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 }

  

原文地址:https://www.cnblogs.com/songliquan/p/3317515.html