Demo for 'Working With a Physics Engine - Ogre Newton'

This lab is going to take a look at how to use an open source physics engine in your own virtual reality simulations. For the engine we are going to use a project called Newton (which interfaces with Ogre through the wrapper classes OgreNewton).

To start, download the template project here. This template is based off of "Demo01_TheBasics" which comes with the OgreNewton wrapper classes. Extract, compile, then run the project to get an idea of the basics of the virtual world. You can use the arrow keys to move around the world (start by backing up to see the whole floor) and you can pan/tilt the camera with the mouse.

Next, we are going to make use of an event listener. The basic structure for the listener is already coded into the template project. We are going to use it to make a ball drop down from above the floor each time the spacebar is pressed. Insert the following code at line 55 of OgreNewtonFrameListner.cpp.

Entity* ent;
SceneNode* node;
Ogre::String name;

name = "Body "+Ogre::StringConverter::toString( count++ );

// Import the Sphere Mesh
ent = mSceneMgr->createEntity( name, "Lab2Sphere.mesh" );
node = mSceneMgr->getRootSceneNode()->createChildSceneNode( name );
			
//Still have to set scale even though the sphere was scaled to size 2 in Blender
node->setScale(Ogre::Vector3(2,2,2));
node->attachObject( ent );

// Texture the mesh with a dirt image
ent->setMaterialName( "Simple/dirt01" );

This will create a sphere object above the floor when you hit the spacebar. It will be textured with an image of dirt. Try running the program and see what happens when you hit the spacebar.

If done correctly you should notice that the ball gets made but just hovers above the floor. Why does this happen? Although the mesh was added into the environment it does not have a physical extent, mass or inertia associated with it inside the physics engine. In order to fix this, place the following code above the comment "End create ball object to drop on slanted floor".

// again, make the collision shape. (parameters to Ellipsoid are a world and dimensions of ellipsoid in all three axis)
OgreNewt::Collision* col = new OgreNewt::CollisionPrimitives::Ellipsoid(m_World, Ogre::Vector3(2,2,2));
			
// then make the rigid body.
OgreNewt::Body* body = new OgreNewt::Body( m_World, col );

//no longer need the collision shape object
delete col;

// something new: moment of inertia for the body.  this describes how much the body "resists"
// rotation on each axis.  realistic values here make for MUCH more realistic results.  luckily
// OgreNewt has some helper functions for calculating these values for many primitive shapes!
Ogre::Vector3 inertia = OgreNewt::MomentOfInertia::CalcSphereSolid( 10.0, 2.0 );
body->setMassMatrix( 10.0, inertia );

// attach to the scene node.
body->attachToNode( node );

// this is a standard callback that simply add a gravitational force (-9.8*mass) to the body.
body->setStandardForceCallback();

// set the initial orientation and velocity!
body->setPositionOrientation( Ogre::Vector3(0.0,10.0,0.0), Ogre::Quaternion::IDENTITY );
body->setVelocity(Ogre::Vector3(0.0, 0.0,0.0));

You can read through the comments to get a good idea of what is going on here. Points to notice about this code is that the collision boundary for the mesh is made as a sphere with radius 2 (or an ellipsoid with the lengths along all three axes 2), it is given an inertia based on a sphere with mass of 10 and radius of 2 and that standard forces of gravity are applied to the object.

Now we are going to add a heavy object to the path of the rolling balls to see how simple collisions can take place. Copy the following code at line 55 of OgreNewtonApplication.cpp.

// Add a heavy box to the path of the moving ball
Entity* ent2;
Ogre::Vector3 boxsize(2.0,2.0,2.0);
Ogre::String name;

name = "Immovable Block";

ent2 = mSceneMgr->createEntity( name, "box.mesh" );
node = mSceneMgr->getRootSceneNode()->createChildSceneNode( name );
			
node->setScale(boxsize);
node->attachObject( ent2 );

ent2->setMaterialName( "Simple/dirt01" );

// again, make the collision shape.  This time it is of type box instead of sphere
OgreNewt::Collision* col3 = new OgreNewt::CollisionPrimitives::Box(m_World, boxsize);
			
// then make the rigid body.
OgreNewt::Body* body = new OgreNewt::Body( m_World, col3 );

//no longer need the collision shape object
delete col3;

// This time set the inertia of the body based on the primitive type box
Ogre::Vector3 inertia = OgreNewt::MomentOfInertia::CalcBoxSolid( 2000.0, boxsize );
body->setMassMatrix( 2000.0, inertia );

// attach to the scene node.
body->attachToNode( node );

// this is a standard callback that simply add a gravitational force (-9.8*mass) to the body.
body->setStandardForceCallback();

// set the initial orientation and velocity!
body->setPositionOrientation( Ogre::Vector3(0.0,-25.0,40.0), Ogre::Quaternion( Ogre::Degree(45.0f), Ogre::Vector3::UNIT_Y) );
body->setVelocity(Ogre::Vector3(0.0, 0.0,0.0));

If you run the code now you should notice that a box will drop down onto the floor when you first run the program. This box has been rotated so that the corner of the box is what comes in contact with the ball (this is located in the quaternion on line 90). When the ball comes in contact with the box it will just bounce away (since the mass of the box is 2000 compared to the mass of the ball being 10). Next change the mass of the box on lines 80 and 81 so that it is less than the ball (say 5) and see what happens.

If you want to see a final copy of the code you can go here.