OGRE中级教程一 Animation, Walking Between Points, and Basic Quaternions
来源:互联网 发布:mac强制卸载软件 编辑:程序博客网 时间:2024/06/03 15:24
英语水平有限,欢迎大家批评指正
本文并没有将原文全部翻译,只是将其中的一些知识点翻译总结了一下,想要查看详细讲解的话,可以到原文处看一下,附上英文原文地址:http://www.ogre3d.org/tikiwiki/tiki-index.php?page=Intermediate+Tutorial+1&structure=Tutorials
Setting up the Scene
在头文件中我们已经定义了3个变量,mEntity保存我们创建的实体,mNode保存我们创建的节点,mWalkList保存我们想让对象走到的所有点。
首先我们要设置环境光,添加如下代码到ITutorial01::createScene函数中:
// Set the default lighting.
mSceneMgr->setAmbientLight(Ogre::ColourValue(1.0f, 1.0f, 1.0f));
下面我们要在屏幕上创建一个机器人,因此我们要为机器人创建实体,然后为他创建一个节点:
// Create the entity
mEntity = mSceneMgr->createEntity("Robot", "robot.mesh");
// Create the scene node
mNode = mSceneMgr->getRootSceneNode()->
createChildSceneNode("RobotNode", Ogre::Vector3(0.0f, 0.0f, 25.0f));
mNode->attachObject(mEntity);
接下来的代码中,我们要告诉机器人他需要移动到哪些地方。对于STL没有任何了解的童鞋,你们需要知道deque(队列)对象是一个非常高效的双端队列。我们将只使用它的一些方法,push_front和push_back方法相应的把items放入队列最前面和尾部,front和back方法相应的返回队列最前端和尾部的值,pop_front和pop_back方法相应的移除队列最前端和末尾的items,最后empty方法返回队列是否为空。下面的代码添加了两个Vector到队列中,这是我们要机器人移动到的位置:
// Create the walking list
mWalkList.push_back(Ogre::Vector3(550.0f, 0.0f, 50.0f ));
mWalkList.push_back(Ogre::Vector3(-100.0f, 0.0f, -200.0f));
下面,我们要在场景中放一些对象来表明机器人将要移动到哪里,注意他们的Y轴坐标,这使得那些对象处于机器人要移动到的位置的下方,当它经过时,它将站在这些对象的上方。
// Create objects so we can see movement
Ogre::Entity *ent;
Ogre::SceneNode *node;
ent = mSceneMgr->createEntity("Knot1", "knot.mesh");
node = mSceneMgr->getRootSceneNode()->createChildSceneNode("Knot1Node",
Ogre::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",
Ogre::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",
Ogre::Vector3(-100.0f, -10.0f,-200.0f));
node->attachObject(ent);
node->setScale(0.1f, 0.1f, 0.1f);
最后设置一下camera的位置以更好的观察:
// Set the camera to look at our handiwork
mCamera->setPosition(90.0f, 280.0f, 535.0f);
mCamera->pitch(Ogre::Degree(-30.0f));
mCamera->yaw(Ogre::Degree(-15.0f));
Animation
我们要制作(setup)一些基本的动画,OGRE中动画很简单。为此你需要获取实体对象的AnimationState,设置它的选项并使它可用。这将激活动画,但为了运行动画,你仍需要每帧后给他添加时间。我们将一次把这些都设置好,首先找到ITutorial01::createFrameListener并在BaseApplication::createFrameListener函数之后添加如下代码:
// Set idle animation
mAnimationState = mEntity->getAnimationState("Idle");
mAnimationState->setLoop(true);
mAnimationState->setEnabled(true);
第二行获取了实体的AnimationState。第三行我们调用setLoop(true)使得动画一直循环,对某些动画(比如死亡时的动画),我们需要把它设为false。第四行使得动画可用。每个网格(mesh)都有他们自己的动画集。要查看你使用的某一网格的所有动画,你需要下载一个OgreMeshViewer。如果我们现在编译运行程序,没有什么改变。因为我们需要每帧更新一次动画状态(animation state)。添加如下代码到ITutorial01::frameRenderingQueued函数开始:
mAnimationState->addTime(evt.timeSinceLastFrame);
Moving the Robot
现在我们要完成让机器人从一个点走到另一个的的任务。我们要使用4个变量来完成机器人移动的任务。首先我们要把机器人移动的方向保存到mDirection中,把机器人移动的目的地保存到mDestination中,把机器人还要移动的距离保存到mDistance中,把机器人的移动速度保存到mWalkSpeed中。
首先我们要设置这些变量,设置移动速度为35单位每秒。有一点需要注意,我们设置mDirection为零向量是因为我们要用它来判断机器人是否在移动。添加如下代码到ITutorial01::createFrameListener:
// Set default values for variables
mWalkSpeed = 35.0f;
mDirection = Ogre::Vector3::ZERO;
下面设置机器人的动作,为了让机器人移动,我们只需要告诉他改变动画。但是,我们只想有另一个要移动到的位置时机器人才开始移动。因此我们调用ITutorial01::nextLocation函数,添加如下代码到ITutorial01::frameRenderingQueued方法的AnimationState::addTime函数之前:
if (mDirection == Ogre::Vector3::ZERO)
{
if (nextLocation())
{
// Set walking animation
mAnimationState = mEntity->getAnimationState("Walk");
mAnimationState->setLoop(true);
mAnimationState->setEnabled(true);
}
}
如果你现在编译运行程序,机器人将原地走路。这是因为机器人的起始方向为ZERO并且ITutorial01::nextLocation函数总是返回true。
现在我们要真正的在场景中移动机器人,为此我们要让机器人每帧移动一点。在ITutorial01::frameRenderingQueued函数中的AnimationState::addTime函数之前,我们上面的if语句之后添加下面的代码:
else
{
Ogre::Real move = mWalkSpeed * evt.timeSinceLastFrame;
mDistance -= move;
Walkspeed与evt.timeSinceLastFrame相乘是为了无视帧率的变化而保持速度的连贯性,如果你只写Real move = mWalkspeed,机器人在一台很慢的电脑上就会走的很慢,在一台很快的电脑上就会走的很快。
现在我们需要查看是否要到达目标位置,即如果mDistance小于0,我们需要跳到该位置并设置下一个要移动到的位置。注意还要设置mDirection为ZERO向量。如果nextLocation函数不改变mDirection,我们就不移动。
if (mDistance <= 0.0f)
{
mNode->setPosition(mDestination);
mDirection = Ogre::Vector3::ZERO;
现在我们移动到了一个位置,然后要设置(setup)下一个位置的动作。一旦我们知道了是否要移动到另一个位置,我们就能设置合适的动画:
// Set animation based on if the robot has another point to walk to.
if (! nextLocation())
{
// Set Idle animation
mAnimationState = mEntity->getAnimationState("Idle");
mAnimationState->setLoop(true);
mAnimationState->setEnabled(true);
}
else
{
// Rotation Code will go here later
}
}
注意如果在队列中还有要移动到的位置,我们就不需要再次设置移动动画。因为机器人已经在移动了就没有必要再告诉它要移动了。但如果机器人需要移动到另一个位置,我们需要旋转他让他脸朝那个位置。
这关心的是当我们离目标位置很近时,现在我们要处理一下常规情况,我们在移动到该位置的路上但还没到。为此我们要变换机器人移动的方向,然后根据移动速度移动它,如下代码来完成这些功能:
else
{
mNode->translate(mDirection * move);
} // else
} // if
该做的我们基本上已经做了。ITutorial01::nextLocation函数在我们走完所有要走的位置时返回false(注意你要在该函数的末尾加上return true语句):
if (mWalkList.empty())
return false;
现在我们要设置变量(还是在nextLocation函数中),从队列中获取目的地向量(destination vector),通过目的地位置减去场景节点当前位置来设置方向向量(direction vector)。现在我们遇到一个问题,还记得在frameRenderingQueued中我们让mDirection和移动量相乘吗?如果我们这样做,就需要方向向量为单位向量(即它的长为1)。normalise函数帮我们做到这些,并返回该向量原来的长度。Handy that, since we need to also set the distance to the destination。
mDestination = mWalkList.front(); // this gets the front of the deque
mWalkList.pop_front(); // this removes the front of the deque
mDirection = mDestination - mNode->getPosition();
mDistance = mDirection.normalise();
编译运行程序,现在机器人走向所有点,但他总是面朝Ogre::Vector3::UNIT_X方向(他的默认方向)。我们要改变他的朝向,当他朝某一点移动时。
我们要做的是获取机器人面向的方向,然后用rotate函数把他旋转到正确的位置。添加如下代码到"// Rotation Code will go here later"处:
Ogre::Vector3 src = mNode->getOrientation() * Ogre::Vector3::UNIT_X;
Ogre::Quaternion quat = src.getRotationTo(mDirection);
mNode->rotate(quat);
第一行获取了机器人面向的方向,第二行创建了一个四元数来代表(represent)从当前方向到目的方向的旋转,第三行旋转了机器人。
我们在Basic Tutorial 4中简单的提到了四元数,但这是我们第一次实际使用它。简单的讲,四元数是对3维空间中的旋转的描述。他们时用来记录对象是如何在空间中被放置的,也可以再OGRE中用来旋转对象。第一行我们调用getOrientation函数,它返回一个描述了机器人在空间中调整方向的方法。有用OGRE不值得哪一边是机器人的"前面"们我们必须让这个orientation(方向)和UNIT_X向量相乘来得到机器人当前朝向的方向。我们把这个方面存在src变量中。第二行getRotationTo方法返回给我们一个四元数,它描述了从机器人面向的方向旋转到我们想让他面向的方向的旋转。第三行我们旋转节点让他朝向新的方向。我们的代码中只有一个问题,有一种特殊的情况SceneNode::rotate方法将失败。如果我们让机器人旋转180度,旋转代码就会出现一个0错误(zero error)而崩溃。要修正这个问题,我们需要检查是否在进行180度的旋转,如果是我们就只让机器人绕Y轴旋转180度,为此删掉我们刚刚添加的第三行并替换为:
Ogre::Vector3 src = mNode->getOrientation() * Ogre::Vector3::UNIT_X;
if ((1.0f + src.dotProduct(mDirection)) < 0.0001f)
{
mNode->yaw(Ogre::Degree(180));
}
else
{
Ogre::Quaternion quat = src.getRotationTo(mDirection);
mNode->rotate(quat);
} // else
如果两个单位向量方向相反,那么他们的dot product就会是-1。所有如果我们dotProduct这两个向量且结果为-1,那么我们就需要绕Y轴旋转180度,否则使用旋转。为什么要加1.0f并坚持它是否小于0.0001f呢?不要忘了浮点数舍入误差,永远不要直接比较两个浮点数。最后,注意这两个向量的dot product的范围为[-1,1]。如果还是不太清楚,那么要做图形编程你需要至少知道基本的线性代数学。最少你需要复习一下四元数和旋转基础,并查阅一半关于基本向量和矩阵的书。
现在代码已经完成,编译运行你的程序!
- OGRE中级教程一 Animation, Walking Between Points, and Basic Quaternions
- OGRE中级教程二 RaySceneQueries and Basic Mouse Usage
- OGRE中级教程四 Volume Selection and Basic Manual Objects
- Ogre中级教程
- Ogre 中级教程六
- XSI Vertex Animation and OGRE Facial Animation
- XSI Vertex Animation and OGRE Facial Animation
- XSI Vertex Animation and OGRE Facial Animation
- OGRE中级教程三 Mouse Picking(3D Object Selection) and SceneQuery Masks
- Ogre中级教程(六): 投影贴图
- Ogre中级教程(九): 深入CEGUI
- OGRE中级教程五 Static Geometry
- OGRE中级教程六 Projective Decals
- Ogre中级教程(一): 动画, 两点间移动, 和四元数基础
- The basic difference between Route and Bridge
- OGRE教程(一)
- Calculate distance, bearing and more between Latitude/Longitude points
- Difference between "Distribute Content" and "Update Distribution Points"(SCCM)
- 改变CXF WEBSERVICE 日志输出方式
- android 修改权限无法开机解决方案 (没有删除数据的前提下)
- Android service与thread的选择
- 安装postgis2.0.1出错configure error: could not find gdal
- 第一章:JavaScript基础---(三)转义字符
- OGRE中级教程一 Animation, Walking Between Points, and Basic Quaternions
- OGRE中级教程二 RaySceneQueries and Basic Mouse Usage
- linux下安装cmake
- 关于typedef的用法总结
- windows7资源管理器无响应的解决方案
- 元芳,这个Bug你怎么看
- OGRE中级教程三 Mouse Picking(3D Object Selection) and SceneQuery Masks
- POJ 3694 Tarjan+LCA
- 说说今天的收获吧