OgreODE入门

来源:互联网 发布:hive查询避免数据倾斜 编辑:程序博客网 时间:2024/06/05 06:40

既然用了Ogre,那么一定是要有一个物理引擎的。最后选择了ODE,因为ODE在持续更新,文档稍微要多一些。

但是中文文档基本没有,为了以后能快速阅读,只好自己先翻一下了。

这只是一个介绍性的文档,其中的代码并不能形成一个完整的可执行程序。如果结合着OgreODE的Demo的代码看这篇文章,效果会很好的。

原文:http://www.ogre3d.org/wiki/index.php/First_steps_with_OgreODE

这是一个为OgreODE初学者所写的一个入门教程。因为这里(OGRE wiki)没有OgreODE的详尽的文档,所以写了这个教程,希望能对初学者有所指引和帮助。SimpleScenes是另一个学习的好地方,那里有7个带有实际代码的教程。本教程的所有代码都是从那7个教程里节选的。

一、初始化OgreODE,创建一个最简单的物理世界

在我们开始学习之前,你需要准备好:

1.带有一个sceneManager、一个camera、一些basic light的可工作的Ogre程序

2.OgreODE和ODE头文件

3.一个带有material and texture 的Ogre mesh,比如一个平面或者一条街道之类的(基础世界)

4.一个盒装的带有material and texture 的Ogre mesh(世界中的物体)

如果你学习完了Ogre Tutorials那么你能很轻松地做到这些。

在一个最好是你申明了Ogre::Root的头文件里,包含上OgreODE的头文件,并申明以下变量:

#include "OgreOde/OgreOde_Core.h"OgreOde::World                       *mWorld;OgreOde::Space                       *mSpace;OgreOde::StepHandler                 *mStepper;

OgreOde::World类似Ogre::Root,是OgreODE最顶层的对象。你所添加的每一个类,都会以某种方式添加到这个world中,因此这个世界中的物理定律就可以应用到添加的这个类上。但是要小心了,现在版本的OgreODE允许在一个程序中存在多个world。不过这种情况,只有在你确实需要复杂的"Prey-style"的重力效果时或做一些进阶性的优化时,才可能出现。

OgreOde::Space(碰撞空间)类似于一个所有对象(集合体更加特殊)的集合。这些对象可以与自己所在的space以及其它的space里的对象相碰撞,也可以不和任何对象发生碰撞。在大多数情况下,你将会创建一个有等级的碰撞空间——最重要节点的在顶部,很多次要的子节点附属在其下面。

在ODE里面有三种类型的碰撞空间——碰撞空间(Collision Space)、简单空间(Simple Space)和象限四分树空间(Quadtree Space)。碰撞空间和简单空间的差别很小(举个例子,设想碰撞空间是“根”空间,而简单空间是类似人物的手臂一样的“子”空间),而象限四分树空间是特别为大型项目的优化而设计的。所以如果你的场景有大于1000平方米的时候,象限四分树能提高10-20%的性能。(问题是,因为一些bug,象限四分树在OgreOde中还没有得到完好地实现,但这些bug是能被胸怀大志的开发者所修正的。)

OgreOde::StepHandler用于处理world中的时间,你将会使用它来更新事件(也就是说,stephandler时刻(比如每一帧)都在运行着,并且决定着哪一个物体运动到哪里以及与什么发生碰撞)。

二、改写你的.cpp文件

现在找到头文件所对应的cpp文件,让我们来创建一个华丽的新世界。

mWorld = new OgreOde::World(mSceneMgr);mWorld->setGravity(Ogre::Vector3(0,-9.80665,0));mWorld->setCFM(10e-5);mWorld->setERP(0.8);mWorld->setAutoSleep(true);mWorld->setAutoSleepAverageSamplesCount(10);mWorld->setContactCorrectionVelocity(1.0);mSpace = mWorld->getDefaultSpace();

正如你所看到的,world注册到了场景管理器(scene manager),同时设定了重力加速度为9.81。这里请注意两个事情:重力加速度设为了“负”,也就是说对象是“下落”而不是“上浮”;关于世界单位——如果你使用的是“1 ogre 单位 = 1 米”那么重力加速度应设为-9.80665,如果你使用的是“1 ogre 单位 = 1 厘米”(也就是说缩小了100倍)那么重力加速度就应该设为-980.665(相应扩大了100倍)。

后面的两行(setCFM 和 setERP)的设定,影响了模拟现实中的的关节、弹力和摩擦等方面。这里不详细讨论这两个函数,就像代码一样写就可以了。

setAutoSleep设定了world启用它的自动优化(即如果一个对象不再移动,它就会停止重复移动)。

setAutoSleepAverageSamplesCount,用于修正AutoSleep。最好就是设其参数为10,我们将在后面来讨论这个。

setContactCorrectionVelocity,一个很重要的设定。如果不设置它的话,对象间可能会相互穿透。

下一步,添加如下代码:

const Ogre::Real _time_step = 0.5;   const Ogre::Real time_scale = Ogre::Real(1.7);   const Ogre::Real max_frame_time = Ogre::Real(1.0 / 4);   mStepper = new OgreOde::StepHandler(mWorld,                                   OgreOde::StepHandler::QuickStep,                                  _time_step,                                   max_frame_time,                                   time_scale);

最后一步是设定Stepper。你可以在StepHandler::QuickStep, StepHandler::BasicStep 和 StepHandler::FastStep中选择一种,但这里不做详细说明。你也可以在其它的不同类型的StepHandler中选择,但是这也是会在后面提到(尽管这个很重要)。

现在,我们有了一个带有重力的世界,但在这个世界里面什么东西都没有。让我们来改写它:

三、用一个盒子和一个平面来测试我们的重力系统

三、用一个箱子和一个平面来测试我们的重力系统

让我们在世界中添加一个平面和一个箱子(Crate)的实体/节点/主体,我们可以让这个箱子在我们设定的重力系统中进行自由落体运动。

在头文件中加入以下变量:

OgreOde::InfinitePlaneGeometry *mGround;       OgreOde::Body                  *mBody;   OgreOde::Geometry              *mGeom;   OgreOde::BoxMass               mMass;   Ogre::SceneNode                *mNode;   Ogre::Entity                   *mEntity;

你应该已经知道最后两行的意思了。这些变量的第一个将会是ground上的平面,后面的三个变量是关于箱子的。

回到cpp文件,为创建平面添加如下代码:

mGround = new OgreOde::InfinitePlaneGeometry(                               Plane(Ogre::Vector3(0,1,0),0),                                mWorld, mWorld->getDefaultSpace());   // Use a load of meshes to represent the floor   int i = 0;   StaticGeometry* s;   s = mSceneMgr->createStaticGeometry("StaticFloor");   s->setRegionDimensions(Ogre::Vector3(160.0, 100.0, 160.0));   // Set the region origin so the center is at 0 world   s->setOrigin(Ogre::Vector3::ZERO);   for (Real z = -80.0;z <= 80.0;z += 20.0)   {   for (Real x = -80.0;x <= 80.0;x += 20.0)   {      String name = String("Ground") + StringConverter::toString(i++);      Entity* entity = mSceneMgr->createEntity(name, "plane.mesh");      entity->setQueryFlags (1<<4);      entity->setUserObject(mGround);      entity->setCastShadows(false);      s->addEntity(entity, Ogre::Vector3(x,0,z));   }   }   s->build();

这里创建的一个位于x-z面的平面。现在来创建箱子,首先我们需要常规的Ogre/Entity/Node:

mEntity = mSceneMgr->createEntity("crate","crateCube.mesh"); mEntity->setQueryFlags (1<<2); mNode = mSceneMgr->getRootSceneNode()->createChildSceneNode("crate"); mNode->attachObject(mEntity); mEntity->setNormaliseNormals(true);//这句可能因为版本的原因运行不了,可以注释掉以后试试看 mEntity->setCastShadows(true);

然后创建箱子的body并将其“注册”到world和场景节点(scene node):

mBody = new OgreOde::Body(mWorld); mNode->attachObject(mBody);

然后我们设定箱子的体积和质量。因为这是一个盒装的对象,所以我们设定OgreOde::BoxGeometry。其它的比如Sphere或者TriangleMesh在OgreODE也同样有效。

Vector3 size(10.0,10.0,10.0);OgreOde::BoxMass mMass(0.5,size);mMass.setDensity(5.0,size);mGeom = (OgreOde::Geometry*)new OgreOde::BoxGeometry(                                            size, mWorld, mSpace);mNode->setScale(size.x * 0.1,size.y * 0.1,size.z * 0.1);mBody->setMass(mMass);mGeom->setBody(mBody);mEntity->setUserObject(mGeom);

最后我们设定箱子的方向和位置。把它放置到摄像机(camera)前,方便看到它自由落体。

mBody->setOrientation(Quaternion(Radian(5.0),Ogre::Vector3(0,0,0)));mBody->setPosition(Vector3(0,120,-20));

现在就有了一个悬在空中的箱子了。我们需要更新world的time steps。添加如下代码到主要的循环或gamestate::update 或你更新当前帧的地方:

Ogre::Real time = 0.1;    if (mStepper->step(time))    {        mWorld->synchronise();    }

如果你的代码里有一个类似"TimeSinceLastFrame"的值,设定"time"为这个值。现在就可以编译了,尝试去实现它!

如果你只看到一毫秒的急速运动的棕色的点,尝试将重力加速度除以100或1000,使用0.00981代替9.81。这个箱子应该会在这一点穿过平面,因为我们根本没有处理碰撞。关于碰撞的处理你可以在这里找到OgreOde Collision Handling。

注:转载源地址
原创粉丝点击