Ragdolls and game character accurate collision/raycasting

ebol

09-09-2007 00:53:52

Hi,

many words was spoken about ragdolls and accurate game character collision/raycasting, but I didn't find anything "ready to use" in the forums. Thats why, I present you me code, nothing much really, but I hope it will help someone and maybe someone will help me to finish it ;)

UPDATE!
Both parts are working now, read further for some movies and updated code!


Anyway, what I did here is divided in two parts:

1) accurate game character collision/raycasting - I think many will agree, that using simple ex. capsule for checking if a character in the game world was hit is sometimes not enough. Now you can not only check if character was actually hit, but you can tell was it a head shot or maybe leg wound.

2) ragdoll simulation - you know it, you love it ;).... but unfortunately, its not ready yet, maybe someone will help me here.

Enough, how to use it:

you create ragdoll like this:

cRagDoll ragdoll("zombie.RD",zombie,"m1",mPhysXScene);

As arguments you pass:
cRagDoll(Ogre::String fileName, Ogre::SceneNode* characterSN, Ogre::String id, NxOgre::Scene* PHXScene);

where fileName is a text file with ragdoll data, like this one:

[Head]
boneName=neckcontrol
actorShape=capsule
dimensions=0.14 0.1 0.14
offset=0 0 0

[Torso]
boneName=Chest
actorShape=sphere
dimensions=0.22 0.22 0.22
offset=0.05 0 0.07

[Pelvis]
boneName=Waist
actorShape=sphere
dimensions=0.14 0.14 0.14
offset=0 0 0.1

...
...


and then, if you want to use it as a accurate collision model, you call cRagDoll::setControlToBones()
or, if you want to use it in a ragdoll simulation you call
cRagDoll::setControlToBoneActors()

Then, you just call cRagDoll::update().

--------------------------------------------------------------

The first part works great, here's a screenshot (nevermind the headless guy ;)):



But I'm stuck on part two, which is controlling ogre bones via nxogre shapes. I read and tried tons of solutions, but I simply can't get it working right. Any help will be appreciated - maybe it's just me being tired and all, but can help, it would be great :)

Anyway, here comes the code, I'm still working on it - look for usage details there, enjoy, any suggestions, comments, questions etc are welcome ;)

betajaen

09-09-2007 09:01:02

Well it's a very good start. I did some ragdoll code in NxOgre 0.6, it didn't work very well but it's worth a look. You could also look how they do it in OgreODE or OgreNewt as well, their physics code aside it's pretty much the same.

I'm planning for proper Ragdoll support in NxOgre 1.1. With quite a few features; support for biped and quadrupeds using some sort of advanced file format. Character system support; with some sort of IK system for the feet being placed onto the ground properly, and so forth.

Since it will be a while before I start on it; What ever you come up with, can I use? ;)

ebol

10-09-2007 23:24:40

What ever you come up with, can I use? :wink:

Sure you can use this, I'll be even glad if you do :) If I wouldn't want any one to use thisI wouldn't post this here.

Anyway, I made some progress, ragdolls are working now, they still are little buggy and need some work, as a the rest of code, but hey, its working and its usable ;)

I'll try to post some more screenshots or maybe a video tomorrow, and I'll update the code in the previous topic.

I'm planning for proper Ragdoll support in NxOgre 1.1.

...until then, I hope maybe my code will get in handy for someone.

ebol

13-09-2007 00:54:25

Ok, ragdolls are working good :), they may need few adjustments - better joints limits for example, but besides that, their fine.

I know I said I'll post latest code here a couple days ago, but I decided to clean it up a little and make it more general and friendly - but if someone would like it to see it know, let me know.

Anyway, the promised video's :

http://ebol.forall.pl/ragdoll1.avi
http://ebol.forall.pl/ragdoll2.avi
http://ebol.forall.pl/ragdoll3.avi


Tell me what you think :)

Aiursrage2k

13-09-2007 03:48:01

Looks pretty good, I would like to see the code when you have time.

betajaen

13-09-2007 09:19:40

Very good. That model keeps reminding me of Dr. Kleiner out of Half-Life 2 - without a head of course.

ebol

14-09-2007 01:10:03

Thanks guys :) I'm glad you like it. And also, betajaen, its good that this model reminds you a scientist/doctor because it suppose to be one - I'm not an artist and this model is done by my ;) - not from scratch, but it was still a lot to do.

Back to the topic, code works even better now, changed a few things, and I'm ready for an first official release.

Read the header file for usage instructions.

cRagDoll.h

#pragma once

#include "NxOgre.h"

struct sBoneBoneActorBind
{
Ogre::Bone* bone;
NxOgre::Actor* BoneActor;


Ogre::Vector3 BAoffset;
Ogre::String name;

Ogre::Quaternion BoneGlobalBindOrientation;
Ogre::Quaternion BoneActorGlobalBindOrientationInverse;
};

class cRagDoll
{
public:
//creates ragdoll/collision shapes for character based on definition from file
cRagDoll(Ogre::String fileName, Ogre::SceneNode* characterSN, Ogre::String id, NxOgre::Scene* PHXScene, Ogre::Real bodyDensity=985);

/*
this does NOT create a ragdoll!
Use it for diagnostics only, it saves to a file of a given name
all the bones in the skeleton (their names) and their lenght's.
*/
cRagDoll(Ogre::String outFileName, Ogre::SceneNode* characterSN);

//Bones from skeleton/animation have control over Bone Actors (collision bodies)
void setControlToBones();

//Bone Actors have controll over animation via skeleton bones (real ragdoll)
void setControlToBoneActors();

//Bone Actors need to be updated every rendering loop? Use with setControlToBones().
void setConstantlyUpdateBoneActors(bool c) { mConstantlyUpdateBoneActors=c;};

bool getConstantlyUpdateBoneActors() { return mConstantlyUpdateBoneActors;};

//call this to update simulation
void update();

/*
By default, the position of character node is controlled by the skeleton root bone,
if its controlled by an Bone Actor. If not, the bone that is controlled by
"Pelvis" Bone Actor is choosed.

Here you can override this and set the bone you want to use for controlling
character by specifing its name.
*/
void setCharacterPositionControllingBone(Ogre::String n);

protected:
void updateBoneActors();
void updateBones();
sBoneBoneActorBind* getBoneBoneActorBindByName(Ogre::String n);

//Helper's
void _setControlToBones();
void _setControlToBoneActors();
void _parseSectionData(Ogre::String secName, std::map<Ogre::String, Ogre::String> section);

void setRagdollBindPose();

//performs bone->setManuallyControlled(manual) on every bone in skeleton
void setAllBonesToManualControll(bool manual);

//performs bone->reset() on every bone in skeleton
void resetAllBones();

void addJoints();

sBoneBoneActorBind* mPositionControllingBone;

bool mControlToBones;
bool mControlToBoneActors;
bool mConstantlyUpdateBoneActors;

//Bone Actors and skeleton bones

/*
assuming we need only 15 Bone Actora to controll the body

(Head, Torso, Pelvis,
LeftUpArm, LeftLoArm, LeftHand,
RightUpArm, RightoArm, RightHand,
LeftUpLeg, LeftLoLeg, LeftFoot,
RightUpLeg, RightLoLeg, RightFoot)

they must be named exactly like this.
*/

sBoneBoneActorBind mBoneBoneActorBind[15];

std::map<Ogre::String, NxOgre::Joint*> mJoints;

Ogre::SceneNode *mCharacterSN;
NxOgre::Scene *mPHXScene;

NxOgre::NxString mCharacterID;

//Wikipedia claims that normal human body has a density of 985, so its a default value ;)
Ogre::Real mBodyDensity;

int mBonesCounter;


};



cRagDoll.cpp


#include "cRagDoll.h"

cRagDoll::cRagDoll(Ogre::String fileName, Ogre::SceneNode *characterSN, Ogre::String id, NxOgre::Scene *PHXScene, Ogre::Real bodyDensity)
{
mCharacterSN=characterSN;
mPHXScene=PHXScene;
mCharacterID=id;
mPositionControllingBone=NULL;
mBodyDensity=bodyDensity;
mBonesCounter=0;


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

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

Ogre::String secName, paramName, valueName;

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

std::map<Ogre::String, Ogre::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 (mBonesCounter==15)
{

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

setAllBonesToManualControll(false);

addJoints();

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

}
else
Ogre::LogManager::getSingletonPtr()->getDefaultLog()->logMessage(Ogre::String("Not enough bones declared in file: ")+fileName+Ogre::String(". Ragdoll was not created!"));
}

void cRagDoll::_parseSectionData(Ogre::String secName, std::map<Ogre::String, Ogre::String> section)
{
Ogre::Vector3 dimensions=Ogre::StringConverter::parseVector3(section["dimensions"]);
Ogre::Vector3 offset=Ogre::StringConverter::parseVector3(section["offset"]);
NxOgre::NxString density=Ogre::StringConverter::toString(mBodyDensity);

Ogre::Entity* ent=(Ogre::Entity*)mCharacterSN->getAttachedObject(0);

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

if (section["actorShape"]==Ogre::String("sphere"))
{
mBoneBoneActorBind[mBonesCounter].BoneActor=mPHXScene->createActor(mCharacterID+Ogre::String("BA")+secName,new NxOgre::SphereShape(dimensions.x),NxOgre::Pose(0,0,0),NxOgre::ActorParams("Density: "+density));
}

if (section["actorShape"]==Ogre::String("cube"))
{
mBoneBoneActorBind[mBonesCounter].BoneActor=mPHXScene->createActor(mCharacterID+Ogre::String("BA")+secName,new NxOgre::CubeShape(dimensions.x,dimensions.y,dimensions.z),NxOgre::Pose(0,0,0),NxOgre::ActorParams("Density: "+density));
}


if (section["actorShape"]==Ogre::String("capsule"))
{
mBoneBoneActorBind[mBonesCounter].BoneActor=mPHXScene->createActor(mCharacterID+Ogre::String("BA")+secName,new NxOgre::CapsuleShape(dimensions.x,dimensions.y),NxOgre::Pose(0,0,0),NxOgre::ActorParams("Density: "+density));
}

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

mBonesCounter++;


}

void cRagDoll::setControlToBones()
{
mControlToBones=true;

mControlToBoneActors=false;
_setControlToBones();
}

void cRagDoll::setControlToBoneActors()
{
mControlToBoneActors=true;

mControlToBones=false;
_setControlToBoneActors();
}

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

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

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

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

for (int i=0; i<15; i++)
{
mBoneBoneActorBind[i].BoneActor->clearActorFlag(NX_AF_DISABLE_COLLISION);
mBoneBoneActorBind[i].BoneActor->clearBodyFlag(NX_BF_KINEMATIC);
mBoneBoneActorBind[i].BoneActor->wakeUp();
mBoneBoneActorBind[i].BoneActor->setAngularDamping(1.0);
mBoneBoneActorBind[i].BoneActor->setLinearDamping(1.0);
}
}

void cRagDoll::updateBoneActors()
{
for(int i=0; i<15; i++)
{
//Get parent and child Positions
Ogre::Vector3 bonePos = mBoneBoneActorBind[i].bone->_getDerivedPosition();
Ogre::Vector3 nextBonePos = mBoneBoneActorBind[i].bone->getChild(0)->_getDerivedPosition();

//get vector difference between parent and child
Ogre::Vector3 difference = nextBonePos-bonePos;
Ogre::Vector3 forward = difference.normalisedCopy();

//Get bone Orientation and re-align
Ogre::Quaternion new_orient = Ogre::Vector3::UNIT_Y.getRotationTo(forward);

//mid point of bone
Ogre::Vector3 pos = bonePos + (forward * (difference.length() * 0.5));

//adjust Bone Actor placement
pos.x+=mBoneBoneActorBind[i].BAoffset.x;
pos.y+=mBoneBoneActorBind[i].BAoffset.y;
pos.z+=mBoneBoneActorBind[i].BAoffset.z;

//update Bone Actor
mBoneBoneActorBind[i].BoneActor->setGlobalPosition(pos+mCharacterSN->getWorldPosition());
mBoneBoneActorBind[i].BoneActor->setGlobalOrientation(new_orient);

//temporarly - Ageia bug
mBoneBoneActorBind[i].BoneActor->render(0);
}
}

void cRagDoll::updateBones()
{
Ogre::Quaternion PhysxRotation, OgreGlobalQuat, NodeRotationInverse = mCharacterSN->getOrientation().Inverse();
for(int i=0; i<15; i++)
{
PhysxRotation = mBoneBoneActorBind[i].BoneActor->getGlobalOrientation()* mBoneBoneActorBind[i].BoneActorGlobalBindOrientationInverse;
Ogre::Quaternion ParentInverse = NodeRotationInverse;
if ( mBoneBoneActorBind[i].bone->getParent())
ParentInverse = mBoneBoneActorBind[i].bone->getParent()->_getDerivedOrientation().Inverse() * NodeRotationInverse;
else
mCharacterSN->setPosition(mBoneBoneActorBind[i].BoneActor->getGlobalPosition() - mCharacterSN->getOrientation()*mBoneBoneActorBind[i].bone->getPosition());

OgreGlobalQuat = PhysxRotation * mBoneBoneActorBind[i].BoneGlobalBindOrientation;

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

}

Ogre::Vector3 newPos=mPositionControllingBone->BoneActor->getGlobalPosition() - mCharacterSN->getOrientation()*mPositionControllingBone->bone->getPosition() - mPositionControllingBone->BAoffset;

mCharacterSN->setPosition(newPos);
}

void cRagDoll::update()
{
if (mControlToBones)
updateBoneActors();

if (mControlToBoneActors)
updateBones();
}

void cRagDoll::addJoints()
{

NxOgre::JointParams jp;
jp.mHasLimits=true;
jp.mLowerLimit=-0.75*NxPi;
jp.mUpperLimit=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
Ogre::Vector3 pos=getBoneBoneActorBindByName("Head")->bone->_getDerivedPosition()+mCharacterSN->getWorldPosition();
NxOgre::Joint* joint=mPHXScene->createSphericalJoint(getBoneBoneActorBindByName("Head")->BoneActor,
getBoneBoneActorBindByName("Torso")->BoneActor,pos,sphJointParam);

//Chest
pos=getBoneBoneActorBindByName("Pelvis")->bone->_getDerivedPosition()+mCharacterSN->getWorldPosition();
joint=mPHXScene->createFixedJoint(getBoneBoneActorBindByName("Torso")->BoneActor,
getBoneBoneActorBindByName("Pelvis")->BoneActor);
//joint->setGlobalAxis(Ogre::Vector3::UNIT_Y);

//Left Leg
pos=getBoneBoneActorBindByName("LeftUpLeg")->bone->_getDerivedPosition()+mCharacterSN->getWorldPosition();
joint=mPHXScene->createSphericalJoint(getBoneBoneActorBindByName("Pelvis")->BoneActor,
getBoneBoneActorBindByName("LeftUpLeg")->BoneActor,pos,sphJointParam);
joint->setGlobalAxis(Ogre::Vector3::NEGATIVE_UNIT_Y);

//Left knee
pos=getBoneBoneActorBindByName("LeftLoLeg")->bone->_getDerivedPosition()+mCharacterSN->getWorldPosition();
joint=mPHXScene->createRevoluteJoint(getBoneBoneActorBindByName("LeftUpLeg")->BoneActor,
getBoneBoneActorBindByName("LeftLoLeg")->BoneActor,-Ogre::Vector3::UNIT_X,pos,jp);

//Left ankle
pos=getBoneBoneActorBindByName("LeftFoot")->bone->_getDerivedPosition()+mCharacterSN->getWorldPosition();
joint=mPHXScene->createRevoluteJoint(getBoneBoneActorBindByName("LeftLoLeg")->BoneActor,
getBoneBoneActorBindByName("LeftFoot")->BoneActor,Ogre::Vector3::UNIT_X,pos,jp);

//Right Leg
pos=getBoneBoneActorBindByName("RightUpLeg")->bone->_getDerivedPosition()+mCharacterSN->getWorldPosition();
joint=mPHXScene->createSphericalJoint(getBoneBoneActorBindByName("Pelvis")->BoneActor,
getBoneBoneActorBindByName("RightUpLeg")->BoneActor,pos,sphJointParam);
joint->setGlobalAxis(Ogre::Vector3::NEGATIVE_UNIT_Y);

//Right knee
pos=getBoneBoneActorBindByName("RightLoLeg")->bone->_getDerivedPosition()+mCharacterSN->getWorldPosition();
joint=mPHXScene->createRevoluteJoint(getBoneBoneActorBindByName("RightUpLeg")->BoneActor,
getBoneBoneActorBindByName("RightLoLeg")->BoneActor,-Ogre::Vector3::UNIT_X,pos,jp);

//Right ankle
pos=getBoneBoneActorBindByName("RightFoot")->bone->_getDerivedPosition()+mCharacterSN->getWorldPosition();
joint=mPHXScene->createRevoluteJoint(getBoneBoneActorBindByName("RightLoLeg")->BoneActor,
getBoneBoneActorBindByName("RightFoot")->BoneActor,Ogre::Vector3::UNIT_X,pos,jp);

//Left shoulder
pos=getBoneBoneActorBindByName("LeftUpArm")->bone->_getDerivedPosition()+mCharacterSN->getWorldPosition();
joint=mPHXScene->createSphericalJoint(getBoneBoneActorBindByName("Torso")->BoneActor,
getBoneBoneActorBindByName("LeftUpArm")->BoneActor, pos, sphJointParam2);
joint->setGlobalAxis(Ogre::Vector3::UNIT_X);

//Left elbow
pos=getBoneBoneActorBindByName("LeftLoArm")->bone->_getDerivedPosition()+mCharacterSN->getWorldPosition();
joint=mPHXScene->createRevoluteJoint(getBoneBoneActorBindByName("LeftUpArm")->BoneActor,
getBoneBoneActorBindByName("LeftLoArm")->BoneActor,Ogre::Vector3::UNIT_Y,pos,jp);

//Left hand
pos=getBoneBoneActorBindByName("LeftHand")->bone->_getDerivedPosition()+mCharacterSN->getWorldPosition();
joint=mPHXScene->createSphericalJoint(getBoneBoneActorBindByName("LeftLoArm")->BoneActor,
getBoneBoneActorBindByName("LeftHand")->BoneActor, pos, sphJointParam);

//Right shoulder
pos=getBoneBoneActorBindByName("RightUpArm")->bone->_getDerivedPosition()+mCharacterSN->getWorldPosition();
joint=mPHXScene->createSphericalJoint(getBoneBoneActorBindByName("Torso")->BoneActor,
getBoneBoneActorBindByName("RightUpArm")->BoneActor, pos, sphJointParam2);
joint->setGlobalAxis(Ogre::Vector3::NEGATIVE_UNIT_X);

//Right elbow
pos=getBoneBoneActorBindByName("RightLoArm")->bone->_getDerivedPosition()+mCharacterSN->getWorldPosition();
joint=mPHXScene->createRevoluteJoint(getBoneBoneActorBindByName("RightUpArm")->BoneActor,
getBoneBoneActorBindByName("RightLoArm")->BoneActor,Ogre::Vector3::UNIT_Y,pos,jp);

//Right hand
pos=getBoneBoneActorBindByName("RightHand")->bone->_getDerivedPosition()+mCharacterSN->getWorldPosition();
joint=mPHXScene->createSphericalJoint(getBoneBoneActorBindByName("RightLoArm")->BoneActor,
getBoneBoneActorBindByName("RightHand")->BoneActor, pos,sphJointParam);

}

void cRagDoll::setRagdollBindPose()
{
updateBoneActors();
for (int i=0; i<15; i++)
{
mBoneBoneActorBind[i].BoneGlobalBindOrientation = mBoneBoneActorBind[i].bone->_getDerivedOrientation();
mBoneBoneActorBind[i].BoneActorGlobalBindOrientationInverse = mBoneBoneActorBind[i].BoneActor->getGlobalOrientation().Inverse();
}
}

void cRagDoll::setAllBonesToManualControll(bool manual)
{
Ogre::Entity* e=(Ogre::Entity*)mCharacterSN->getAttachedObject(0);
Ogre::SkeletonInstance* skeletonInst = e->getSkeleton();
Ogre::Skeleton::BoneIterator boneI=skeletonInst->getBoneIterator();

while(boneI.hasMoreElements())
boneI.getNext()->setManuallyControlled(manual);
}

void cRagDoll::resetAllBones()
{
Ogre::Entity* e=(Ogre::Entity*)mCharacterSN->getAttachedObject(0);
Ogre::SkeletonInstance* skeletonInst = e->getSkeleton();
Ogre::Skeleton::BoneIterator boneI=skeletonInst->getBoneIterator();

while(boneI.hasMoreElements())
boneI.getNext()->reset();
}

sBoneBoneActorBind* cRagDoll::getBoneBoneActorBindByName(Ogre::String n)
{
for (int i=0; i<15; i++)
if (mBoneBoneActorBind[i].name==n)
return &mBoneBoneActorBind[i];

return NULL;
}

void cRagDoll::setCharacterPositionControllingBone(Ogre::String n)
{
mPositionControllingBone=getBoneBoneActorBindByName(n);
}

cRagDoll::cRagDoll(Ogre::String outFileName, Ogre::SceneNode* characterSN)
{
std::ofstream file(outFileName.c_str());
if (file)
{
Ogre::Entity* e=(Ogre::Entity*)characterSN->getAttachedObject(0);
Ogre::SkeletonInstance* skeletonInst = e->getSkeleton();
Ogre::Skeleton::BoneIterator boneI=skeletonInst->getBoneIterator();

file<<"Creating bone lenght information from:\n";
file<<"Mesh name: "<<e->getMesh()->getName()<<"\n";
file<<"Skeleton name: "<<skeletonInst->getName()<<"\n\n";

while(boneI.hasMoreElements())
{
Ogre::Bone* bone=boneI.getNext();
Ogre::String bName=bone->getName();

if (bone->getChild(0))
{
Ogre::Vector3 curr = bone->_getDerivedPosition();
Ogre::Vector3 next = bone->getChild(0)->_getDerivedPosition();

Ogre::Vector3 difference = next-curr;

//length of bone
Ogre::Real lenght = difference.length();

file<<bName<<"\t\t\t=\t"<<Ogre::StringConverter::toString(lenght,3)<<"\n";
if (!bone->getParent())
file<<bName<<" is a Root Bone!\n";
}
}
}
}


Cheers :)

Fumé

20-09-2007 23:18:01

Maybe I missed it - but which NxOgre version have you been using? 0.6? In that case we will probably try it out on one of our models :-)

Thanks,

Markus

ebol

20-09-2007 23:26:53

No, your right, I haven't actually written what version I'm using, I sometimes forget that there are other version that 0.9 ;) I'm guessing you are using 0.6, you can try this code with it, but I can't guaranty you anything, sorry.

kungfoomasta

20-09-2007 23:42:02

Hey ebol, just wanted to post and show support!

I need to finish up QuickGUI so I can start playing with this stuff. :lol:

ebol

21-09-2007 11:38:52

Thanks kungfoomasta, I appreciate it :)

Fumé

27-09-2007 22:16:51

So, we managed to ragdoll one of our characters. The joint limits need a little tweaking and I guess there is an issue with the mass or friction or something. But other than that it's awesome :-) We'll show some screens in a little while...

Now we have it running with 0.9. Unfortunately, our app which has grown a little big is 0.6.

Can any of you NxOgre gurus tell or maybe give it a quick try whether the ragdoll code can be fitted to work with 0.6? That would be so helpful!

In case this doesn't work out. Betajaen, can you give us any indication of how difficult it might be to move our app from 0.6 to 0.9. Like, only takes minor changes to some method names, or major changes that may take a long time to make work.

Really appreciate it!

Aiursrage2k

28-09-2007 00:23:09

Awesome, awesome to the max. Thanks alot!

regarding the porting of 6 to 9 there is already a thread that might be some help.
http://www.ogre3d.org/phpBB2addons/view ... 7cd68ed79b

ebol

05-10-2007 12:27:04

I totally missed those two last post, sorry :oops:

@Fum�
Like I said, joints limits need tweaking, but there shouldn't be any problems with mass, unless you created your ragdoll right - mass is calculated from bodies using given density.

But, I forgot to mention one thing, I use slightly different material on my ragdoll - its a modified copy of the default material:


NxOgre::Material* defaultMaterial=mPhysXScene->getMaterial(0);

defaultMaterial->setRestitution(0.5);
defaultMaterial->setStaticFriction(0.5);
defaultMaterial->setDynamicFriction(0.5);


I'll update the code in a while. And if you'll get satisfying results with joints limits, please post them here.


Anyway, I'm glad that someone tried this stuff and that you like it guys - post some screen shots :)

Caphalor

10-10-2007 21:46:07

Wow, really good work! Here are my first results: Video
But I have a problem: When the bones are synchronized with the Actors and the Orientation of the SceneNode isn't "standard", I get wired results: Image
I have only one question: Does that work in your program? Because I changed a couple of things in your class and I want to know whether that could be responsible for it. Of course I already tried a lot of things, but I'm not very familiar with quaternions. :(

ebol

11-10-2007 12:20:42

Ah, a video at last ;)

Caphalor, what do you mean by Orientation off the SceneNode isn't "standard"And I can't tell you if the changes you made may cause problems unless you tell my what you did :)

But after looking at your screenshot, does your ragdoll fits its visual representation? It looks like some of Actors are too small, that could produce those unnatural stretches.

Romep

09-02-2008 22:29:47

i get error msg:



NxOgre::Error::reportError#78T0 F0

PhysX Error (NXE_INVALID_PARAMETER) 'Supplied NxActorDesc is not valid. createActor returns NULL.' in line 743 of g:\scm\release\PhysX_2.7.3\novodex\SDKs\Physics\src\NpScene.cpp






NxOgre::Actor::_createActor#321T0 F0

Creation of Actor with the identifier 'rd1BAPelvis' failed.




NxOgre (NxOgre 0.9-38.Debug) Started, working with:

- PhysX => 2.7.3
- Ogre => 1.4.5 'Eihort'
- Platform => Windows Debug



can anyone help? did everything like described.

skumancer

01-03-2008 10:31:45

Thanks a lot for your hard work ebol.

I have two questions:

1. How do I avoid my character's mesh from going through the floor or other meshes? I already have ragdolls working, but when I activate them:mRagdoll->setControlToBoneActors()the character falls down and most of its body goes through the floor (although in the PhysX debugger the actors are correctly above the ground).

2. What joint limits would you recommend for a normal human? I don't know why the arms of my character get bent around (twisting around their Y axis).

Otherwise, its working really good. I modified the class a little so that I could selectively activate ragdolls on some bones only.

Thanks,

Ricardo :D

SiWi

02-03-2008 08:32:53

To your first question Romep:
This means that your physical floor doesn´t fit your visual represantation.