Using Ogre with the Newton Game Dynamics physics SDK
This tutorial is intended to explain how to setup a simple project using Ogre version 1.0.0, to work with the Newton Game Dynamics physics SDK, currently version 1.31.
Requirements:
The first thing we need to do, is get OgreNewt compiled, and up and running. I will be assuming you have a directory tree setup like below:
directory structure:
<some_dir>/OGRE/ogrenew <- ogre install dir <some_dir>/OGRE/ogreaddons/OgreNewt/ <- OgreNewt install dir. <some_dir>/NewtonSDK <- Newton SDK install dir <some_dir>/tinyxml <- Tinyxml library (used only for demo08, not in OgreNewt itself)
If your directory tree is different, you will need to modify the OgreNewt project files to get it to compile properly.
Okay, so open up VC++, and load the "OgreNewt" solution. You should see 9 total projects:
Assuming your directory structure is set up like I have shown above, you should be able to compile the solution right away with no problems. Do so now. Note that you will have to have tinyxml compiled properly (use the STL version) to get demo08 to compile properly.
Now you can navigate to the "OgreNewt/Bin/Debug" or "OgreNewt/Bin/Release" directories, and there should be the executables for the demos there. Copy over the standard Ogre .dll files, as well as the newton.dll file from your Newton SDK directory, and try running the demos.
DEMO CONTROLS:
Okay, if you've made it this far, you're ready to try and make your own simple OgreNewt application. I'll be using the standard ExampleApplication and ExampleFrameListener classes used in most Ogre tutorials. if you've never made an Ogre application with these classes, you might want to read through a few general Ogre tutorials to get up to speed first.
Okay... so first let's set up our Application class. Create a new project and add a new header file called "OgreNewtApplication.h". Open it up and set up the basic class outline like below:
OgreNewtApplication.h
#ifndef _OGRENEWTAPPLICATION_ #define _OGRENEWTAPPLICATION_ #include "ExampleApplication.h" class OgreNewtApplication : public ExampleApplication { public: OgreNewtApplication(void); ~OgreNewtApplication(void); void createScene(); void createFrameListener(void); };
This should look familiar... it's just a standard inherited ExampleApplication class. First we need to set up the various include directories for our project. in the C/C++ section of the project settings, make sure the following directories are in the "include directories" list:
include directories
ogrenew/ogremain/include ogrenew/samples/common/include ogreaddons/OgreNewt/OgreNewt_Main/inc ogreaddons/OgreNewt/demos/Include NewtonSDK/sdk
library directories
ogrenew/ogremain/lib/debug <or release> ogreaddons/OgreNewt_Main/lib/debug <or release> NewtonSDK/dll/
Now we need to add the various pieces necessary to make a Newton application. first, let's include the OgreNewt main header:
#include <OgreNewt.h>
okay, simple enough. now add the following line to a "private:" section of the class:
OgreNewt::World* mWorld;
if you have autocomplete set up in your IDE, you should see a bunch of classes and namespaces pop up when you type "OgreNewt::". Let's now take a minute and talk about the Newton SDK, and how it works.
This section is a quick introduction to the Newton SDK, and how it works. it is by no means a substitute to the SDK documentation, which is included with the SDK. My OgreNewt library is pretty much a 1:1 conversion of the Newton functions into a class-based environment, so most of the function descriptions in the Newton documentation apply directly to OgreNewt.
Anyway, Newton has a few basic elements used to describe the physics world... they are:
Then you build what is called a "MaterialPair". A material pair is a description of what happens when 2 materials collide with each other. For example, you might create a material pair for collisions between iron and steel. Then you will know any time an "iron" and "steel" object come in contact. You can then create sparks, or sound effects, etc.
Okay, those are the big, basic objects that are used in Newton. Note that there are also special objects for creating ragdolls and vehicles as well. See the Newton documentation for more information on them. At this time, OgreNewt has no special implementation for these objects.
okay, so back to our OgreNewtApplication class. as you can see, we've now added a pointer to an OgreNewt::World, which will be the main World in which we place our rigid bodies. now create a new OgreNewtApplication.cpp source file, and add the basic elements necessary. you should end up with something looking like this:
OgreNewtApplication.cpp
#include "./ogrenewtapplication.h" OgreNewtApplication::OgreNewtApplication(void) { } OgreNewtApplication::~OgreNewtApplication(void) { } void OgreNewtApplication::createScene() { } void OgreNewtApplication::createFrameListener() { }
now, let's create the Newton world in the constructor for the application class. add this line:
mWorld = new OgreNewt::World();
this line creates the OgreNewt::World object. you need to create this object before creating any other Newton objects, as they will all require you pass a pointer to a World object. you might also want to add a line to delete the world in the destructor:
delete mWorld;
Now there's one more thing we want to add to the Application class while we're here: a frame listener. in most demos, they have you create a FrameListener class inherited from ExampleFrameListener. We'll do the same in this demo, but also add a special FrameListener just for updating and debugging the Newton world. First, setup the standard ExampleFrameListener class, in your createFrameListener() function like so:
OgreNewtApplication.cpp
void OgreNewtApplication::createFrameListener() { mFrameListener = new ExampleFrameListener( mWindow, mCamera ); mRoot->addFrameListener( mFrameListener ); }
now we'll add a frame listener to update the physics, and provide physics debugging features. Luckily, I've included such a frame listener in the OgreNewt library, called "BasicFrameListener". add a member pointer variable in the Application class like this:
OgreNewt::BasicFrameListener* mOgreNewtListener;
and then, add these lines to the createFrameListener() function:
mOgreNewtListener = new OgreNewt::BasicFrameListener( mWindow, mCamera, mSceneMgr, mWorld, 120 ); mRoot->addFrameListener( mOgreNewtListener );
the OgreNewt::BasicFrameListener is a simple frame listener that updates the Newton world each frame, with a simple time-slicing method, which means you can control the rate at which the physics update. the last paramater you pass to the constructor is the desired update fps for the physics system. by adding this FrameListener to your application, the physics will automatically update. Also, the frame listener has a simple debug system implemented, which I'll discuss later. note that for more complex applications, it would probably be better to implement your own frame listener for the physics, which gives more control.
Okay, so everything is all set up. now let's build a simple Newton scene. For this demo, we're going to make a very simple scene, which creates a basic floow (out of a box), and drops several primitive objects onto the ground.
so let's get started. first let's make a simple ground. first we'll make a standard visual object, like any other in Ogre, and then add the physics Rigid Body "behind it". Now would be a good time to download the MESH PACK for this tutorial, and unzip the .mesh files somewhere your Ogre program will find them. okay, first add the mesh as usual:
Ogre::Vector3 size(10.0,1.0,10.0); Ogre::SceneNode* node = mSceneMgr->getRootSceneNode()->createChildSceneNode(); Ogre::Entity* ent = mSceneMgr->createEntity( "floorobj", "box.mesh" ); node->attachObject( ent ); node->setScale( size );
okay, now let's make the Rigid Body that represents this object. it's actually pretty simple: first we make a collision object that represents the shape:
OgreNewt::Collision* col = new OgreNewt::CollisionPrimitives::Box( mWorld, size );
then, we make a Rigid Body object from this collision object.
OgreNewt::Body* floorbody = new OgreNewt::Body( mWorld, col );
notice that we also must pass a pointer to our Newton World object as well when making these objects. now our body is created, finally we need to "connect" the Rigid Body, to the visual 3D object attached to the SceneNode. what does this mean? well, Newton has a really interesting system of callbacks, which means that if you setup your scene properly, Newton will automatically update the position and rotation of objects for you! for example, let's say you have 50 different objects in a scene. when you ask Newton to update the physics, it calculates the new position and rotation of all of the objects in the scene, based on physical laws. with many physics engines, you then need to perform some kind of loop, which goes through all of the physics bodies in the scene, gets their orientation, and applies this to their "visual" object, to match them up. However Newton has a callback system built in, which does this for you. this is ultimately very cool because it's automated, and also more efficient, because Newton only calls the callback for bodies that are moving, bodies that have not moved since the last update are properly ignored. Anyway, the way this is implemented in OgreNewt is through the "attachToNode()" member function of the OgreNewt::Body class. basically this function says "this SceneNode has some meshes attached to it, which are a visual representation of this Rigid Body. when this Rigid Body moves, please also move this SceneNode". it's as simple as that. here's how it's done:
floorbody->attachToNode( node );
finally, we want to set the initial position of our floor. let's place it in the center of the world, down 5 units on the Y axis, like so:
floorbody->setPositionOrientation( Ogre::Vector3(0,-5,0), Ogre::Quaternion::IDENTITY ); delete col;
this member function manually sets the position and orientation of a RigidBody, as well as the SceneNode attached to it (if any). You'll notice we also delete the Collision object, as we don't need it anymore.
now our floor is complete. next, let's make a few other primitive shapes to fall onto the floor! First let's make a simple cylinder-shaped body. The first few steps are exactly like above:
// CYLINDER BODY // cylinder with a radius of 0.5, height of 1.3 size = Ogre::Vector3( 1.3, 0.5, 0.5 ); node = mSceneMgr->getRootSceneNode()->createChildSceneNode(); ent = mSceneMgr->createEntity("cylinder_body", "cylinder.mesh" ); node->attachObject( ent ); node->setScale( size ); // rigid body. col = new OgreNewt::CollisionPrimitives::Cylinder( mWorld, 0.5, 1.3 ); OgreNewt::Body* bod = new OgreNewt::Body( mWorld, col ); bod->attachToNode( node ); // initial position bod->setPositionOrientation( Ogre::Vector3(-2,3,2), Ogre::Quaternion::IDENTITY ); delete col;
okay, all of that should look familiar, it's very similar to the Floor code. however, we want this body to be "dynamic", in the sense that it should be affected by gravity, and fall down, hitting other objects, and generally impressing us. To do so, we need to define a few other properties of the Rigid Body, namely Mass and Moment of Inertia. Mass is simple, you can use any units you see fit, although personally I recommend using Kilograms as a standard. Inertia might not be so intuitive, as it's a value that represents an objects resistance to rotation around a specific axis. many factors can affect this value, and getting truly accurate values is beyond me. however, there are some handy formulas available on the internet for calculating the moment of inertia for certain primitive shapes. what's even more handy, is that I've included these functions right inside OgreNewt. there just happens to be a function for cylinders, so we'll use it to calculate the inertia values for us, based on the mass and size of the object. here's how we set it up:
Ogre::Real mass = 10.0; Ogre::Vector3 inertia = OgreNewt::MomentOfInertia::CalcCylinderSolid( mass, 0.5, 1.3 ); bod->setMassMatrix( mass, inertia );
okay. now the object has mass! however if you were to compile and run your program right now (go ahead and try if you want!), the body would not fall to the ground. this is because we haven't applied any forces to the object, to set it in motion. in Physics simulations, the most common force is gravity. so how do we add gravity with Newton?
Well, in a similar fashion to the callback that positions and orients visual objects for you, Newton also provides a callback for applying forces to a body. this way, you can create different general callbacks, which apply some kind of force to a body, and by simply setting the callback for the body, you can adjust the forces that act upon it. I have yet to fully implement the details of adding custom callbacks into OgreNewt, but it's not too difficult to implement if you read the documentation for Newton, and have a look at the OgreNewt source code. however I have included a "basicForceTorqueCallback" right into the OgreNewt::Body class, which applies a constant gravitational (-Y) force of 9.8units/sec^2 to the body. to set this callback, simply do the following:
bod->setStandardForceCallback();
and voila! your Rigid Body now has gravity. okay, that's the basic setup for making a rigid body in this tutorial. let's now add a few more bodies to the scene, following the same steps we have seen above:
// CONE BODY // cone with a radius of 0.8, height of 1.0 size = Ogre::Vector3( 1.0, 0.8, 0.8 ); node = mSceneMgr->getRootSceneNode()->createChildSceneNode(); ent = mSceneMgr->createEntity("cone_body", "cone.mesh" ); node->attachObject( ent ); node->setScale( size ); // rigid body. col = new OgreNewt::CollisionPrimitives::Cone( mWorld, 0.8, 1.0 ); bod = new OgreNewt::Body( mWorld, col ); bod->attachToNode( node ); // initial position bod->setPositionOrientation( Ogre::Vector3(2,3,2), Ogre::Quaternion::IDENTITY ); delete col; mass = 10.0; inertia = OgreNewt::MomentOfInertia::CalcCylinderSolid( mass, 0.5, 1.3 ); bod->setMassMatrix( mass, inertia ); bod->setStandardForceCallback(); // BOX BODY // standard 1x1x1 cube. size = Ogre::Vector3( 1, 1, 1 ); node = mSceneMgr->getRootSceneNode()->createChildSceneNode(); ent = mSceneMgr->createEntity("box_body", "box.mesh" ); node->attachObject( ent ); node->setScale( size ); // rigid body. col = new OgreNewt::CollisionPrimitives::Box( mWorld, size ); bod = new OgreNewt::Body( mWorld, col ); bod->attachToNode( node ); // initial position bod->setPositionOrientation( Ogre::Vector3(0,3,-2),Ogre::Quaternion::IDENTITY ); delete col; mass = 10.0; inertia = OgreNewt::MomentOfInertia::CalcBoxSolid( mass, size ); bod->setMassMatrix( mass, inertia ); bod->setStandardForceCallback();
Okay, that's it! don't forget to also add a light to your scene, and possibly set a good starting point for the camera. Now compile and run your project, you should have 3 objects that fall and bounce on the ground we made.
This should be enough to get you started with Ogre and Newton, using my OgreNewt library... although I think the main ideas in the tutorial would work for your own implementation of Newton in Ogre as well. Good luck, and good physics!
Edit by Persoontje: If you get an error like this:
Unhandled exception at 0x00423d76 in newtontest.exe: 0xC0000005: Access violation reading location 0xfeef003e In the line: m_debugnode->detachAllObjects();
You need to deinit the debugger. To do this, add
OgreNewt::Debugger::getSingleton().deInit();
to the destructor of your application class.