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 }
本文来自博客园,作者:struggle_time,转载请注明原文链接:https://www.cnblogs.com/songliquan/p/3317515.html