Ragdoll issues

shanefarris

09-12-2010 15:54:15

I am going off of the ragdoll example that was posted a few years back and a lot has changes since then. I got the code compiling but my model is twitching in a ball like its possessed by a demon on crack. If you need a video I can create one later tonight (I'm at work at the moment). I set the joints flag to 0, and 1 and both act the same. Here is my code, if anyone has an idea of what I am doing wrong I would like to hear it.

The "addJoints" method is what I think maybe wrong, for now I just have mostly default settings, but it is acting like they are colliding with each other even though I set the joint flag to 0.

Thanks a bunch!

struct BoneBind
{
Bone* bone;
NxOgre::Actor* BoneActor;


Vector3 BAoffset;
String name;

Quaternion BoneGlobalBindOrientation;
Quaternion BoneActorGlobalBindOrientationInverse;
};

BoneBind m_BoneBoneActorBind[15];
std::map<String, NxOgre::Joint*> m_Joints;
SceneNode* m_CharacterNode;
NxOgre::Scene* m_PHYSScene;
String m_CharacterID;



#include "CRagdoll.h"
#include "Nxp.h"
#include "NxActor.h"

using namespace Core;
using namespace Core::Physics;

CRagdoll::CRagdoll(String fileName, SceneNode *characterSN, String id, NxOgre::Scene *PHXScene, f32 bodyDensity)
{
m_CharacterNode = characterSN;
m_PHYSScene=PHXScene;
m_CharacterID=id;
m_PositionControllingBone=NULL;
m_BodyDensity=bodyDensity;
m_BonesCounter=0;

ConfigFile mRagDollCfgFile;
mRagDollCfgFile.loadFromResourceSystem(fileName, "General");

ConfigFile::SectionIterator seci = mRagDollCfgFile.getSectionIterator();

String secName, paramName, valueName;

while (seci.hasMoreElements())
{
secName = seci.peekNextKey();
ConfigFile::SettingsMultiMap *settings = seci.getNext();
ConfigFile::SettingsMultiMap::iterator i;

std::map<String, String> sectionData;

for (i = settings->begin(); i != settings->end(); ++i)
{
paramName = i->first;
valueName = i->second;

sectionData[paramName]=valueName;

}
if (secName!="")
{
_parseSectionData(secName, sectionData);
}


}

if (m_BonesCounter==15)
{

setControlToBones();
setAllBonesToManualControll(true);
setRagdollBindPose();

setAllBonesToManualControll(false);

addJoints();

//...as we dont have root bone attached to Bone Actor, we use Pelvis BA instead
if (!m_PositionControllingBone)
m_PositionControllingBone=getBoneBoneActorBindByName("Pelvis");

}
else
LogManager::getSingleton().logMessage( "Not enough bones declared in file: " + fileName + ". CRagdoll was not created!" );
}

void CRagdoll::_parseSectionData( String secName, std::map<String, String> section )
{
Vector3 dimensions = StringConverter::parseVector3( section["dimensions"] );
Vector3 offset = StringConverter::parseVector3( section["offset"] );

Entity* ent = ( Entity* ) m_CharacterNode->getAttachedObject( 0 );

m_BoneBoneActorBind[m_BonesCounter].name = secName;
m_BoneBoneActorBind[m_BonesCounter].bone = ent->getSkeleton()->getBone( section["boneName"] );
m_BoneBoneActorBind[m_BonesCounter].BAoffset = offset;

NxOgre::RigidBodyDescription desc;
//desc.reset();
desc.mMass = 0.0;
desc.mDensity = m_BodyDensity;
desc.mType = NxOgre::Enums::RigidBodyType_Dynamic;
desc.mBodyFlags = NX_BF_VISUALIZATION;

if (section["actorShape"]==String("sphere"))
{
m_BoneBoneActorBind[m_BonesCounter].BoneActor = m_PHYSScene->createActor(
new NxOgre::Sphere(dimensions.x), Matrix44_Identity,
desc);
}

if (section["actorShape"]==String("cube"))
{
m_BoneBoneActorBind[m_BonesCounter].BoneActor = m_PHYSScene->createActor(
new NxOgre::Box(dimensions.x,dimensions.y,dimensions.z), Matrix44_Identity,
desc);
}

if (section["actorShape"]==String("capsule"))
{
m_BoneBoneActorBind[m_BonesCounter].BoneActor = m_PHYSScene->createActor(
new NxOgre::Capsule(dimensions.x,dimensions.y), Matrix44_Identity,
desc);
}

//he have found a root bone - use it for character positioning
if (!m_BoneBoneActorBind[m_BonesCounter].bone->getParent())
m_PositionControllingBone=&m_BoneBoneActorBind[m_BonesCounter];

m_BonesCounter++;
}

void CRagdoll::setControlToBones()
{
m_ControlToBones=true;

m_ControlToBoneActors=false;
_setControlToBones();
}

void CRagdoll::setControlToBoneActors()
{
m_ControlToBoneActors=true;

m_ControlToBones=false;
_setControlToBoneActors();
}

void CRagdoll::_setControlToBones()
{
for (int i=0; i<15; i++)
{
m_BoneBoneActorBind[i].BoneActor->getNxActor()->raiseActorFlag( NX_AF_DISABLE_COLLISION );
m_BoneBoneActorBind[i].BoneActor->getNxActor()->raiseBodyFlag( NX_BF_KINEMATIC );
m_BoneBoneActorBind[i].BoneActor->putToSleep();
}
}

void CRagdoll::_setControlToBoneActors()
{
//updateBoneActors();
setAllBonesToManualControll(true);
resetAllBones();

//disabling all animations
Entity* e = ( Entity* ) m_CharacterNode->getAttachedObject( 0 );
AnimationStateSet* set = e->getAllAnimationStates();
AnimationStateIterator it = set->getAnimationStateIterator();
AnimationState *anim;

while( it.hasMoreElements() )
{
anim = it.getNext();
anim->setTimePosition( 0 );
anim->setEnabled( false );
anim->setWeight( 0 );
}

for( int i = 0; i < 15; i++ )
{
m_BoneBoneActorBind[i].BoneActor->getNxActor()->clearActorFlag(NX_AF_DISABLE_COLLISION);
m_BoneBoneActorBind[i].BoneActor->getNxActor()->clearBodyFlag(NX_BF_KINEMATIC);
m_BoneBoneActorBind[i].BoneActor->wakeUp(Real(20.0 * 0.02));
m_BoneBoneActorBind[i].BoneActor->setAngularDamping(1.0);
m_BoneBoneActorBind[i].BoneActor->setLinearDamping(1.0);
}
}

void CRagdoll::updateBones()
{
Quaternion PhysxRotation, OgreGlobalQuat, NodeRotationInverse = m_CharacterNode->getParentSceneNode()->getOrientation().Inverse();

// Loop through all bones
for( int i = 0; i < 15; i++ )
{
PhysxRotation = m_BoneBoneActorBind[i].BoneActor->getGlobalOrientationQuat().as<Quaternion>() * m_BoneBoneActorBind[i].BoneActorGlobalBindOrientationInverse;

Ogre::Quaternion ParentInverse = NodeRotationInverse;

if ( m_BoneBoneActorBind[i].bone->getParent() )
ParentInverse = m_BoneBoneActorBind[i].bone->getParent()->_getDerivedOrientation().Inverse() * NodeRotationInverse;
else
{
reVector3Df pos = m_BoneBoneActorBind[i].BoneActor->getGlobalPosition().as<reVector3Df>() -
m_CharacterNode->getParentSceneNode()->getOrientation() *
m_BoneBoneActorBind[i].bone->getPosition();
m_CharacterNode->getParentSceneNode()->setPosition( pos);
}

OgreGlobalQuat = PhysxRotation * m_BoneBoneActorBind[i].BoneGlobalBindOrientation;

m_BoneBoneActorBind[i].bone->setOrientation( ParentInverse * OgreGlobalQuat );
}

Ogre::Vector3 newPos = m_PositionControllingBone->BoneActor->getGlobalPosition().as<reVector3Df>() -
m_CharacterNode->getParentSceneNode()->getOrientation() *
m_PositionControllingBone->bone->getPosition() - m_PositionControllingBone->BAoffset;

m_CharacterNode->getParentSceneNode()->setPosition( newPos );
}

void CRagdoll::addJoints()
{
//NxOgre::JointParams jp;
//jp.mHasLimits=true;
//jp.mLowerLimit=-0.75*NxPi;
//jp.mUpperLimit=0;
NxOgre::RevoluteJointDescription rjd;
NxOgre::JointLimitPairDescription rjdLimit;
NxOgre::JointLimitDescription limit1;
limit1.mValue = -0.75*NxPi;

NxOgre::JointLimitDescription limit2;
limit2.mValue = 0;

rjdLimit.first = limit1;
rjdLimit.second = limit2;
rjd.mLimit = rjdLimit;
rjd.mJointFlags = 0;

NxOgre::SphericalJointDescription sjd;
sjd.mJointFlags = 0;

NxOgre::SphericalJointDescription sjd2;
sjd2.mJointFlags = 0;

//NxOgre::JointParams sphJointParam;

//sphJointParam.mHasLimits=true;
//
//sphJointParam.mHasTwistLimit=true;
//sphJointParam.mTwistLimit_Low_Value=-(NxReal)0.025*NxPi;
//sphJointParam.mTwistLimit_Low_Restitution=0.5;
//sphJointParam.mTwistLimit_High_Value=(NxReal)0.025*NxPi;
//sphJointParam.mTwistLimit_High_Restitution=1;

//sphJointParam.mHasSwingLimit=true;
//sphJointParam.mSwingLimit_Value=(NxReal)0.15*NxPi;
//sphJointParam.mSwingLimit_Restitution=0.5;

//sphJointParam.mHasTwistSpring=true;
//sphJointParam.mTwistSpring_Damper=1;
//sphJointParam.mTwistSpring_Spring=0.5;

//sphJointParam.mHasSwingSpring=true;
//sphJointParam.mSwingSpring_Spring=0.5;
//sphJointParam.mSwingSpring_Damper=1;

//sphJointParam.mJointProjectionDistance=(NxReal)0.15;
//sphJointParam.mJointProjectionMode=NX_JPM_POINT_MINDIST;

/////
//
//NxOgre::JointParams sphJointParam2=sphJointParam;
//sphJointParam2.mSwingLimit_Value=(NxReal)0.45*NxPi;
//sphJointParam2.mTwistLimit_Low_Value=-(NxReal)0.15*NxPi;
//sphJointParam2.mTwistLimit_High_Value=(NxReal)0.15*NxPi;



//Neck
NxOgre::Joint* joint = m_PHYSScene->createSphericalJoint(
getBoneBoneActorBindByName("Head")->BoneActor,
getBoneBoneActorBindByName("Torso")->BoneActor, sjd /*,pos ,sphJointParam*/);

//Chest
joint = m_PHYSScene->createFixedJoint(
getBoneBoneActorBindByName("Torso")->BoneActor,
getBoneBoneActorBindByName("Pelvis")->BoneActor);
//joint->setGlobalAxis(Vector3::UNIT_Y);

//Left Leg
joint=m_PHYSScene->createSphericalJoint(
getBoneBoneActorBindByName("Pelvis")->BoneActor,
getBoneBoneActorBindByName("LeftUpLeg")->BoneActor, sjd /*,pos,sphJointParam*/);
joint->setGlobalAxis(Vector3::NEGATIVE_UNIT_Y);

//Left knee
joint = m_PHYSScene->createRevoluteJoint(
getBoneBoneActorBindByName("LeftUpLeg")->BoneActor,
getBoneBoneActorBindByName("LeftLoLeg")->BoneActor, rjd/*,-Vector3::UNIT_X,pos,jp*/);

//Left ankle
joint = m_PHYSScene->createRevoluteJoint(
getBoneBoneActorBindByName("LeftLoLeg")->BoneActor,
getBoneBoneActorBindByName("LeftFoot")->BoneActor, rjd/*,Vector3::UNIT_X,pos,jp*/);

//Right Leg
joint = m_PHYSScene->createSphericalJoint(
getBoneBoneActorBindByName("Pelvis")->BoneActor,
getBoneBoneActorBindByName("RightUpLeg")->BoneActor, sjd /*,pos,sphJointParam*/);
joint->setGlobalAxis(Vector3::NEGATIVE_UNIT_Y);

//Right knee
joint = m_PHYSScene->createRevoluteJoint(
getBoneBoneActorBindByName("RightUpLeg")->BoneActor,
getBoneBoneActorBindByName("RightLoLeg")->BoneActor, rjd /*,-Vector3::UNIT_X,pos,jp*/);

//Right ankle
joint = m_PHYSScene->createRevoluteJoint(
getBoneBoneActorBindByName("RightLoLeg")->BoneActor,
getBoneBoneActorBindByName("RightFoot")->BoneActor, rjd /*,Vector3::UNIT_X,pos,jp*/);

//Left shoulder
joint = m_PHYSScene->createSphericalJoint(
getBoneBoneActorBindByName("Torso")->BoneActor,
getBoneBoneActorBindByName("LeftUpArm")->BoneActor, sjd2 /*, pos, sphJointParam2*/);
joint->setGlobalAxis(Vector3::UNIT_X);

//Left elbow
joint = m_PHYSScene->createRevoluteJoint(
getBoneBoneActorBindByName("LeftUpArm")->BoneActor,
getBoneBoneActorBindByName("LeftLoArm")->BoneActor, rjd /*,Vector3::UNIT_Y,pos,jp*/);

//Left hand
joint = m_PHYSScene->createSphericalJoint(
getBoneBoneActorBindByName("LeftLoArm")->BoneActor,
getBoneBoneActorBindByName("LeftHand")->BoneActor, sjd /*, pos, sphJointParam*/);

//Right shoulder
joint = m_PHYSScene->createSphericalJoint(
getBoneBoneActorBindByName("Torso")->BoneActor,
getBoneBoneActorBindByName("RightUpArm")->BoneActor, sjd2 /*, pos, sphJointParam2*/);
joint->setGlobalAxis(Vector3::NEGATIVE_UNIT_X);

//Right elbow
joint = m_PHYSScene->createRevoluteJoint(
getBoneBoneActorBindByName("RightUpArm")->BoneActor,
getBoneBoneActorBindByName("RightLoArm")->BoneActor, rjd /*,Vector3::UNIT_Y,pos,jp*/);

//Right hand
joint = m_PHYSScene->createSphericalJoint(
getBoneBoneActorBindByName("RightLoArm")->BoneActor,
getBoneBoneActorBindByName("RightHand")->BoneActor, sjd /*, pos,sphJointParam*/);
}

void CRagdoll::setRagdollBindPose()
{
updateBoneActors();
for (int i=0; i<15; i++)
{
m_BoneBoneActorBind[i].BoneGlobalBindOrientation = m_BoneBoneActorBind[i].bone->_getDerivedOrientation();
m_BoneBoneActorBind[i].BoneActorGlobalBindOrientationInverse =
NxOgre::Quat::invert(m_BoneBoneActorBind[i].BoneActor->getGlobalOrientationQuat()).as<Quaternion>();
}
}

shanefarris

16-12-2010 22:01:04

Any ideas?

betajaen

16-12-2010 22:20:48

I'm afraid not. What you could do is try increasing the damping on the joints and actors, and increasing the minimum sleep velocity.

shanefarris

17-12-2010 16:19:21

I'll try that. I've been messing with the joints and I am still getting the same issue, I'm wondering if my update method is correct. I've had to do a lot of updating to the "ragdoll cake" code so maybe I did something wrong because I don't understand the math, and wish I did.

void CRagdoll::updateBones()
{
Quaternion PhysxRotation, OgreGlobalQuat, NodeRotationInverse = m_CharacterNode->getParentSceneNode()->getOrientation().Inverse();

// Loop through all bones
for( int i = 0; i < 15; i++ )
{
PhysxRotation = m_BoneBoneActorBind[i].BoneActor->getGlobalOrientationQuat().as<Quaternion>() * m_BoneBoneActorBind[i].BoneActorGlobalBindOrientationInverse;

Ogre::Quaternion ParentInverse = NodeRotationInverse;

if ( m_BoneBoneActorBind[i].bone->getParent() )
ParentInverse = m_BoneBoneActorBind[i].bone->getParent()->_getDerivedOrientation().Inverse() * NodeRotationInverse;
else
{
reVector3Df pos = m_BoneBoneActorBind[i].BoneActor->getGlobalPosition().as<reVector3Df>() -
m_CharacterNode->getParentSceneNode()->getOrientation() *
m_BoneBoneActorBind[i].bone->getPosition();
m_CharacterNode->getParentSceneNode()->setPosition( pos);
}

OgreGlobalQuat = PhysxRotation * m_BoneBoneActorBind[i].BoneGlobalBindOrientation;

m_BoneBoneActorBind[i].bone->setOrientation( ParentInverse * OgreGlobalQuat );
}

Ogre::Vector3 newPos = m_PositionControllingBone->BoneActor->getGlobalPosition().as<reVector3Df>() -
m_CharacterNode->getParentSceneNode()->getOrientation() *
m_PositionControllingBone->bone->getPosition() - m_PositionControllingBone->BAoffset;

m_CharacterNode->getParentSceneNode()->setPosition( newPos );
}


I don't think its a big deal but in the conditional state that checks if the bone is a parent, it never finds a bone that is a parent.

Over all though, does this update method look right? Again, I wish I understood why we are doing what we are doing in this code but I just don't. I understand the math, I just don't understand why.

betajaen

17-12-2010 16:25:24

I'm not sure myself.

What you could do is compare the Ogre position/orientation visually using the Visual Debugger.

shanefarris

17-12-2010 16:35:44

I've never been able to get that working, I know I should get that running first before diving into this, but this is so much fun :)

shanefarris

20-12-2010 15:16:41

Messing with these settings didn't do anything. Here's another thing, if I only set joins for the left side of the body, it looks as if the leg is being pulled in one direction. The only thing I can think of is the math for updating the ragdoll is wrong, and I don't understand the math. I really want to get this to work, I've even offered to pay someone to implement it for me:
http://www.gamedev.net/community/forums/forum.asp?forum_id=8

And no one has even replied yet. Please if someone has any ideas let me know and if I get this to work I will post the code so others don't have to suffer :)

Thanks.

betajaen

20-12-2010 15:31:11

Alright. Let's start from the beginning, and see if I can help.

First up, versions? NxOgre, Critter/OGRE3DRendersystem/Custom, Ogre, PhysX?

shanefarris

20-12-2010 17:18:52

Thanks for you time. I don't remember the version, I downloaded NxOgre last July, so I think that was the latest stable release. I'm not using Critter because the engine I have needs to create the players. This code is the updated version of "Ragdoll Cake", the only changes I've done is just changes so it will build with the newer NxOgre version.

The only input is the scene node and the physics scene, so Critter is not needed.

CRagdoll::CRagdoll(String fileName, SceneNode *characterSN, String id, NxOgre::Scene *PHXScene, f32 bodyDensity)
{
m_CharacterNode = characterSN;
m_PHYSScene=PHXScene;
m_CharacterID=id;
m_PositionControllingBone=NULL;
m_BodyDensity=bodyDensity;
m_BonesCounter=0;

ConfigFile mRagDollCfgFile;
mRagDollCfgFile.loadFromResourceSystem(fileName, "General");

ConfigFile::SectionIterator seci = mRagDollCfgFile.getSectionIterator();

String secName, paramName, valueName;

while (seci.hasMoreElements())
{
secName = seci.peekNextKey();
ConfigFile::SettingsMultiMap *settings = seci.getNext();
ConfigFile::SettingsMultiMap::iterator i;

std::map<String, String> sectionData;

for (i = settings->begin(); i != settings->end(); ++i)
{
paramName = i->first;
valueName = i->second;

sectionData[paramName]=valueName;

}
if (secName!="")
{
_parseSectionData(secName, sectionData);
}


}

if (m_BonesCounter==15)
{

setControlToBones();
setAllBonesToManualControll(true);
setRagdollBindPose();

setAllBonesToManualControll(false);

addJoints();

//...as we dont have root bone attached to Bone Actor, we use Pelvis BA instead
if (!m_PositionControllingBone)
m_PositionControllingBone=getBoneBoneActorBindByName("Pelvis");

}
else
LogManager::getSingleton().logMessage( "Not enough bones declared in file: " + fileName + ". CRagdoll was not created!" );
}


Correction, this is based off of a super project called "Dead Cold" from a group of students I believe. They based there code off of Ragdoll Cake. Dead Cold is open and I think its on source forge, I recommend anyone new to PhysX to check it out, its a great project.

shanefarris

22-12-2010 16:47:33

If no one has any ideas on this, does anyone know of another ragdoll solution? Please don't suggest the PhysX demo, we are dealing with bones and animation, which makes things more complex.

Thanks.

shanefarris

30-12-2010 17:10:49

Does anyone have a working ragdoll class?

dcyuri

04-01-2011 12:53:22

Sounds like we need to make one. I'm game to help - will try a few things out and let you know of results.
Perhaps we can work together on it? I'm sure it would help many others.

I'm currently reviewing code from other engines(UE3 namely, its like pseudo-code lol), and about to "port"/"hack" it over. be back in a few/many hours with something buggy but working.

*edit:
http://www.ogre3d.org/addonforums/viewtopic.php?t=5289
looks quite promising. 0.o

shanefarris

14-01-2011 16:24:31

Anyone have any updates? There has got to be some implementation of ragdolls using the latest NxOgre.