Rag Doll exported from Blender not working in OgreODE

joemarshall

27-02-2007 06:32:00

I've written some code using OgreOdeRagDoll.

It works fine with the zombie model that comes with ogreode.

However, I'm now trying to import my own character models from Blender,

Mesh, skeleton and original blend file here -
http://www.wikiupload.com/download_page.php?id=90745

When I use them directly in ogre, the model works okay, moving the skeleton moves the body.

However, when I use them in the ragdoll code, they don't work right, they just go weird and twisted, and don't collide correctly, even if I set all the joints to fixed as a test (and set all bones to create boxes).

From turning on the debug display in OgreOde::World, it appears that the bodies being created for each bone are being created in the wrong place. For example the head appears somewhere down the legs, offset to be behind the model, where as various other bones create bodies that are offset in front of the model, and none of them create bodies which are centred front to back on the model, which should be the case for all of the created bodies.

I've traced it back through the code, and it seems that EntityInformer::createOrientedBox is creating the wrong boxes for this mesh for some reason, and I just can't work out why? I presume my mesh is set up in a slightly different way to the standard ones, that isn't supported by OgreODE.

Does anyone have any idea what might be going wrong here? Can anyone give me some tips to fix it?

Also, if anyone has a model that exports nicely from blender and works as a ragdoll, that I could have, to see how its skeleton is done, that'd be really useful.

cheers,

Joe

joemarshall

27-02-2007 06:37:56

Looking at it closely, it's generating correctly sized bodies for each bone.

However, when I show the bodies in debug, they're just jumbled randomly around the mesh, rather than being in the right place on the body, even before I run the physics simulation at all, and when I run the physics simulation it goes a bit funny, because it thinks the body is such a funny shape.

Joe

rewb0rn

27-02-2007 07:38:19

You have to write your own .ogreode file for ragdolls. checkout zombie.ogreode

joemarshall

27-02-2007 08:11:43

Yep, I've done that. It doesn't fix this problem.

Something is going wrong with the transformations of the generated body objects, and I can't tell what.

Joe

joemarshall

27-02-2007 10:31:42

I've just made up a very simple example - this is just 3 cubes, with bones joining the cubes.

In blender it animates fine, but when I load the mesh+skeleton into ogreode, this is what I get - all the cubes are offset by 50% of the width of the cube, in a random direction (it changes sometimes when I turn on/off the rag doll's physical control)



Joe

rewb0rn

27-02-2007 13:03:12

This might be the same problem that has been mentioned here: http://www.ogre3d.org/phpBB2addons/viewtopic.php?t=3578
Seems to me like this is a bug for boxes in the ragdolls class. Maybe you want to create and submit a patch for this :)

joemarshall

28-02-2007 00:05:39

Thank you for that. It appears it's exactly that. My (working) zombie_auto.ode was using all capsules. I've changed it to boxes and the same bug occurs - it appears box shapes just don't work.

I'll look and see if I can do a fix today, if I don't manage it, it's convert to newton time.

Joe

joemarshall

28-02-2007 01:54:02

The bug is here in EntityInformer.cpp


box_kCenter += (box_afExtent[0])*box_akAxis[0] +
(box_afExtent[1])*box_akAxis[1] +
(box_afExtent[2])*box_akAxis[2];


should be


box_kCenter += (0.5*(fY0Max+fY0Min))*box_akAxis[0] +
(0.5*(fY1Max+fY1Min))*box_akAxis[1] +
(0.5*(fY2Max+fY2Min))*box_akAxis[2];


I guess that code just never worked, I can't see any situation in which it would have worked.

This is a fix to the immediate problem with the zombies. It doesn't fix the problem that it's just doing the wrong thing. The method it is using works fine for complex models, but won't work at all if there is a singularity in the model, in the worst case of a cube, it'll just give you a randomly rotated box that the cube fits inside. A box fitting method that doesn't work for boxes is not the right box fitting method.

It doesn't work for my model still, which is rubbish.

I think what I'm going to do is change the createOrientedBox, createOrientedCapsule etc. to use the bone orientation given to them, and then just work out the box from that, rather than try to be clever and do a bad job as currently seems to be happening.

Joe

joemarshall

28-02-2007 06:24:31

Hmm,

I've fixed various bugs, but it's still broken.

I'm getting to the point where I just don't believe this ever worked, I mean if you play with the demo, it doesn't work.

I'm going to try newton and see what that does.

Joe

joemarshall

28-02-2007 09:52:57

For reference, in case anyone else tries this, having spent 3 days/20 hours of work attempting to fix the bugs in OgreODE ragdolls, I just spent the last 30 minutes compiling the Newton physics wrapper for Ogre (OgreNewt) and running it in that. It was oh so easy, and works fantastically.

Joe

tuan kuranes

28-02-2007 13:52:17

I've fixed various bugs, but it's still broken.
Stil interested in fix, anyway
I'm getting to the point where I just don't believe this ever worked, I mean if you play with the demo, it doesn't work.
Not sure it ever works better than now too.

For a very nice open source code that does that and better you can check :
http://codesuppository.blogspot.com/200 ... amics.html

joemarshall

01-03-2007 09:33:34

Stil interested in fix, anyway


BoxGeometry* EntityInformer::createOrientedBox(unsigned char bone, World *world, Space* space)
{
unsigned int vertex_count;
Vector3* vertices;
if (!getBoneVertices(bone, vertex_count, vertices))
return 0;

Vector3 box_kCenter(Vector3::ZERO);
Ogre::Vector3 box_akAxis[3];
Ogre::Real box_afExtent[3];

// EigenSolver::GaussPointsFit (vertex_count-1, &vertices[1], box_kCenter, box_akAxis, box_afExtent);

Ogre::Real invVertexCount=1.0/(Ogre::Real)vertex_count;
for(int c=0;c<vertex_count;c++)
{
box_kCenter+=vertices[c];
}
box_kCenter*=invVertexCount;

Quaternion orient=_entity->getSkeleton()->getBone(bone)->_getDerivedOrientation();
orient.ToAxes(box_akAxis);


// Let C be the box center and let U0, U1, and U2 be the box axes. Each
// input point is of the form X = C + y0*U0 + y1*U1 + y2*U2. The
// following code computes min(y0), max(y0), min(y1), max(y1), min(y2),
// and max(y2). The box center is then adjusted to be
// C' = C + 0.5*(min(y0)+max(y0))*U0 + 0.5*(min(y1)+max(y1))*U1 +
// 0.5*(min(y2)+max(y2))*U2


Ogre::Vector3 kDiff (vertices[1] - box_kCenter);
Ogre::Real fY0Min = kDiff.dotProduct(box_akAxis[0]), fY0Max = fY0Min;
Ogre::Real fY1Min = kDiff.dotProduct(box_akAxis[1]), fY1Max = fY1Min;
Ogre::Real fY2Min = kDiff.dotProduct(box_akAxis[2]), fY2Max = fY2Min;

for (unsigned int i = 2; i < vertex_count; i++)
{
kDiff = vertices[i] - box_kCenter;

const Ogre::Real fY0 = kDiff.dotProduct(box_akAxis[0]);
if ( fY0 < fY0Min )
fY0Min = fY0;
else if ( fY0 > fY0Max )
fY0Max = fY0;

const Ogre::Real fY1 = kDiff.dotProduct(box_akAxis[1]);
if ( fY1 < fY1Min )
fY1Min = fY1;
else if ( fY1 > fY1Max )
fY1Max = fY1;

const Ogre::Real fY2 = kDiff.dotProduct(box_akAxis[2]);
if ( fY2 < fY2Min )
fY2Min = fY2;
else if ( fY2 > fY2Max )
fY2Max = fY2;
}

box_afExtent[0] = ((Real)0.5)*(fY0Max - fY0Min);
box_afExtent[1] = ((Real)0.5)*(fY1Max - fY1Min);
box_afExtent[2] = ((Real)0.5)*(fY2Max - fY2Min);

box_kCenter += (0.5*(fY0Max+fY0Min))*box_akAxis[0] +
(0.5*(fY1Max+fY1Min))*box_akAxis[1] +
(0.5*(fY2Max+fY2Min))*box_akAxis[2];

BoxGeometry *geom = new BoxGeometry(Vector3(box_afExtent[0] * 2.0,
box_afExtent[1] * 2.0,
box_afExtent[2] * 2.0),
world, space);
geom->setOrientation(Quaternion(box_akAxis[0],box_akAxis[1],box_akAxis[2]));
geom->setPosition(box_kCenter);
return geom;
}


This is the last version I got to - it uses the bone axis as the axis for the box, rather than the gaussian fit axis - this avoids the problem that if your bone is actually a box, there is a singularity in the matrix that makes it go a bit mad. Thinking about it, it doesn't need to calculate the mean of the points either, it could just use an arbitrary point.

Joe