First steps with OgreODE        
Image

These a guide for new users to OgreODE. There is not much documentation for OgreODE, so hopefully this can help get new users up and running with their own projects. Another good place to look is in SimpleScenes, which are seven tutorials where the you can find most of this code in a real project. Everything written here was pulled from those pieces of code.

Initialize OgreODE, create a World with minimal Physics

What you need:
A working Ogre application with a sceneManager, a camera, some basic light.
OgreODE and ODE header files
An Ogre mesh file with material and texture for a plane, a street or something like that.
An Ogre mesh file with material and texture for a crate or a box-like object.

You should have these if you followed the Ogre Tutorials.

In a header file, probably one where you declared Ogre::Root, include the following OgreOde header and add these variables:

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

The world is like the root in Ogre, it is OgreODE's topmost object. Every Object you add will somehow be added to that world, so that the world's rules (physics), can be applied to it. But beware, it is now possible to have more than one world in your application. However this is only necessary if you are making complicated "Prey-style" gravity effects, or doing some aggressive optimizations.

The space (or collision space) is like a collection of all your objects (geometries to be more specific). Objects can collide within their own space, with objects from other spaces, or not collide with anything at all. Most likely you would have a hierarchy of collision spaces - the central on top, and lots of children attached.

There are three types of collision spaces in Ode - Collision Space, Simple Space and Quadtree Space. The differences between the first two are very minor (as an example think of Collision space as your "root" space, and simple space as a child space for something like character's limbs), but Quadtree Space is intended for optimizations of large levels. So, if you have scenes of 1 sq. km. and above, it an give you 10-20% boost. (the trouble is, it is not yet properly implemented in OgreOde due to some bugs that an aspiring programmer could fix).

The StepHandler handles the time in your world, you will use it to update events (i.e. it runs every now and then (e.g. one per frame) and determines which body moves where and what collides with what). We'll do that later in Chapter 2.

Changing your .cpp file

Now take the .cpp file to the header, let's create our brave new world:

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();

As you can see, the world is registered at your scene manager and we set earth's gravity of about 9,81. Please note two things: gravity is with a "minus", that is objects are "falling" not "floating", and the units - if you are using 1 Ogre unit = 1 meter, than the gravity is -9.80665, BUT if your units are 1 Ogre unit = 1 cm (i.e. 100x smaller), your gravity becomes -980.665 (i.e. 100x bigger).

Next two lines (setCFM and setERP) affect such aspects of your simulation as joints, springs, friction. They aren't discussed in this chapter, and will be fine as is.

setAutoSleep tells our world to turn on its auto optimization (i.e. if an object is not moving any more, it will stop iterating it).

setAutoSleepAverageSamplesCount - is used to tweak the AutoSleep. Best left at 10, we will discuss this later.

setContactCorrectionVelocity - a very important line. Without it objects may just pass through each other.

The last line assigns your variable mSpace to the default collision space, which comes with any new world.

Next, add the following:

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);

The final step is the stepper. You can choose between StepHandler::QuickStep, StepHandler::BasicStep and StepHandler::FastStep here, but they aren't going to be elaborated upon here. Also you can choose between different types of StepHandler, but later about that. (it is quite important though).

Now at this point we have a world with gravity, but nothing in it. Let's change that:

Testing our gravity with a box and a plane

Let's add a plane and an entity/node/body for a crate, that we can make fall down with our new implemented gravity. In the header file, add the following vars:

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

You should already know the last two of those, the one at the top will be our plane on the ground, the other three will be about the crate. Go back to the .cpp file and add the following for the plane:

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();

This creates a plane in X and Z dimensions. Now for the crate, we first need the usual Ogre/Entity/Node stuff for our new object:

mEntity = mSceneMgr->createEntity("crate","crateCube.mesh");
    mEntity->setQueryFlags (1<<2);
    mNode = mSceneMgr->getRootSceneNode()->createChildSceneNode("crate");
    mNode->attachObject(mEntity);
    mEntity->setNormaliseNormals(true);
    mEntity->setCastShadows(true);

Now we create a body for our crate and "register" it in our world and the scene node, where the entity already has its place:

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

After that, we set size and mass of the box. Because it is a box-like object, we use the OgreOde::BoxGeometry. Others like Sphere or TriangleMesh are also available in 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, mWorld->getDefaultSpace());
    mNode->setScale(size.x,size.y,size.z);
    mBody->setMass(mMass);
    mGeom->setBody(mBody);
    mEntity->setUserObject(mGeom);

Finally we set the orientation and position of the crate. Put it in front of / above your camera, so that you can see it falling down.

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

Now you have a crate hanging in the air. We need to update your world's time steps. Add the following code to your main loop or your gamestate::update or wherever your program increments the current frame:

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

If you have a value like "TimeSinceLastFrame", set "time" to be this value. And then go, try it out!

If you only see a rushing brown point for a millisecond, try dividing the gravitation by 100 or 1000, use 0.00981 instead of 9.81.
The crate should go through your plane at this point, for we haven't implemented collision handling at all. That can be found at OgreOde Collision Handling

Here is a complete code using the ExampleFramework for this tutorial:

/** TutorialApplication.cpp */

/** Include example application headerfile */
#include "ExampleApplication.h"
//#include "OgreOde\OgreOde_Core.h"
#include "OgreOde_Core.h"

class TutorialFrameListener : public ExampleFrameListener
{
protected:
  OgreOde::World* mWorld;
  OgreOde::StepHandler* mStepper;

public:
    TutorialFrameListener(RenderWindow* win, Camera* cam, OgreOde::World* _world,
OgreOde::StepHandler* _stepper)
        : ExampleFrameListener(win, cam), mWorld(_world), mStepper(_stepper)
    {
    }
   //bool frameStarted(const FrameEvent& evt)
   bool frameEnded(const FrameEvent& evt)
   {
      Real time = evt.timeSinceLastFrame;
      if ( mStepper->step(time) )
            mWorld->synchronise();
      return ExampleFrameListener::frameEnded(evt);
      //return ExampleFrameListener::frameStarted(evt);
   }
};

/** Class TutorialApplication */
class TutorialApplication : public ExampleApplication
{
protected:

public:
    TutorialApplication(void)
    {
    }

    ~TutorialApplication(void)
    {
    }

protected:
    void createScene(void)
    {

        /** Create ambient light */
        mSceneMgr->setAmbientLight(ColourValue(1, 1, 1));

        /** Create point light, set its type and position */
        Light *light = mSceneMgr->createLight("Light1");
        light->setType(Light::LT_POINT);
        light->setPosition(Vector3(0, 150, 250));

        /** set the diffuse and specular colour */
        light->setDiffuseColour(1.0, 1.0, 1.0);
        light->setSpecularColour(1.0, 1.0, 1.0);

        /** Add physics to Ogre */
        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();

        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);

        mGround = new OgreOde::InfinitePlaneGeometry(Plane(Ogre::Vector3(0,1,0),0), mWorld,
mWorld->getDefaultSpace());
        
        //load meshed
        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();

        mEntity = mSceneMgr->createEntity("crate", "crate.mesh");
        mEntity->setQueryFlags(1<<2);
        mNode = mSceneMgr->getRootSceneNode()->createChildSceneNode("crate");
        mNode->attachObject(mEntity);
        //mEntity->setNormaliseNormals(true);
        mEntity->setCastShadows(true);

        //create a body for our crate
        //and "register" it in our world and the scene node
        mBody = new OgreOde::Body(mWorld);
        mNode->attachObject(mBody);

        //set size and mass of the box
        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);

        //set the orientation and position of the crate
        mBody->setOrientation(Quaternion(Radian(5.0), Ogre::Vector3(0,0,0)));
        mBody->setPosition(Vector3(0,120,-20));
    }

    //create framelistener
    void createFrameListener(void)
    {
        mFrameListener = new TutorialFrameListener(mWindow, mCamera, mWorld, mStepper);
        mRoot->addFrameListener(mFrameListener);
    }

private:
    OgreOde::World            *mWorld;
    OgreOde::Space            *mSpace;
    OgreOde::StepHandler    *mStepper;

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

#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
#define WIN32_LEAN_AND_MEAN
#include "windows.h"

INT WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInstance, LPSTR lpCmdLine, INT nShowCmd)
#else
int main(int argc, char **argv)
#endif
{
    /** Create application object */
    TutorialApplication app;

    try
    {
        app.go();
    }
    catch(Exception e)
    {
    #if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
        MessageBox(NULL, (LPWSTR)e.getFullDescription().c_str(),
L"An Exception has occured.", MB_OK | MB_ICONERROR | MB_TASKMODAL);
    #else
        fprintf(stderr, "An exception has occured: %s\n", e.getFullDescription().c_str());
    #endif
    }

    return 0;
}


Call to undefined function mb_split()Call to undefined function mb_split()Call to undefined function mb_split()Call to undefined function mb_split()