ogre3D学习基础12 --- 让机器人动起来(移动模型动画)
学了那么长时间,才学会跑起来。My Ogre,动起来。
第一,还是要把框架搭起来,这里我们用到双端队列deque,前面已经简单介绍过,头文件如下:
#include "ExampleApplication.h"
#include "deque"
using namespace std;
第二,是我们的监听器,继承至ExampleFrameListener,构造函数我们使用五个参数,分别为渲染窗口,摄像机,场景节点,实体,行走路线上的位置坐标。
MoveDemoListener(RenderWindow *win,Camera *cam,SceneNode *sn,Entity *ent,std::deque <Vector3> &walk) :ExampleFrameListener(win,cam,false,false), mNode(sn),mEntity(ent),mWalkList(walk)
{ // Set default values for variables
mWalkSpeed = 35.0f;//行走 速度设为每秒 35 个单位
mDirection = Vector3::ZERO;//可用来判断机器人是否正在行走,为零时不走 }
第三,我们接着完善监听器,首先成员函数添加了
Real mDistance;//实体要移动的距离
Vector3 mDirection;//方向
Vector3 mDestination;//目的地 AnimationState *mAnimationState;//物体的目前的动画状态 Entity *mEntity;
SceneNode *mNode;
std::deque<Vector3> mWalkList;//要行走的点
Real mWalkSpeed;//物体移动的速度
然后添加一个函数,bool nextLocation();用来判断是否有下一个方位,确定下一步怎么走。如果返回行走的队列为空,返回false
bool nextLocation()
{
if (mWalkList.empty())
return false;
mDestination = mWalkList.front(); // 取得队列的头部
mWalkList.pop_front(); // 删除已走过的点
mDirection = mDestination - mNode->getPosition();//距离由目的地减去当前位置得到
mDistance = mDirection.normalise();//normalise()作用是将方向向量转换成单位向量,返回向量的原始长度
return ture;
}
最后我们添加在每一帧前渲染的函数frameStarted(),这函数我们见了好多次,以后我们还会见面的。移动、转向操作等都在这里。
bool frameStarted(const FrameEvent &evt)
{
if (mDirection == Vector3::ZERO)
{
if (nextLocation())//如果行走列表不为空
{
// 设置行走的动画
mAnimationState = mEntity->getAnimationState("Walk");//设置动画为走动
mAnimationState->setLoop(true);//循环执行
mAnimationState->setEnabled(true);//激活
}
}
else//开始 移动
{
Real move = mWalkSpeed * evt.timeSinceLastFrame;//速度*时间 = 移动距离
mDistance -= move;//更新距离
if (mDistance <= 0.0f)//小于0,说明已经走过目标地点
{
mNode->setPosition(mDestination);//重新设置为目的地
mDirection = Vector3::ZERO;//方向为0,不走
if (! nextLocation())//如果行走列表为空,没有目的地
{// Set Idle animation
mAnimationState = mEntity->getAnimationState("Idle");//从网格动画的动画集(Idle)中获取当前的状态
mAnimationState->setLoop(true);//设置循环
mAnimationState->setEnabled(true);//激活
}
else //继续走
{
Vector3 src = mNode->getOrientation() * Vector3::UNIT_X;//获取实体的当前朝向,这里有向量的乘积,如果俩个向量方向相反,乘积就是-1
if ((1.0f + src.dotProduct(mDirection)) < 0.0001f)//如果要旋转180度
{
mNode->yaw(Degree());
}
else//如果不是要旋转180度
{
Ogre::Quaternion quat = src.getRotationTo(mDirection);//获取方向
mNode->rotate(quat);//旋转
} // else
}
}
else
{
mNode->translate(mDirection * move);//移动一定距离
} // else
} // if mAnimationState->addTime(evt.timeSinceLastFrame);//更新动画状态
return ExampleFrameListener::frameStarted(evt);
}
我已经把注释写的很详细了。这里说一下第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);
}
第四,创建场景,如下,都是一些简单的东西,不解释
void createScene(void)
{
mSceneMgr->setAmbientLight( ColourValue( 1.0f, 1.0f, 1.0f ) );
mEntity = mSceneMgr->createEntity( "Robot", "robot.mesh" );
mNode = mSceneMgr->getRootSceneNode( )->createChildSceneNode( "RobotNode", Vector3( 0.0f, 0.0f, 25.0f ) );
mNode->attachObject( mEntity ); // 创建走动列表
mWalkList.push_back( Vector3( 550.0f, 0.0f, 50.0f ) );
mWalkList.push_back( Vector3(-100.0f, 0.0f, -200.0f ) ); Entity *ent;
SceneNode *node;
ent = mSceneMgr->createEntity( "Knot1", "knot.mesh" );
node = mSceneMgr->getRootSceneNode( )->createChildSceneNode( "Knot1Node",Vector3( 0.0f, -10.0f, 25.0f ) );
node->attachObject( ent );
node->setScale( 0.1f, 0.1f, 0.1f );
ent = mSceneMgr->createEntity( "Knot2", "knot.mesh" );
node = mSceneMgr->getRootSceneNode( )->createChildSceneNode( "Knot2Node",Vector3( 550.0f, -10.0f, 50.0f ) );
node->attachObject( ent );
node->setScale( 0.1f, 0.1f, 0.1f );
ent = mSceneMgr->createEntity( "Knot3", "knot.mesh" );
node = mSceneMgr->getRootSceneNode( )->createChildSceneNode( "Knot3Node",Vector3(-100.0f, -10.0f,-200.0f ) );
node->attachObject( ent );
node->setScale( 0.1f, 0.1f, 0.1f ); mCamera->setPosition( 90.0f, 280.0f, 535.0f );
mCamera->pitch( Degree(-30.0f) );
mCamera->yaw( Degree(-15.0f) );
}

好了,完整代码如下
#include "ExampleApplication.h"
#include "deque"
using namespace std; class MoveDemoListener : public ExampleFrameListener
{
public:
MoveDemoListener(RenderWindow *win,Camera *cam,SceneNode *sn,Entity *ent,std::deque <Vector3> &walk)
:ExampleFrameListener(win,cam,false,false),mNode(sn),mEntity(ent),mWalkList(walk)
{
mWalkSpeed = 35.0f;//行走 速度设为每秒 35 个单位
mDirection = Vector3::ZERO;//可用来判断机器人是否正在行走
} bool nextLocation()
{
if (mWalkList.empty())
return false;
mDestination = mWalkList.front(); //
mWalkList.pop_front(); //
mDirection = mDestination - mNode->getPosition();
mDistance = mDirection.normalise();
return true;
}
bool frameStarted(const FrameEvent &evt)
{
if (mDirection == Vector3::ZERO)
{
if (nextLocation())//如果行走列表不为空
{
// 设置行走的动画
mAnimationState = mEntity->getAnimationState("Walk");//设置动画为走动
mAnimationState->setLoop(true);//循环执行
mAnimationState->setEnabled(true);//激活
}
}
else//开始 移动
{
Real move = mWalkSpeed * evt.timeSinceLastFrame;//速度*时间 = 移动距离
mDistance -= move;//更新距离
if (mDistance <= 0.0f)//小于0,说明已经走过目标地点
{
mNode->setPosition(mDestination);//重新设置为目的地
mDirection = Vector3::ZERO;//方向为0,不走
if (! nextLocation())//如果行走列表为空,没有目的地
{
mAnimationState = mEntity->getAnimationState("Idle");//从网格动画的动画集(Idle)中获取当前的状态
mAnimationState->setLoop(true);//设置循环
mAnimationState->setEnabled(true);//激活
}
else //继续走
{
Vector3 src = mNode->getOrientation() * Vector3::UNIT_X;//获取实体的当前朝向,这里有向量的乘积,如果俩个向量方向相反,乘积就是-1
if ((1.0f + src.dotProduct(mDirection)) < 0.0001f)//如果要旋转180度
{
mNode->yaw(Degree());
}
else//如果不是要旋转180度
{
Ogre::Quaternion quat = src.getRotationTo(mDirection);//获取方向
mNode->rotate(quat);//旋转
} // else
}
}
else
{
mNode->translate(mDirection * move);//移动一定距离
} // else
} // if mAnimationState->addTime(evt.timeSinceLastFrame);//更新动画状态
return ExampleFrameListener::frameStarted(evt);
}
protected:
Real mDistance;//实体要移动的距离
Vector3 mDirection;//方向
Vector3 mDestination;//目的地 AnimationState *mAnimationState;//物体的目前的动画状态 Entity *mEntity;
SceneNode *mNode;
std::deque<Vector3> mWalkList;//要行走的点
Real mWalkSpeed;//物体移动的速度 }; class MoveDemoApplication:public ExampleApplication
{
public:
MoveDemoApplication()
{ }
~MoveDemoApplication()
{ }
protected:
Entity *mEntity;
SceneNode *mNode;
std::deque<Vector3> mWalkList;
void createScene(void)
{
mSceneMgr->setAmbientLight( ColourValue( 1.0f, 1.0f, 1.0f ) );
mEntity = mSceneMgr->createEntity( "Robot", "robot.mesh" );
mNode = mSceneMgr->getRootSceneNode( )->createChildSceneNode( "RobotNode", Vector3( 0.0f, 0.0f, 25.0f ) );
mNode->attachObject( mEntity ); mWalkList.push_back( Vector3( 550.0f, 0.0f, 50.0f ) );
mWalkList.push_back( Vector3(-100.0f, 0.0f, -200.0f ) ); Entity *ent;
SceneNode *node;
ent = mSceneMgr->createEntity( "Knot1", "knot.mesh" );
node = mSceneMgr->getRootSceneNode( )->createChildSceneNode( "Knot1Node",Vector3( 0.0f, -10.0f, 25.0f ) );
node->attachObject( ent );
node->setScale( 0.1f, 0.1f, 0.1f );
ent = mSceneMgr->createEntity( "Knot2", "knot.mesh" );
node = mSceneMgr->getRootSceneNode( )->createChildSceneNode( "Knot2Node",Vector3( 550.0f, -10.0f, 50.0f ) );
node->attachObject( ent );
node->setScale( 0.1f, 0.1f, 0.1f );
ent = mSceneMgr->createEntity( "Knot3", "knot.mesh" );
node = mSceneMgr->getRootSceneNode( )->createChildSceneNode( "Knot3Node",Vector3(-100.0f, -10.0f,-200.0f ) );
node->attachObject( ent );
node->setScale( 0.1f, 0.1f, 0.1f ); mCamera->setPosition( 90.0f, 280.0f, 535.0f );
mCamera->pitch( Degree(-30.0f) );
mCamera->yaw( Degree(-15.0f) );
} void createFrameListener(void)
{
mFrameListener = new MoveDemoListener(mWindow,mCamera,mNode,mEntity,mWalkList);
mFrameListener->showDebugOverlay(true);
mRoot->addFrameListener(mFrameListener);
} }; #include "windows.h" INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, INT)
{
MoveDemoApplication app;
app.go();
return ;
}
ogre3D学习基础12 --- 让机器人动起来(移动模型动画)的更多相关文章
- ogre3D学习基础1 -- 核心对象与脚本技术
一.核心对象介绍1.命名空间 Ogre3d使用了C++的特性--命名空间,可以防止命名混淆.使用方法也简单,using namespace Ogre;或者直接在使用时加上“Ogre::”的前缀,如Og ...
- ogre3D学习基础13 -- 键盘控制网格动画mesh
以上一节为蓝本,这里增加一点难度,添加了四个节点,增加键盘控制移动速度,使用bool变量控制是否移动. 第一,要增加键盘控制,那就使用OIS::KeyListener,在监听器里添加一个父类KeyLi ...
- ogre3D学习基础5 -- 阴影与动画
五.阴影 阴影是渲染一个真实场景的重要组成部分,它可以给场景中的物体提供更加真实的感觉,同时还可以帮助用户更好的了解对象间的空间关系. 启用阴影: 缺省情况下,阴影是关闭的,开启方式如下: 1.建立场 ...
- ogre3D学习基础8 --- 资源管理器
资源管理 可管理的资源有: 材质资源:在.material文件中包含的材质脚本定义(技术.通路.纹理单元等数据的定义). 模型资源:经过优化的二进制网格模型文件,扩展名为.mesh.包含几何信息和一些 ...
- ogre3D学习基础19 --- 材质的继承,纹理的滚动与旋转
以上一节为基础,废话不多说. 首先新增一个节点,用于比较显示 //新增一个节点 ent = mSceneMgr->createEntity("Quad"); ent-> ...
- ogre3D学习基础18 -- 材质的使用与脚本的简单书写
这一节以基础16为基础,练习材质的使用. 第一,看看框架 //material #include "ExampleApplication.h" class TutorialAppl ...
- ogre3D学习基础11 -- 交换两个场景管理器
这一节,练习一下前几次学习的内容,功能很简单,就是建立两个不同的场景管理器,当按下键盘上某个键时切换镜头. 基本框架不变,这个监听器继承了两个父类,一个是我们的老朋友ExampleFrameListe ...
- ogre3D学习基础9 -- 光源程序实例
这一章练习一下光源的使用,光源分为三种:点光源,聚光源,有向光.具体内容前面说过,这里就不解释了. 继续在上一章的程序的基础上实现. 1.创建摄像机(Camera) createCamera()函数是 ...
- ogre3D学习基础7---材质详解
物体着色的基础 --- 四种不同光照作用 1.环境反射 近似的模拟了场景中的全局辐射,也就是用来近似模拟所有光在场景中不断散射的结果.材质中有相应的属性来代表这种环境反射颜色. 2.漫反射 这种颜色是 ...
随机推荐
- newCoder在线编程---(1)
二维数组查找 题目描述: 在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数. 1.暴 ...
- 网页编辑器CKEditor4.3.1+CKFinder2.4+JW Player6.7(视频播放器)集成
CKEditor是使用最多的一款在线网页编辑器,不仅好用,而且功能强大.易扩展.浏览器兼容性好.另外,CKEditor网页编辑器经常更新.本程序使用的是最新稳定版CKEditor4.3.1,添加使用了 ...
- JavaScript getMonth() 方法
应该特别注意的是Js中getMonth()这个方法的返回值: 定义和用法: getMonth() 方法可返回表示月份的数字. 返回值: dateObject 的月份字段,使用本地时间.返回值是 0(一 ...
- Liunx开发(Extjs4.1+desktop+SSH2超强视频教程实践)(1)
下周一出差宁波了,周六日就折腾点视频: 跟着视频教程开发,不过开发环境换linux,上月找工作,某个吉祥物是松鼠的公司要求用linux开发,没用过的,连面试机会都不给,极其高冷:好吧,咱就试试,用li ...
- Android(java)学习笔记79:Android中SimpleAdapter,ArrayAdapter和BaseAdapter常见的适配器
1. SimpleAdapter(BaseAdapter子类扩展类): simpleAdapter的扩展性最好,可以定义各种各样的布局出来,可以放上ImageView(图片)等.可以显示比较复杂的列表 ...
- 第八章 熟练dom的几个常用方法
显示“缩略词语” <abbr> 标签指示简称或缩写,比如 <abbr title="World Wide Web Consortium">W3C</a ...
- 初学HBase的几个问题
转自 http://itindex.net/detail/50571-hbase-%E9%97%AE%E9%A2%98 本文主要针对对HBase不了解的人.主要想基于个人的理解回答以下几个问题: 什么 ...
- python剑指offer 链表中环的入口节点
题目: 一个链表中包含环,请找出该链表的环的入口结点. 思路: 先说个定理:两个指针一个fast.一个slow同时从一个链表的头部出发, fast一次走2步,slow一次走一步,如果该链表有环,两个指 ...
- python_43_移动文件指针补充
#移动文件指针补充 ''' 文件对象.seek((offset,where)) offset:移动的偏移量,单位为字节.等于正数时向文件尾方向移动,等于负数时向文件头方向移动文件指针 where:指针 ...
- 分词,复旦nlp,NLPIR汉语分词系统
http://www.nlpir.org/ http://blog.csdn.net/zhyh1986/article/details/9167593