"Floating" hand with Physics that accompanies the body

TeaBag

26-08-2009 14:10:01

Hi there,

First of all I want to say I'm sorry if this post is too long. There are several problems with what I'm trying to achieve. I'm using Mogre 1.4.8 and MogreNewt (NGD 1.53) but any tips from anyone are more than welcome. I should also state that my knowledge with MogreNewt is quite limited as well with physics so if you see something completely wrong don't be surprised :D .

I currently have a "actor" body created as already mentioned several times in the forums (I will try to get to a little more detail a little later) and now I'm trying to add a hand to that "actor". The particularities of the hand are that it is just a right hand, floating in the air at a distance from the actor's body (try to picture Rayman's hands... the concept is the same). I will have to able to move this hand (I will define some limits) but something important is that this hand has to have physical properties so that it collides with objects. The hand itself is a simple mesh without bones, etc... just a representation of the hand that will not change its shape.

The actor part is working with an Ellipsoid collision body.
Basically I have (the order that I create everything is the one that I show below):
actorNode (I start by updating its position and orientation to the ones that I want)
|> Camera (Create a camera)
|> actorBody (attached to actorNode, position and orientation of the Body updated accordingly to the actorNode's)
|> handNode (since I want to move it independently this seemed to me the logical choice. I loaded the hand's Entity and attached to this node)
|> handBody (here I created a ConvexHull collision type passing the handNode and using the handNode's position and orientation to affect the Body)

The code that I'm using is this:

// Init function of my Actor class
public void Init( Vector3 size, Vector3 startPosition, Quaternion orientation )
{
// update position
actorNode.Position = startPosition;
// update orientation (only the y is important for now)
actorNode.Orientation = new Quaternion( 1, 0, orientation.y, 0 );
actorNode.SetScale( Vector3.UNIT_SCALE );

actorNode.AttachObject( camera );

CreateBodyNode( size, startPosition );

CreateHandNode( Vector3.ZERO );
}

protected override void CreateBodyNode( Vector3 size, Vector3 startPosition )
{
float height = size.y / 2;

Vector3 bodySize = new Vector3( size.x, height, size.z );
Collision collision = new Ellipsoid( newtHandler.World, bodySize );
actorBody = new Body( newtHandler.World, collision, true );

collision.Dispose();

actorBody.SetPositionOrientation( actorNode.Position, actorNode.Orientation );

const float mass = 1000f;
Vector3 inertia = MomentOfInertia.CalcEllipsoidSolid( mass, bodySize );
actorBody.SetMassMatrix( mass, inertia );
actorBody.AttachToNode( actorNode );

MaterialID = new MaterialID( newtHandler.World );
actorBody.MaterialGroupID = MaterialID;

actorBody.ForceCallback += ApplyGravityForceCallback;

new UpVector( newtHandler.World, actorBody, Vector3.UNIT_Y );
upVectorZ = new UpVector( newtHandler.World, actorBody, Vector3.UNIT_Z );

actorBody.UnFreeze();

// Set the camera's position
headCamera.Position = new Vector3( 0f, height, 0f );
}

protected override void CreateHandNode( Vector3 position )
{
handNode = actorNode.CreateChildSceneNode( "handNode_" + actorCounter );

// Create the entity for the hand
Entity hand = sceneManager.CreateEntity( "hand", "hand.mesh" );
hand.SetMaterialName( "hand" );
hand.NormaliseNormals = true;

// Attach it to handNode previously created
handNode.AttachObject( hand );
// Scale the node and assign its position
handNode.Scale( Vector3.UNIT_SCALE );
handNode.Position = position;
handNode.Position += new Vector3( 10f, 15f, 10f );

// Add physical properties
// Create ConvexHull for the hand
ConvexCollision collision = new ConvexHull( newtHandler.World, handNode, handNode.WorldPosition );
Vector3 inertia, offset;
const float mass = 20f;
collision.CalculateInertialMatrix( out inertia, out offset );
inertia = inertia * mass;

// Create a physics Body
handBody = new Body( newtHandler.World, collision );
collision.Dispose();
handBody.SetMassMatrix( mass, inertia );

// Attach the body to the handNode (so that actions will be reflected in that node)
handBody.AttachToNode( handNode );

// Set its position and orientation
handBody.SetPositionOrientation( handNode.Position, handNode.Orientation );

// Calculate a center of mass (assuming the center of the BoundingBox of the hand mesh)
handBody.CenterOfMass = hand.BoundingBox.Center;
handBody.IsGravityEnabled = false;

handBody.UnFreeze();
}


So what are the problems with this?
1: The visual hand appears where I sent it but the physical object is at the position that handNode has (the handNode's local position) but in world position (ok, this is complicated to me to explain so lets see some numbers: if my actor is at Vector3(100, 0, 100) and the hand is at Vector3(10,10,10) (local to the actor), my physical hand always appears at Vector3(10,10,10) in world coordinates).
I have tried to "feed" the hand's Body with the world position of the handNode but has the same effect (even when the values are different, checked by debugging).
2: Since I also want that the hand "rotates" when the body rotates I was considering to create some sort of Custom collision body that has the Ellipsoid body and the hand but I'm not sure if this will even work (I found some ways here in the forums to create Custom Joints that I believe that I can adapt to my situation).

The problem is explained so my questions are:

Do you have any suggestion on a good way to approach this problem?
Did anyone noticed anything completely wrong with my code?

Thank in advance,
Luís