(NEW VIDEO) my fighting game project video (ragdoll)

LucaMoller

20-11-2009 19:37:50

<NEW>
I've recorded a new video of the most recent version of the project: (it has better graphics, new cenarios and a new character)
http://www.youtube.com/watch?v=rtF50nlVCCw
</NEW>

Hello everyone,

Some months ago I made a post here asking about some joint stuff to work out a ragdoll. I said i would post something about the project when its more advanced. Right now, I'm not working on in it anymore, my team won the science and technology fair of my university with it :D (but, we dont kow why, we didnt qualify to the game competition we wanted)...

This is a video from one of the versions before the lasts (we got some better graphics, another character, more magics and deeper water so it doesnt look like the character is walking over water hehe):

http://www.youtube.com/watch?v=RkD48e-MT0w

Ill try to post a video from the most recent version, but I wont promisse because it was a pain in the *** to make this one xD

If anyone wants some code or hints, just ask ;)

betajaen

20-11-2009 19:52:13

Muito bom, bem feito!

I'm sure many of us would love to see the source for the ragdolls or your experience working with it, but congratulations on winning.

klarax

23-11-2009 11:35:16

Would love to see how your ragdoll's work :)

LucaMoller

24-11-2009 05:07:35

In the attachment are the 3 code files that I believe that contain all the ragdoll stuff.
But as I said before, the code is bad code xD
Ill try to explain the essential here:

Im my system I have 2 types of capsules(that always go together), one is for collision detection, the other for collision effects. The dynamic (they act like ghosts) is for detection, the kinematic for the effects.

Creating the capsules: (we will create capsules for the character corpse with right sizes)

Ogre::Skeleton::BoneIterator iterador = jgd::jog_luta[p]->ent->getSkeleton()->getBoneIterator(); // ent is the entity that has the character skeleton
char nomes[20];
Ogre::Bone *b;
while(iterador.hasMoreElements()) //move through all the skeletons bones
{
b = iterador.peekNext();
sprintf(nomes, "bone %d %d",i , p);

if( strcmp(b->getName().c_str() , NAME_OF_THE_BONE_YOU_WANT ) == 0) // here we will create the capsule between the bone we want and his parent
{
Vector3 posparent = jgd::jog_luta[p]->node->getPosition() + jgd::jog_luta[p]->node->getOrientation()*(b->getParent()->_getDerivedPosition())
Vector3 posbone = jgd::jog_luta[p]->node->getPosition() + jgd::jog_luta[p]->node->getOrientation()*(b->_getDerivedPosition());
Vector3 rel = posbone-posparent;

sprintf( nomes, "corpo %d %d",i ,p);
sys::mNxScene->createBody(nomes,new NxOgre::Capsule(tam,rel.length()-5), posparent+0.5*rel,"","mass:10");
sys::mNxScene->getActor(nomes)->raiseBodyFlag(NX_BF_DISABLE_GRAVITY);
sys::mNxScene->getActor(nomes)->raiseActorFlag(NX_AF_DISABLE_RESPONSE);
sys::mNxScene->getActor(nomes)->setLinearDamping(3);
sys::mNxScene->getActor(nomes)->setAngularDamping(3);
sys::mNxScene->getActor(nomes)->setGroup(jgd::jog_luta[p]->ag_corpo);
NxShape* const* s = sys::mNxScene->getActor(nomes)->getNxActor()->getShapes();
(*s)->setGroup(10+p);
(*s)->setMaterial( sys::mNxScene->getMaterialIndex("material_capsulas"));

sprintf( nomes, "corpok %d %d",i ,p);
sys::mNxScene->createBody(nomes,new NxOgre::Capsule(tam,rel.length()-5), posparent+0.5*rel,"","mass:10");
sys::mNxScene->getActor(nomes)->raiseBodyFlag(NX_BF_KINEMATIC);
sys::mNxScene->getActor(nomes)->setGroup(jgd::jog_luta[p]->ag_ossos);
NxShape* const* s2 = sys::mNxScene->getActor(nomes)->getNxActor()->getShapes();
(*s2)->setGroup(20+p);
}



Putting the capsules at the right place (called every loop):

char nomes[20];
int i=0;
Ogre::Bone *b;
while( i < jgd::jog_luta[p]->num_ossos ) //I have just numbered the bones and put them in a vector
{
b = jgd::jog_luta[p]->bones[i] ; // this vector
sprintf(nomes, "bone %d %d",i , p);

if( jgd::jog_luta[p]->ragdoll == 0 && jgd::jog_luta[p]->ragdoll_ant == 0) // lets put the capsules at right place if not in ragdoll mode
{
if(jgd::jog_luta[p]->osso_mao_direita == i || jgd::jog_luta[p]->osso_mao_esquerda == i || jgd::jog_luta[p]->osso_cotovelo_direito == i || jgd::jog_luta[p]->osso_cotovelo_esquerdo== i || jgd::jog_luta[p]->osso_joelho_direito == i || jgd::jog_luta[p]->osso_joelho_esquerdo == i || jgd::jog_luta[p]->osso_pe_direito == i || jgd::jog_luta[p]->osso_pe_esquerdo == i)
{

// Calculating the capsules position, putting them there, and them doing the right rotations

Vector3 posparent = jgd::jog_luta[p]->node->getPosition() + jgd::jog_luta[p]->node->getOrientation()*(b->getParent()->_getDerivedPosition()) ;
Vector3 posbone = jgd::jog_luta[p]->node->getPosition() + jgd::jog_luta[p]->node->getOrientation()*(b->_getDerivedPosition());
Vector3 rel = posbone-posparent;

sprintf( nomes, "corpo %d %d",i ,p);
sys::mNxScene->getActor(nomes)->setGlobalPosition( posparent + 0.5*rel);
Vector3 vecy( 0, 1, 0);
sys::mNxScene->getActor(nomes)->setGlobalOrientation( vecy.getRotationTo(rel) );
sys::mNxScene->getActor(nomes)->setLinearVelocity( Vector3(0,0,0));

sprintf( nomes, "corpok %d %d",i ,p);
sys::mNxScene->getActor(nomes)->moveGlobalPosition( posparent + 0.5*rel);
sys::mNxScene->getActor(nomes)->moveGlobalOrientation( vecy.getRotationTo(rel) );
}


When comes the time to activate the ragdoll, we create the joints and put the capsules in dynamic mode:

void Luta::set_dyn( int p )
{
char nomes[20];
int i=0;
while( i <jgd::jog_luta[p]->num_ossos )
{
if( jgd::jog_luta[p]->osso_mao_direita == i ||
jgd::jog_luta[p]->osso_mao_esquerda == i ||
jgd::jog_luta[p]->osso_cotovelo_direito == i ||
jgd::jog_luta[p]->osso_cotovelo_esquerdo== i ||
jgd::jog_luta[p]->osso_joelho_direito == i ||
jgd::jog_luta[p]->osso_joelho_esquerdo == i ||
jgd::jog_luta[p]->osso_pe_direito == i ||
jgd::jog_luta[p]->osso_pe_esquerdo == i ||
jgd::jog_luta[p]->osso_cabeca == i )
{
sprintf( nomes, "corpo %d %d",i ,p);
sys::mNxScene->getActor(nomes)->clearBodyFlag(NX_BF_DISABLE_GRAVITY);
sys::mNxScene->getActor(nomes)->clearActorFlag(NX_AF_DISABLE_RESPONSE);
}
if( jgd::jog_luta[p]->osso_mao_direita == i ||
jgd::jog_luta[p]->osso_mao_esquerda == i ||
jgd::jog_luta[p]->osso_cotovelo_direito == i ||
jgd::jog_luta[p]->osso_cotovelo_esquerdo== i ||
jgd::jog_luta[p]->osso_joelho_direito == i ||
jgd::jog_luta[p]->osso_joelho_esquerdo == i ||
jgd::jog_luta[p]->osso_pe_direito == i ||
jgd::jog_luta[p]->osso_pe_esquerdo == i)
{
sprintf( nomes, "corpok %d %d",i ,p);
sys::mNxScene->getActor(nomes)->raiseActorFlag(NX_AF_DISABLE_RESPONSE);
}

//example of creation of one of the joints between capsules, the other should be created similarly (choose the best joint to fit that place, spherical, revoltion, etc)
//my parameters here may not make much sense (I learned while doing it, so the initial garbage from tests may be still on)
void Luta::criar_juntas(int p)
{
char nomes[20];
char nomes2[20];
Ogre::Bone *b;
int i=0;
while( i <jgd::jog_luta[p]->num_ossos )
{
printf("%d\n",i);
NxOgre::JointParams jpr;
jpr.setToDefault();

jpr.mHasSwingSpring=1;
jpr.mSwingSpring_Damper=0.0;
jpr.mSwingSpring_Spring=100.0;
jpr.mSwingSpring_Target=0.0;

jpr.mHasSwingLimit=0;
b = jgd::jog_luta[p]->bones[i];

if( jgd::jog_luta[p]->osso_mao_direita == i)
{
printf("a\n");
Vector3 posparent = jgd::jog_luta[p]->node->getPosition() + jgd::jog_luta[p]->node->getOrientation()*(b->getParent()->_getDerivedPosition()) ;
Vector3 pos = jgd::jog_luta[p]->node->getPosition() + jgd::jog_luta[p]->node->getOrientation()*(b->_getDerivedPosition()) ;
Vector3 pos_avo = jgd::jog_luta[p]->node->getPosition() + jgd::jog_luta[p]->node->getOrientation()*(b->getParent()->getParent()->_getDerivedPosition()) ;
sprintf( nomes, "corpo %d %d",i ,p);

jpr.mHasLimits=1;
jpr.mUpperLimit=0.80*NxPi;
jpr.mUpperLimitRestitution=0.2;
jpr.mLowerLimit=0.00*NxPi;
jpr.mLowerLimitRestitution=0.2;

jgd::jog_luta[p]->joint_cotovelo_direito = sys::mNxScene->createSphericalJoint( sys::mNxScene->getActor(nomes), sys::mNxScene->getActor(nomes2), posparent ,jpr);
}


Now comes the dificult part: making the character entity go after the capsules
First you should release your entity of all kinds of animation. Set all its bones manually_controled(true).
Now you have to rotate the bones so the model fit the capsules.



//First i put the root bone in the right place/rotation
void Luta::anim_bones_pre(int p)
{
char nomes[20];
Ogre::Bone *b;
int i=0;
while( i <jgd::jog_luta[p]->num_ossos )
{
b = jgd::jog_luta[p]->bones[i];

b->setPosition( jgd::jog_luta[p]->initial_pos[i] );
b->setOrientation(jgd::jog_luta[p]->initial_ori[i] );
b->_update(1,0);

if(jgd::jog_luta[p]->osso_pai == i)
{
//Vector3 pos_cabeca = jgd::jog_luta[p]->node->getPosition() + jgd::jog_luta[p]->node->getOrientation()*b->_getDerivedPosition() ;
Vector3 pos_pai = jgd::jog_luta[p]->node->getPosition()+ jgd::jog_luta[p]->node->getOrientation()*b->getPosition();
Vector3 pos_node = jgd::jog_luta[p]->node->getPosition();
sprintf( nomes, "corpo %d %d", jgd::jog_luta[p]->osso_cabeca, p);
Vector3 pos_capsule = sys::mNxScene->getActor(nomes)->getGlobalPositionAsOgreVector3();
Vector3 joint1 = jgd::jog_luta[p]->joint_virilha_direita->getGlobalAnchor();
Vector3 joint2 = jgd::jog_luta[p]->joint_virilha_esquerda->getGlobalAnchor();

Vector3 pos_result = jgd::jog_luta[p]->node->getOrientation().Inverse() * ( 0.5*(joint1 + joint2) - pos_node) ;

b->setPosition( pos_result );

Quaternion qrot = sys::mNxScene->getActor(nomes)->getGlobalOrientationAsOgreQuaternion();
b->setOrientation( jgd::jog_luta[p]->node->getOrientation().Inverse() * qrot );
if(jgd::jog_profile[p]->index_personagem_escolhido==3)b->setOrientation( jgd::jog_luta[p]->node->getOrientation().Inverse() * Quaternion(cos(15*3.14/180.0),0,0,sin(15*3.14/180.0))* qrot );
b->_update(1,0);
}
i++;
}

//Then i put the other others in the right place (Put the ancestors in the right place before!)
void Luta::anim_bones( int p )
{
Ogre::Bone *b;
char nomes[20];
int i=0;
while( i <jgd::jog_luta[p]->num_ossos )
{
b = jgd::jog_luta[p]->bones[i];


if(jgd::jog_luta[p]->osso_cotovelo_direito == i)
{
Vector3 pos_anchor = jgd::jog_luta[p]->joint_cotovelo_direito->getGlobalAnchor();
Vector3 pos_parent = jgd::jog_luta[p]->node->getPosition() + jgd::jog_luta[p]->node->getOrientation()*b->getParent()->_getDerivedPosition() ;
Vector3 pos_i = jgd::jog_luta[p]->node->getPosition() + jgd::jog_luta[p]->node->getOrientation()*b->_getDerivedPosition() ;
Quaternion qinv = jgd::jog_luta[p]->node->getOrientation()*b->getParent()->_getDerivedOrientation();
Vector3 vi = qinv.Inverse()*(pos_i - pos_parent) ;
Vector3 vf = qinv.Inverse()*(pos_anchor - pos_parent);
Quaternion qrot = vi.getRotationTo(vf);
b->getParent()->setOrientation( b->getParent()->getOrientation()*qrot );
b->getParent()->_update(1,0);

/*Quaternion quat = jgd::jog_luta[p]->node->getOrientation()*b->getParent()->_getDerivedOrientation();
Vector3 pos_result = pos_anchor - pos_parent;
b->setPosition(quat.Inverse()*pos_result);*/
}
if(jgd::jog_luta[p]->osso_cotovelo_esquerdo == i)
{
Vector3 pos_anchor = jgd::jog_luta[p]->joint_cotovelo_esquerdo->getGlobalAnchor();
Vector3 pos_parent = jgd::jog_luta[p]->node->getPosition() + jgd::jog_luta[p]->node->getOrientation()*b->getParent()->_getDerivedPosition() ;
Vector3 pos_i = jgd::jog_luta[p]->node->getPosition() + jgd::jog_luta[p]->node->getOrientation()*b->_getDerivedPosition() ;
Quaternion qinv = jgd::jog_luta[p]->node->getOrientation()*b->getParent()->_getDerivedOrientation();
Vector3 vi = qinv.Inverse()*(pos_i - pos_parent) ;
Vector3 vf = qinv.Inverse()*(pos_anchor - pos_parent);
Quaternion qrot = vi.getRotationTo(vf);
b->getParent()->setOrientation( b->getParent()->getOrientation()*qrot);
b->getParent()->_update(1,0);
}

if(jgd::jog_luta[p]->osso_joelho_direito == i)
{
Vector3 pos_anchor = jgd::jog_luta[p]->joint_joelho_direito->getGlobalAnchor();
Vector3 pos_parent = jgd::jog_luta[p]->node->getPosition() + jgd::jog_luta[p]->node->getOrientation()*b->getParent()->_getDerivedPosition() ;
Vector3 pos_i = jgd::jog_luta[p]->node->getPosition() + jgd::jog_luta[p]->node->getOrientation()*b->_getDerivedPosition() ;
Quaternion qinv = jgd::jog_luta[p]->node->getOrientation()*b->getParent()->_getDerivedOrientation();
Vector3 vi = qinv.Inverse()*(pos_i - pos_parent) ;
Vector3 vf = qinv.Inverse()*(pos_anchor - pos_parent);
Quaternion qrot = vi.getRotationTo(vf);
b->getParent()->setOrientation( b->getParent()->getOrientation()*qrot);
b->getParent()->_update(1,0);
}

if(jgd::jog_luta[p]->osso_joelho_esquerdo == i)
{
Vector3 pos_anchor = jgd::jog_luta[p]->joint_joelho_esquerdo->getGlobalAnchor();
Vector3 pos_parent = jgd::jog_luta[p]->node->getPosition() + jgd::jog_luta[p]->node->getOrientation()*b->getParent()->_getDerivedPosition() ;
Vector3 pos_i = jgd::jog_luta[p]->node->getPosition() + jgd::jog_luta[p]->node->getOrientation()*b->_getDerivedPosition() ;
Quaternion qinv = jgd::jog_luta[p]->node->getOrientation()*b->getParent()->_getDerivedOrientation();
Vector3 vi = qinv.Inverse()*(pos_i - pos_parent) ;
Vector3 vf = qinv.Inverse()*(pos_anchor - pos_parent);
Quaternion qrot = vi.getRotationTo(vf);
b->getParent()->setOrientation( b->getParent()->getOrientation()*qrot);
b->getParent()->_update(1,0);
}

if( jgd::jog_luta[p]->osso_mao_direita == i ||
jgd::jog_luta[p]->osso_mao_esquerda == i ||
jgd::jog_luta[p]->osso_pe_direito == i ||
jgd::jog_luta[p]->osso_pe_esquerdo == i )
{
sprintf(nomes, "corpo %d %d", i , p);
Vector3 pos_capsule = sys::mNxScene->getActor(nomes)->getGlobalPositionAsOgreVector3();
Vector3 pos_parent = jgd::jog_luta[p]->node->getPosition() + jgd::jog_luta[p]->node->getOrientation()*b->getParent()->_getDerivedPosition() ;
Vector3 pos_i = jgd::jog_luta[p]->node->getPosition() + jgd::jog_luta[p]->node->getOrientation()*b->_getDerivedPosition() ;
Quaternion qinv = jgd::jog_luta[p]->node->getOrientation()*b->getParent()->_getDerivedOrientation();
Vector3 vi = qinv.Inverse()*(pos_i - pos_parent) ;
Vector3 vf = qinv.Inverse()*(pos_capsule - pos_parent);
Quaternion qrot = vi.getRotationTo(vf);
b->getParent()->setOrientation( b->getParent()->getOrientation()*qrot);
b->getParent()->_update(1,0);

/*Quaternion quat = jgd::jog_luta[p]->node->getOrientation()*b->getParent()->_getDerivedOrientation();
Vector3 pos_result = 2.0*(pos_capsule - pos_parent);
b->setPosition(quat.Inverse()*pos_result);*/
}
i++;
}
}


When the kinematic capsules of the character hit the other one in ragdoll mode, they will push his ragdoll capsules in the way the attack should do.

As you may notice, my code is a total mess, but i was totally inexperienced with everything about this project when I started it ( I just knew C before, not C++, so I took some time so I started to make classes with a better design).
Other thing you may notice is that my ragdoll may act weird some times!! ( I dont handle twisting!!!, thats too bad) ( I had problems with the twisting of the physic capsules, I was having dificulties to limit it accordingly, and after all I dint have time to remake it all)

If you're having a hard time trying to understand something, just ask! :wink: (sorry for the bad code again :? )
And if you want to know more about my project or more of its code just let me know too! I'm willing to post more stuff if someone is interested. (maybe the character movement handling can be interesting)

deshan

26-11-2009 08:16:34

hey LucaMoller
I just watch your video and that is really coooooool. 8)
What I say is you must make a nxogre code snippet for this ragdoll demonstration. :)
Thnax for sharing your work

LucaMoller

27-11-2009 17:33:03

Yes, thats a good idea!
I will try to familiarize with BloodyMess( I've just worked with Bleeding until now) when I have some time, and maybe try implement a Ragdoll class ready-to-use. :wink:

LucaMoller

11-12-2009 09:52:25

I've recorded a new video of the most recent version of the project: (it has better graphics, new cenarios and a new character)
http://www.youtube.com/watch?v=rtF50nlVCCw

subgravitation

11-02-2010 15:06:14

I've problems with this ragdoll, which I created using LucaMoller's code.This is a video with my ragdoll *http://www.youtube.com/watch?v=Y3AiNyaIvvg* . As you see it's o'k with setting position, but a big trouble with setting orientation. :evil: And that is my code:

Edit:

void Ragdoll::settingNxBones()
{
if (mode) return;

Ogre::Bone *b;
Ogre::Vector3 vecy( 1, 1, 1);

Ogre::LogManager::getSingleton().logMessage(" ");
Ogre::LogManager::getSingleton().logMessage("/*********************/");
Ogre::LogManager::getSingleton().logMessage("next iteration");

for (int i = 0; i < Bones.size(); i++)
{
b = Bones[i]; // this vector

Ogre::Vector3 posparent = node->getPosition() + node->getOrientation()*(b->getParent()->_getDerivedPosition());
Ogre::Vector3 posbone = node->getPosition() + node->getOrientation()*(b->_getDerivedPosition());
Ogre::Vector3 rel = posbone-posparent;

{
using namespace Ogre;
String NxQ = "NxBone orientation: ";
String Q = "Bone orientation: ";
//NxOgre::Functions::WXYZ<Ogre::Quaternion, Real4>(mCamera->getOrientation() );

NxQ.append(StringConverter::toString(NxOgre::Functions::WXYZ<NxOgre::Real4, Ogre::Quaternion>( NxBones[i]->getGlobalOrientationQuat() )));
Q.append(StringConverter::toString( Bones[i]->_getDerivedOrientation() ));

Ogre::LogManager::getSingleton().logMessage(" ");
Ogre::LogManager::getSingleton().logMessage("/* */");
Ogre::LogManager::getSingleton().logMessage(Bones[i]->getName());
Ogre::LogManager::getSingleton().logMessage(NxQ);
Ogre::LogManager::getSingleton().logMessage(Q);
}

NxBones[i]->setGlobalPosition( toNx(posparent + 0.5*rel));
NxBones[i]->setGlobalOrientation(NxOgre::Matrix33(NxOgre::Functions::WXYZ<Ogre::Quaternion, NxOgre::Real4>(Bones[i]->_getDerivedOrientation())));
NxBones[i]->setLinearVelocity( NxOgre::Real3(0,0,0));
}
}


As you see, the quaternions of NxBones and Bones don't match:

22:09:18: /*********************/
22:09:18: next iteration
22:09:18:
22:09:18: /* */
22:09:18: Rbicept
22:09:18: NxBone orientation: 0.801433 0 -0.254346 -0.541307
22:09:18: Bone orientation: -0.70293 -0.422722 0.313807 0.478248
22:09:18:
22:09:18: /* */
22:09:18: Rforearm
22:09:18: NxBone orientation: 0.659009 0 -0.219632 -0.719353
22:09:18: Bone orientation: -0.572567 -0.440421 0.263429 0.639376
22:09:18:
22:09:18: /* */
22:09:18: Rhand
22:09:18: NxBone orientation: 0.71448 0 0.525038 -0.462443
22:09:18: Bone orientation: -0.792828 0.0969374 -0.303243 0.519684
22:09:18:
22:09:18: /* */
22:09:18: Rshoulder
22:09:18: NxBone orientation: 0.99722 0 0.0731038 0.0144152
22:09:18: Bone orientation: 0.856461 -0.51045 0.0751558 0.0163485
22:09:18:
22:09:18: /* */
22:09:18: Lshoulder
22:09:18: NxBone orientation: -0.0243513 -0.00122739 0.634728 0.772351
22:09:18: Bone orientation: -0.0264267 0.0251499 0.634658 0.771932
22:09:18:
22:09:18: /* */
22:09:18: Lbicept
22:09:18: NxBone orientation: -0.124541 -0.487766 0.863065 -0.0411425
22:09:18: Bone orientation: -0.126589 -0.487707 0.863452 0.0238486
22:09:18:
22:09:18: /* */
22:09:18: Lforearm
22:09:18: NxBone orientation: -0.221973 -0.55632 0.742919 0.298844
22:09:18: Bone orientation: -0.109847 -0.544964 0.740905 0.37684
22:09:18:
22:09:18: /* */
22:09:18: Lhand
22:09:18: NxBone orientation: -0.358789 -0.356466 0.10592 0.856144
22:09:18: Bone orientation: -0.347231 -0.338388 0.251336 0.837708
22:09:18:
22:09:18: /* */
22:09:18: Rthigh
22:09:18: NxBone orientation: 0.5761 -0.524251 0.626479 -0.0281791
22:09:18: Bone orientation: 0.367341 -0.556877 0.661152 -0.343259
22:09:18:
22:09:18: /* */
22:09:18: Rshin
22:09:18: NxBone orientation: 0 0.708494 -0.691384 0.141508
22:09:18: Bone orientation: 0.268954 -0.613846 0.596792 -0.441245
22:09:18:
22:09:18: /* */
22:09:18: Lthigh
22:09:18: NxBone orientation: 0.516692 0 0.767395 -0.37965
22:09:18: Bone orientation: -0.613173 0.313291 -0.571255 0.446694
22:09:18:
22:09:18: /* */
22:09:18: Lshin
22:09:18: NxBone orientation: -0.373958 0.224708 -0.0287063 0.899354
22:09:18: Bone orientation: -0.299575 0.613735 -0.294372 0.668527
22:09:18:
22:09:18: /* */
22:09:18: Lfooteffector
22:09:18: NxBone orientation: 0.623086 0 0.749753 -0.222786
22:09:18: Bone orientation: -0.682745 0.247193 -0.650561 0.222543
22:09:18:
22:09:18: /* */
22:09:18: Rfootroot
22:09:18: NxBone orientation: 0.521755 0.0272075 0.83635 -0.165982
22:09:18: Bone orientation: 0.491164 0.0262378 0.856416 -0.156914


Can you help me to solve that problem?

PS: NxOgre 1.5.4, PhysX 2.8.1, Ogre 1.6.2.
PPS: sorry, that i wrote in old thread. :oops:

LucaMoller

13-02-2010 17:15:44

I think that i found something that is missing (but I'm not sure it will solve the problem at all). When you use _getDerivedOrientation() I think you get the orientation of the node relative to the entity's node (the entity to which the bone belongs), and not relative the world's root node!(what you want)
So the orientation you want to set to the NxBones in fact is entity_node->get_Orientation()*bone->get_DerivedOrientation().

Try changing this then:
NxBones[i]->setGlobalOrientation(NxOgre::Matrix33(NxOgre::Functions::WXYZ<Ogre::Quaternion, NxOgre::Real4>(entity_node->get_Orientation()*Bones[i]->_getDerivedOrientation())));

Now, why I'm not confident that this will solve the problem? I think the legs bones would not match at some times if this were the only problem... but cant be sure.

Anyway, if it dont solve the problem, there's another thing i'm not sure about your code, I dont know how you are relating your NxBones with the bones exaclty (when I did my ragdoll I made it in a way that the orientation I needed was the bone's father and not the bone's). So, just try to change Bones->_getDerivedOrientation() to Bones->getParent()->_getDerivedOrientation() and see if it gets better.

Let we know if it works or not, I remember the big troubles I had with these kinds of problems hehe. (but this part of setting the Nxbones orientation after the bones' I did in a different way, but if you can get your approach to work, it will be much better than mine and I think it would solve the problems I had with the twisting of the nxbones when setting the orientation of the bones based on the nxbones, in fact I ignored twisting in my aproach xD)

subgravitation

14-02-2010 09:53:04

in fact I ignored twisting in my aproach xD
Oh, you know, i have a big headache with this) I thought, that there are problems with my NxOgre engine))

So, about using function _getDerivedOrientation(). If I get bone's father orientation, there are the same problems + for example for the hand bone we set the orientation of the forearm bone)

So that is the code:
Ragdoll.h

#ifndef Ragdoll_H
#define Ragdoll_H

#include "stdafx.h"

class Ragdoll
{
public:
Ragdoll(const int &_id);
~Ragdoll();

void shutdown();
bool injectFrameEntered(Ogre::Real _time);

protected:
void creatingNxBones();
void _settingNxBones();
void settingNxBones();

private:
std::vector<Ogre::String> names;
std::vector<Ogre::Bone*> Bones;
std::vector<NxOgre::Actor*> NxBones;
int ID;
bool mode; // true - если труп, false - если живой

Ogre::Entity *ent;
Ogre::SceneNode *node;
Ogre::AnimationState *animState;

Ogre::String name;
Ogre::String node_name;

std::fstream ragdoll_log;
};

#endif


jaiqua_skeleton.xml

<?xml version="1.0" encoding="utf-8"?>
<model source="jaiqua">
<!--<bone>head</bone>
<bone>neck</bone>
<bone>Rforearm</bone>
<bone>Rhand</bone>
<bone>Lbicept</bone>
<bone>Lforearm</bone>
<bone>Lhand</bone>
<bone>Lhandroot</bone>
<bone>Rhandroot</bone>
<bone>Spine03</bone>
<bone>Spine02</bone>
<bone>Spine01</bone>-->
<bone>Rshin</bone>
<bone>Lshin</bone>
<bone>Lfooteffector</bone>
<bone>Rfootroot</bone>
<bone>Lfoot</bone>
<bone>Rfoot</bone>
</model>

Ragdoll.cpp

#include "Ragdoll.h"
#include "GameManager.h"
#include "tinyxml.h"

Ragdoll::Ragdoll(const int &_id) :
ID(_id),
mode(false),
ent(0),
node(0),
animState(0)
{
Ogre::String Filename = "../media/models/jaiqua_skeleton.xml";

TiXmlDocument doc(Filename.c_str());
if (doc.LoadFile())
{
TiXmlHandle hDoc(&doc);
TiXmlElement* pElem;
TiXmlHandle hRoot(0);

pElem = hDoc.FirstChildElement().Element();
if (pElem)
{
Ogre::String m_name = pElem->Value();
hRoot = TiXmlHandle(pElem);
}

pElem = hRoot.FirstChild("bone").Element();
for( pElem; pElem; pElem = pElem->NextSiblingElement())
{
const char *pKey = pElem->Value();
const char *pText = pElem->GetText();
if (pKey && pText)
names.push_back(pText);
}
}

name = "ragdoll_";
node_name = "ragdoll_node_";

name.append(Ogre::StringConverter::toString(ID));
node_name.append(Ogre::StringConverter::toString(ID));

ent = GameManager::getInstance().mSceneMgr->createEntity(name,"jaiqua.mesh");
node = GameManager::getInstance().mSceneMgr->getRootSceneNode()->createChildSceneNode(node_name,Ogre::Vector3(ID*20,0,0));
node->attachObject(ent);

std::vector<Ogre::String> anim_names;
anim_names.push_back("Run");
anim_names.push_back("Sneak");
anim_names.push_back("Stagger");
anim_names.push_back("Turn");
anim_names.push_back("Walk");

while (ID > 4)
ID -= 5;

animState = ent->getAnimationState(anim_names[ID]);
animState->setLoop( true );
animState->setEnabled( true );

ID = _id;

Ogre::String log_name = name;
log_name.append(".log");

ragdoll_log.open((log_name).c_str(), std::ios::out | std::ios::trunc);
creatingNxBones();
}

Ragdoll::~Ragdoll()
{
shutdown();
}

void Ragdoll::shutdown()
{
//for (int i = 0; i < NxBones.size(); i++)
//PhysXManager::getInstance().mNxScene;

GameManager::getInstance().mSceneMgr->destroyEntity(name);
GameManager::getInstance().mSceneMgr->getRootSceneNode()->removeChild(node_name);
GameManager::getInstance().mSceneMgr->destroySceneNode(node_name);
}

void Ragdoll::creatingNxBones()
{
// ent is the entity that has the character skeleton
Ogre::Skeleton::BoneIterator iterator = ent->getSkeleton()->getBoneIterator();
Ogre::Bone *b;

Bones.clear();
NxBones.clear();

NxOgre::RigidBodyDescription bodyDescr;
bodyDescr.mMass = 10;
bodyDescr.mBodyFlags |= NxOgre::Enums::BodyFlags_DisableGravity;
bodyDescr.mActorFlags |= NxOgre::Enums::ActorFlags_DisableResponse;
NxOgre::Actor* actor;

//move through all the skeletons bones
while(iterator.hasMoreElements())
{
b = iterator.getNext();
b->reset();

Ogre::String _name = b->getName();
Ogre::LogManager::getSingleton().logMessage(_name);

// here we will create the capsule between the bone we want and his parent
for (int i = 0; i < names.size(); i++)
if( strcmp(b->getName().c_str() , names[i].c_str()) == 0) //если равны
{
Ogre::Vector3 posparent = node->getPosition() + node->getOrientation()*(b->getParent()->_getDerivedPosition());
Ogre::Vector3 posbone = node->getPosition() + node->getOrientation()*(b->_getDerivedPosition());
Ogre::Vector3 rel = posbone-posparent;

//if (rel == Ogre::Vector3::ZERO) continue;

int radius = 1;

NxOgre::SharedString name = b->getName().c_str();
actor = PhysXManager::getInstance().mNxScene->createActor
(new NxOgre::Capsule(radius,rel.length()),NxOgre::Functions::XYZ<Ogre::Vector3, NxOgre::Real3>(posparent+0.5*rel),bodyDescr);
actor->setLinearDamping(3);
actor->setAngularDamping(3);
actor->setGroup(0);

Bones.push_back(b);
NxBones.push_back(actor);
}
}
}

void Ragdoll::settingNxBones()
{
// lets put the capsules at right place if not in ragdoll mode
if (mode) return;

NxOgre::Scene *mNxScene = PhysXManager::getInstance().mNxScene;
Ogre::Bone *bone;
Ogre::Quaternion new_orient;

//I have just numbered the bones and put them in a vector
for (int i = 0; i < Bones.size(); i++)
{
bone = Bones[i];

// Calculating the capsules position, putting them there, and them doing the right rotations
Ogre::Vector3 posparent = node->getPosition() + node->getOrientation()*(bone->getParent()->_getDerivedPosition());
Ogre::Vector3 posbone = node->getPosition() + node->getOrientation()*(bone->_getDerivedPosition());
Ogre::Vector3 rel = posbone-posparent;
Ogre::Vector3 forward = rel.normalisedCopy();

//Get bone Orientation and re-align
new_orient = node->_getDerivedOrientation()*Bones[i]->_getDerivedOrientation();
//new_orient = Ogre::Vector3::UNIT_Y.getRotationTo(forward);

NxBones[i]->setGlobalPosition( NxOgre::Functions::XYZ<Ogre::Vector3, NxOgre::Real3>(posparent + 0.5*rel));
NxBones[i]->setGlobalOrientation(NxOgre::Functions::WXYZ<Ogre::Quaternion, NxOgre::Real4>(new_orient));
NxBones[i]->setLinearVelocity( NxOgre::Real3(0,0,0));

{//result log
std::string NxQ = "NxBone orientation: ";
std::string Q = "Bone orientation: ";

NxQ.append(Ogre::StringConverter::toString(new_orient));
Q.append(Ogre::StringConverter::toString( bone->_getDerivedOrientation() ));

//writting information
ragdoll_log << "*** ***" << std::endl;
ragdoll_log << bone->getName() << std::endl;
ragdoll_log << NxQ << std::endl;
ragdoll_log << Q << std::endl;
}
}
}

bool Ragdoll::injectFrameEntered(Ogre::Real _time)
{
animState->addTime(_time);
settingNxBones();

return true;
}


It's another video:
http://www.youtube.com/watch?v=WGUAv4BRbaE
I found another topic about the ragdoll. In that ( <-- ) topic there is the code of the ragdoll.
Download
I compare it with my code. Mostly they are the same. May be I missed something, but I can't solve that problem(

And the last question) LucaMoller, when you align Bones with NxBones (when person is dead), is there such problem? or it's o'k?

LucaMoller

14-02-2010 14:23:53

When I put the NxBones after the Bones I didnt have much trouble (I just aligned the Nxbones with the (pos_bone - pos_father) vector, and by doing that I was ignoring twisting). Doing the back, setting the Bones after the NxBones was much harder! hehehe (but I think that with your approach it will be easier). If everything goes right, you will have the NxBone orientation and you will have to set the Bone orientation so that after it

(node->_getDerivedOrientation()*Bones->_getDerivedOrientation()) gets equal to (NxBone->getGlobalOrientation())

To do it you will have to do some math with the quaternions, I think the method Ogre::Quaterinon::Inverse() will be quite usefull (it was for me). You take the bone, set its orientation to (NxBone->getGlobalOrientation() * father_global_orientation.Inverse()) and I think you're done.

I have a doubt, when you create the capsules, they are in vertical position, but if you put all bones with global orientation Quat(0,0,0,1), will they stay in vertical position too? (I didn't think so at first, but as the legs are matching I'm thinking that it maybe works that way... and if not, it would not explain the "jumps" the capsules are performing) If not, this could be a problem, and you would need to set to the NxOgre a basic orientation and then, when changing its orientation, you would need to set it to (new_orient*basic_orientation) quaternion.

(The next 3 or 4 days I wont have access to internet I think, so I may not answer in this period, but I'm looking forward to see the result of your work! Just post here if you solve the problem or find anything else weird :wink: )

subgravitation

14-02-2010 14:55:23

O'k! :) I'll try to do something.

subgravitation

19-02-2010 12:50:24

how can i ctreate a d6 joint with NxOgre 1.5.4? I can't find the answer.

LucaMoller: have you an icq number?

LucaMoller

19-02-2010 17:25:02

I didn't use d6 joints, I dont even know what they are yet (I've used spherical and revolution joints).
I've sent you a private message with my gtalk account.

subgravitation

04-04-2010 12:17:06

:arrow: I've made correct ragdoll. but it's some bugs, and i made ragdoll without using NxOgre.. later I'll post the video :!:

LucaMoller

04-04-2010 15:26:27

cool! :wink: I'm looking foward to watch the video
Did you manage to solve that bug you had? (the capsules were not following the bones) Or you implemented it in a different way?

subgravitation

04-04-2010 16:00:02

in a different way) I'll post the code some time later)

subgravitation

08-04-2010 12:03:15

O'k. I made one part of the ragdoll without some bags and here is a video of it:
:arrow: http://www.youtube.com/user/subgravitat ... 7uq8_MpHDs
:arrow: http://www.youtube.com/user/subgravitat ... AZ-RIdUO9M

And what about the second part. Now I try to fix this bug:
:arrow: http://www.youtube.com/user/subgravitat ... awFXsTBbXM

When I do it, I'll tune the joints and post the code. Mayby I'll do it earlier, if I can't fix the bug :D

subgravitation

04-05-2010 17:39:38

My ragdoll was created with ogre 1.7 and PhysX 2.8.3.
:arrow: http://www.youtube.com/watch?v=ZBJpyTucOp0

The most important functions:

void Ragdoll::settingNxBones()
{
Ogre::Quaternion PhysxRotation, OgreGlobalQuat;
Ogre::Vector3 OgrePosition;
for (int i = 0; i < NxBones.size(); i++)
{
OgrePosition = (node->getOrientation() * NxBones[i].bone->_getDerivedPosition()) + node->getPosition();
OgreGlobalQuat = NxBones[i].bone->_getDerivedOrientation() * NxBones[i].OgreGlobalBindOrientation.Inverse();
PhysxRotation = OgreGlobalQuat * NxBones[i].PhysxBindOrientationInverse.Inverse();
NxBones[i].actor->setGlobalPosition(toNx(OgrePosition));
NxBones[i].actor->setGlobalOrientationQuat(toNx(node->getOrientation() * PhysxRotation, true));
}
}



void Ragdoll::settingBones(NxVec3 _flyForce)
{
for (int i = 0; i < NxBones.size(); i++)
NxBones[i].actor->addForce(_flyForce);

Ogre::SkeletonInstance* skeletonInst = ent->getSkeleton();
Ogre::Skeleton::BoneIterator boneI = skeletonInst->getBoneIterator();

Ogre::Quaternion PhysxRotation, OgreGlobalQuat, NodeRotationInverse = node->getOrientation().Inverse();
NxBones[0].bone->setPosition(toOgre(NxBones[0].actor->getGlobalPosition()) - node->getPosition());
for (int i = 0; i < NxBones.size(); i++)
{
Ogre::Quaternion ParentInverse;

PhysxRotation = toOgre(NxBones[i].actor->getGlobalOrientationQuat()) * NxBones[i].PhysxBindOrientationInverse;
ParentInverse = NodeRotationInverse;
if (NxBones[i].bone->getParent())
ParentInverse = ParentInverse * NxBones[i].bone->getParent()->_getDerivedOrientation().Inverse();
OgreGlobalQuat = PhysxRotation * NxBones[i].OgreGlobalBindOrientation;

NxBones[i].bone->setOrientation(ParentInverse * OgreGlobalQuat);
if (i != 0) NxBones[i].bone->_setDerivedPosition(toOgre(NxBones[i].actor->getGlobalPosition()) - node->getPosition());
}

};

nargil

18-05-2010 23:50:50

here are mine: http://www.youtube.com/watch?v=Pc_G6K_JhWU ;-)

LucaMoller

20-05-2010 20:07:39

Very nice!! They are looking much better than mine :wink:
If I try to do a ragdoll again some day, I'll use your approach! :)

subgravitation

22-05-2010 14:57:48

I find another bug. There is some delay among bones and nxbones. And I have no ideas how to solve this problem. Ideas?
http://www.youtube.com/watch?v=6UMDVyaL520

nargil

22-05-2010 19:18:09

Update the bone actors after you update the mesh position, and before rendering.

subgravitation

23-05-2010 07:47:46

o'k thanks, I'll try it

dudeabot

04-07-2010 19:19:36

does anyone have a working sample of ragdolls? cause i already tried all code samples but always have serious issues: sometimes some bones rotate too much leaving unnatural (even when i use limits), other the ragdolls rotates like exorcist or else dont match bone/actor

thanks