Image
Note: The implementation below uses an OgreODE RayGeometry and a CapsuleGeometry to build a ray model controller for game characters.
The end result looks like a corn dog or a lolly pop XD

I've written a short demo application, and it tested fine on my machine. If for some reason it doesn't work, just re-use the parts of code that work best for you.

Image

CharacterController.h

#ifndef _CHARACTER_CONTROLLER_
#define _CHARACTER_CONTROLLER_

#include "OgreOde_Core.h"
#include "ExampleFrameListener.h"

// Declare a subclass of the ExampleFrameListener class
class MyListener : 
	public ExampleFrameListener
	, public OgreOde::CollisionListener
	, public OgreOde::StepListener
	, public OgreOde::TriangleMeshRayListener
{ 
public:
	MyListener( Ogre::RenderWindow* win
                , Ogre::Camera* cam
		, Ogre::SceneManager* sMgr
                , Ogre::Root* mRoot );
	~MyListener( void );

	bool frameStarted( const Ogre::FrameEvent& evt ); 
	bool frameEnded( const FrameEvent& evt );

	// OgreOde::CollisionListener function
	bool collision( OgreOde::Contact* contact );

	// OgreOde::StepListener function
	bool preStep( Ogre::Real time ) 
	{ 
		//addForcesAndTorques();
		return true; 
	}

	// reposition OgreOde Ray(s)
	void simulatePhysics( const FrameEvent &evt );
	// Will get called just before each time step, 
	// since a timestep zeros the force accumulators
	void addForcesAndTorques( void ) {}

	void create_ODE_Terrain( std::string meshFile
               , Ogre::Vector3 position
               , Ogre::Vector3 size );

	void player_Initialise( void );

	void act_walk( bool walk_request = false
               , bool forward_walk = false );
	void act_strafe( bool strafe_request = false
               , bool left_strafe = false );
	void act_jump( bool jump_request = false );

private:
	OgreOde::World		*p_World;
	OgreOde::StepHandler	*p_Stepper;
	Ogre::SceneManager	*p_SceneMgr;
	Ogre::Camera		*p_Camera;

	Ogre::Entity	*p_BaseEntity; //Your Player.mesh
	Ogre::SceneNode	*p_BaseNode;
	Ogre::SceneNode	*p_ModelNode;

	OgreOde::Space		   *p_PhysicsCharSpace;
	OgreOde::Body		   *p_BaseBody;
	OgreOde::Geometry	   *p_GeomBaseBody;
	OgreOde::TransformGeometry *p_GeomBody;

	// Use this for body area specific collisions. 
	/*OgreOde::Geometry		*p_GeomBaseHead; 
	OgreOde::TransformGeometry	*p_GeomHead;
	OgreOde::Body			*p_HeadBody;*/

	OgreOde::RayGeometry		*p_BaseRay;
	OgreOde::TriangleMeshGeometry	  
                              *p_terrainTriMeshGeom;

	Ogre::Real r_WalkStrength, r_WalkSpeed
                              , r_RunSpeedMultiplier;

	Ogre::Real r_JumpHeight, r_Radius;
	OgreOde::Contact	*p_Contact;
	bool	b_onGround, b_isFalling;	
};

#endif


CharacterController.cpp

#include "CharacterController.h"

MyListener::MyListener( Ogre::RenderWindow* win, Ogre::Camera* cam
	, Ogre::SceneManager* sMgr, Ogre::Root* mRoot ) 
	: ExampleFrameListener( win, cam )
{
	p_SceneMgr = sMgr;
	p_Camera = cam;

	// create OgreOde World 
	p_World = new OgreOde::World( p_SceneMgr );
	p_World->setCollisionListener( this );
	p_World->setGravity( Ogre::Vector3( 0
                , /*-9.80665*/ -9.83665, 0 ));
	p_World->setCFM( 10e-5 );
	p_World->setERP( 0.8 );
	p_World->setAutoSleep( true );
	p_World->setAutoSleepSteps( 10 );
	p_World->setAutoSleepAngularThreshold( 0.1 );
	/*p_World->setAutoSleepAngularThreshold(           
                OgreOde::Utility::Infinity );*/
	p_World->setAutoSleepLinearThreshold( 0.1 );
	//p_World->setContactCorrectionVelocity( 1 );
	p_World->setContactCorrectionVelocity( 2 );
	
	// Create something that will step the world, but   
        // don't do it automatically.
	p_Stepper = new OgreOde::StepHandler(
		p_World
		, OgreOde::StepHandler::QuickStep
		, Ogre::Real( 0.01 ) // Step size
		, Ogre::Real( 1.0 / 4 ) // Max interval
		, Ogre::Real( 1.0 )); // Time scale

	p_Stepper->setStepListener( this );

	/*create_ODE_Terrain( "yourTerrainFile.mesh"
                , position, size );*/
	create_ODE_Terrain( "racingcircuit.mesh"
               , Ogre::Vector3::ZERO
               , Ogre::Vector3( 10, 10, 10 )); 

	player_Initialise();

	p_World->setShowDebugGeometries( true );
}

MyListener::~MyListener( void )
{
	// destroy to remove the characters, terrain and 
	// stepper before destroying the OgreOde world
	if( p_terrainTriMeshGeom ) 
            delete p_terrainTriMeshGeom;

	delete p_Stepper;
	p_Stepper = NULL;

	delete p_World;
	p_World = NULL;
}

bool MyListener::frameStarted( const Ogre::FrameEvent& evt )
{
	// quit app
	if( mKeyboard->isKeyDown( OIS::KC_ESCAPE )) 
		return false;

	// basic movement
        if( mKeyboard->isKeyDown( OIS::KC_UP ))
		act_walk( true, true );
	else if( mKeyboard->isKeyDown( OIS::KC_DOWN )) 
		act_walk( true, false );

	if( mKeyboard->isKeyDown( OIS::KC_LEFT ))
		act_strafe( true, true );
	else if( mKeyboard->isKeyDown( OIS::KC_RIGHT ))
		act_strafe( true, false );
	
	if( mKeyboard->isKeyDown( OIS::KC_SPACE ))
		act_jump( true );

	simulatePhysics( evt );

	return true;        
}

bool MyListener::frameEnded( const FrameEvent& evt )
{
	if( !mKeyboard->isKeyDown( OIS::KC_UP ) ||
		!mKeyboard->isKeyDown( OIS::KC_DOWN ))
		act_walk( false );
	else if( !mKeyboard->isKeyDown( OIS::KC_LEFT ) ||
		!mKeyboard->isKeyDown( OIS::KC_RIGHT ))
		act_strafe( false ); 
	
	if( !mKeyboard->isKeyDown( OIS::KC_SPACE ))
		act_jump( false );

	return 
            ExampleFrameListener::frameEnded( evt );        
}

bool MyListener::collision( OgreOde::Contact* contact )
{
	if( contact->getFirstGeometry()->getID() == 
		p_BaseRay->getID() ||
		contact->getSecondGeometry()->getID() == 
		p_BaseRay->getID() )
	{
		/*contact->setCoulombFriction( 
                      OgreOde::Utility::Infinity );*/
		contact->setBouncyness( 0.0 );	
		p_Contact = contact;
	}
	
	return true;
}

void MyListener::simulatePhysics( const FrameEvent &evt )
{
	p_Stepper->step( evt.timeSinceLastFrame );
	p_World->synchronise();

	b_onGround = false;
	bool collideSuccess;
	OgreOde::Contact *tempContact;

	//p_BaseBody->setDamping( 10, 10 );
	//p_BaseBody->setDamping( 0.1, 0.1 );

	// Fire the ray downward
	p_BaseRay->setDefinition( 
		p_BaseNode->getPosition() + 
                         Ogre::Vector3( 0, r_Radius * 2, 0 )
		, Ogre::Vector3::NEGATIVE_UNIT_Y );

	if( p_BaseRay->collide( p_terrainTriMeshGeom, this ))
		collideSuccess = true;
	else
		collideSuccess = false;

	if( collideSuccess == true ) 
	{     
		p_BaseBody->setAngularVelocity( 
                     Ogre::Vector3::ZERO );
		tempContact = p_Contact;

		Ogre::Vector3 position = 
                     p_BaseBody->getPosition();
		p_BaseBody->setPosition( Ogre::Vector3( 
			position.x
			, tempContact->getPosition().y
			, position.z ));

		b_onGround = true;
	} 

	p_BaseBody->setAngularVelocity( 
                         Ogre::Vector3::ZERO );
	p_BaseBody->setOrientation( Ogre::Quaternion( 
		p_BaseBody->getOrientation().xAxis()
		, Ogre::Vector3::UNIT_Y
		, p_BaseBody->getOrientation().zAxis() ));
}

void MyListener::create_ODE_Terrain( std::string meshFile
	, Ogre::Vector3 position, Ogre::Vector3 size )
{
	Ogre::SceneNode* sn = 
           p_SceneMgr->getRootSceneNode()->
               createChildSceneNode( 
		   "TerrainNode", position );
	Ogre::Entity* ent = p_SceneMgr->createEntity( 
		"Terrain", meshFile.c_str() );
	sn->attachObject( ent );
	sn->setScale( size );

	OgreOde::EntityInformer ei( 
                ent, sn->_getFullTransform() );
	p_terrainTriMeshGeom =
		ei.createStaticTriangleMesh( p_World
		       , p_World->getDefaultSpace() );
	p_terrainTriMeshGeom->setRayListener( this );
}

void MyListener::player_Initialise( void )
{
	r_WalkStrength =		1;
	r_RunSpeedMultiplier =	        1.2;
	r_JumpHeight =			10;
	r_WalkSpeed =			15;
	b_onGround =                    false;

	p_PhysicsCharSpace = new OgreOde::SimpleSpace( 
		p_World, p_World->getDefaultSpace() );
	p_PhysicsCharSpace->setInternalCollisions( false );

	p_BaseEntity = p_SceneMgr->createEntity( 
		"Ninja", "ninja.mesh" );

	p_BaseNode = p_SceneMgr->getRootSceneNode()->
		createChildSceneNode( "NinjaNode" );
	p_ModelNode = p_BaseNode->createChildSceneNode( 
		"NinjaModel"
                , Ogre::Vector3( 0, /*-0.2*/ 0, 0 ));
	p_ModelNode->attachObject( p_BaseEntity );

	//p_ModelNode->setScale( 0.1, 0.1, 0.1 );
	p_ModelNode->setScale( 0.05, 0.05, 0.05 );

	Ogre::AxisAlignedBox aab = 
            p_ModelNode->getAttachedObject( 
		"Ninja" )->getBoundingBox();
	Ogre::Vector3 min = aab.getMinimum() * 
                            p_ModelNode->getScale();
	Ogre::Vector3 max = aab.getMaximum() *  
                            p_ModelNode->getScale();
	Ogre::Vector3 size( 
		fabs( max.x - min.x )
		, fabs( max.y - min.y )
		, fabs( max.z - min.z ));
	r_Radius = 
          ( size.x > size.z ) ? size.z / 3.0 : size.x / 3.0;

	p_BaseRay = new OgreOde::RayGeometry( 
		r_Radius * 2
                , p_World
                , p_PhysicsCharSpace );

	p_BaseBody = new OgreOde::Body( p_World );
	p_BaseBody->setMass( OgreOde::CapsuleMass( 
		70 * 2
		, size.x / 2.0 //r_Radius
		, Ogre::Vector3::UNIT_Y
		, size.y - 6 * r_Radius ));
	p_BaseBody->setAutoSleep( false );

	p_GeomBaseBody = new OgreOde::CapsuleGeometry( 
		size.x / 2.0 //r_Radius
		, size.y - 6 * r_Radius
		, p_World );
	p_GeomBaseBody->setPosition( Ogre::Vector3( 
		0
		, size.y - (( size.y - 4 * r_Radius ) / 2 + 
                     2 * r_Radius )
		, 0 ));
	p_GeomBaseBody->setOrientation( 
                Quaternion( Degree( 90 )
		, Ogre::Vector3::UNIT_X ));
	
	p_GeomBody = new OgreOde::TransformGeometry( 
		p_World, p_PhysicsCharSpace );
	p_GeomBody->setEncapsulatedGeometry( 
                                 p_GeomBaseBody );
	p_GeomBody->setBody( p_BaseBody );

	p_BaseNode->attachObject( p_BaseBody );

	// position and attach the camera
	p_Camera->setPosition( 
		p_ModelNode->getPosition() + 
                       Ogre::Vector3( 0, 20, 35 ));
	p_Camera->lookAt( p_ModelNode->getPosition() );
	p_ModelNode->attachObject( p_Camera );
	
	//p_GeomBody->setOffsetPosition( 
                      Ogre::Vector3( 0, 1.8, 0 ));

	// ??? Seems to make no difference in the demo if 
        // commented out.
	// ??? I can't remember if or when this call is    
        // necessary...
	//p_BaseEntity->setUserAny( Ogre::Any( p_GeomBody ));
}

void MyListener::act_walk( 
         bool walk_request, bool forward_walk )
{
	if( walk_request == true )
	{
		if( forward_walk == true )
		{
		   if( b_onGround == true ) 
		   {
		      Ogre::Vector3 walkVect3 = Vector3( 
			0 
			, 0
			, r_WalkSpeed * r_WalkStrength * 
                                    r_RunSpeedMultiplier );
				 
                      p_BaseBody->setLinearVelocity( 
			  p_BaseBody->getOrientation() *
                                             -walkVect3 );
		   }
		}
		else if( forward_walk == false )
		{
		   if( b_onGround == true ) 
		   {
		      Ogre::Vector3 walkVect3 = Vector3( 
			0 
			, 0
			, r_WalkSpeed * r_WalkStrength *
                                   r_RunSpeedMultiplier );
                    
                      p_BaseBody->setLinearVelocity(  
                        p_BaseBody->getOrientation() * 
                                            walkVect3 );
		   }
		}
	}
	else if( walk_request == false ) 
	{
	  if( b_onGround == true )
	  {
	     p_BaseBody->setLinearVelocity( 
		p_BaseBody->getOrientation() *  
                              Ogre::Vector3::ZERO );
	  }
	}
}

void MyListener::act_strafe( bool strafe_request
                               , bool left_strafe )
{
	if( strafe_request == true )
	{
	   if( left_strafe == true )
	   {
	      if( b_onGround == true ) 
	      {
		Ogre::Vector3 strafeVect3 = Vector3( 
		  r_WalkSpeed * r_WalkStrength *  
                              r_RunSpeedMultiplier 
		  , 0
		  , 0 );
				
                p_BaseBody->setLinearVelocity( 
                  p_BaseBody->getOrientation() * 
                     -strafeVect3 );
	      }
	   }
	   else if( left_strafe == false )
	   {
	      if( b_onGround == true ) 
	      {
		Ogre::Vector3 strafeVect3 = Vector3( 
		 r_WalkSpeed * r_WalkStrength * 
                             r_RunSpeedMultiplier  
		, 0
		, 0 );
				
                p_BaseBody->setLinearVelocity( 
                     p_BaseBody->getOrientation() *
                                         strafeVect3 );
	      }
	   }
	}
	else if( strafe_request == false ) 
	{
	   if( b_onGround == true )
	   {
	     p_BaseBody->setLinearVelocity( 
		p_BaseBody->getOrientation() * 
                                Ogre::Vector3::ZERO );
	   }
	}
}

void MyListener::act_jump( bool jump_request ) 
{
    if( b_onGround == true && jump_request == true ) 
    {
       p_BaseBody->setLinearVelocity( Vector3( 
	  p_BaseBody->getLinearVelocity().x /*/ 1.9 */ 
	  , r_JumpHeight
	  , p_BaseBody->getLinearVelocity().z /*/ 1.9*/ ));
    }
}


Main.cpp

#include "ExampleApplication.h"
#include "CharacterController.h"

 // Declare a subclass of the ExampleApplication class
 class SampleApp : public ExampleApplication 
 {
 public:
   SampleApp( void ) {}
 
 protected:
   // Define what is in the scene
   void createScene( void ) {}
 
   // Create new frame listener
   void createFrameListener( void )
   {
       mFrameListener = new MyListener( 
                  mWindow, mCamera, mSceneMgr, mRoot );
       mRoot->addFrameListener( mFrameListener );
   }
 };

 #if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
 #define WIN32_LEAN_AND_MEAN
 #include "windows.h"
 #endif
 
 #ifdef __cplusplus
 extern "C" {
 #endif

 #if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
 INT WINAPI WinMain( 
     HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT )
 #else
 int main( int argc, char **argv )
 #endif
 {
    // Create application object
    SampleApp app;
 
    try {
        app.go();
    } catch( Exception& e ) {
 #if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
        MessageBox( NULL, e.getFullDescription().c_str()
            , "An exception has occured!"
            , MB_OK | MB_ICONERROR | MB_TASKMODAL);
 #else
        std::cerr << "An exception has occured: " <<   
                                   e.getFullDescription();
 #endif
    }
 
    return 0;
 }
 
 #ifdef __cplusplus
 }
 #endif



I have found strange effects when walking over parts of the mesh which overlap itself, such as a terrain with a built in bridge. One thing to try is to make the bridge as a separate trimesh and see if the character correctly walks over it.

by 0_0, Janitor Bob, Orange, the All-in-One...