IK with Ogre
-
- Kobold
- Posts: 29
- Joined: Sun Apr 15, 2007 1:35 am
IK with Ogre
Hello,
I did some character inverse knematic with a personal project and since I didn't have a real animation system (loading / playing / blending animations) I'd like to redo this project using Ogre.
My goal is to create a rigged character in Ogre as an artist is able to rig a character in 3dsmax or any other DCC application.
In 3dsmax and in my project I do this by affecting controllers to the skeleton bones :
- IK limb solver (for arms and legs)
- Orientation constraint controller (for hands and feets)
- LookAt controller (head, torso)
- hierarchy
- ...
So I was wondering what architecture I should use to create this in Ogre.
Would you suggest to use the Ogre controllers or something else ?
I did some character inverse knematic with a personal project and since I didn't have a real animation system (loading / playing / blending animations) I'd like to redo this project using Ogre.
My goal is to create a rigged character in Ogre as an artist is able to rig a character in 3dsmax or any other DCC application.
In 3dsmax and in my project I do this by affecting controllers to the skeleton bones :
- IK limb solver (for arms and legs)
- Orientation constraint controller (for hands and feets)
- LookAt controller (head, torso)
- hierarchy
- ...
So I was wondering what architecture I should use to create this in Ogre.
Would you suggest to use the Ogre controllers or something else ?
-
- Kobold
- Posts: 29
- Joined: Sun Apr 15, 2007 1:35 am
Since I'd like to blend the IK with an existing animation, maybe the best way would be to wrap the IK in an AnimationState.
It would make a procedural animationState that I could blend for free with standard animation.
I'm going to try that.
It would make a procedural animationState that I could blend for free with standard animation.
I'm going to try that.
Last edited by noche on Fri Sep 21, 2007 10:39 am, edited 1 time in total.
-
- OGRE Retired Moderator
- Posts: 9481
- Joined: Fri Feb 18, 2005 2:03 am
- Location: Dublin, CA, US
- x 22
-
- Kobold
- Posts: 29
- Joined: Sun Apr 15, 2007 1:35 am
I'm a bit new to Ogre, so don't hesitate to tell me if I miss something.
Here is how I started :
I've seen Ogre have 3 main kind of animations :
- NumericAnimationTrack
- NodeAnimationTrack
- VertexAnimationTrack
Those tracks can be created from an Animation instance, itself created from a Skeleton instance. I find a little anoying that the Ogre::Animation must create itself the Ogre::AnimationsTracks because this mean that I cannot add a new kind of animation track. A method Animation::addAnimationTrack(AnimationTrack*) would be nice since anyone could create his own AnimationTrack.
So to do my tests I have to override Skeleton Animation and AnimationTrack :
This is inside this method that all the magic should happend : ProceduralAnimationTrack::getInterpolatedKeyFrame.
A keyframe should be calculated according the IK contraints (an some other kind of contraints too). This way, the procedural animation could be blended with other regular animations. For now, I tried to create a key inside this method with some constant rotation to see if it works :
To test it, I tryed to update the animation by doing this :
But I dont see any visual changes on my Entity. The bone is not moving. If you have any idea, of how to update the entity ? (I checked I pass in ProceduralAnimationTrack::getInterpolatedKeyFrame and ProceduralAnimationTrack::apply)
The apply method is copy pasted from NodeAnimationTrack::apply :
Here is the rest of the cpp code...
Here is how I started :
I've seen Ogre have 3 main kind of animations :
- NumericAnimationTrack
- NodeAnimationTrack
- VertexAnimationTrack
Those tracks can be created from an Animation instance, itself created from a Skeleton instance. I find a little anoying that the Ogre::Animation must create itself the Ogre::AnimationsTracks because this mean that I cannot add a new kind of animation track. A method Animation::addAnimationTrack(AnimationTrack*) would be nice since anyone could create his own AnimationTrack.
So to do my tests I have to override Skeleton Animation and AnimationTrack :
Code: Select all
//-----------------------------------------------------------------------------
class ProceduralAnimationTrack : public AnimationTrack
{
public:
ProceduralAnimationTrack(Animation* parent, unsigned short handle, Node* target);
void apply(const TimeIndex& timeIndex, Real weight = 1.0, Real scale = 1.0f);
void getInterpolatedKeyFrame(const TimeIndex& timeIndex, KeyFrame* kf) const;
KeyFrame* createKeyFrameImpl(Real time);
private:
Node* node;
};
//-----------------------------------------------------------------------------
class ProceduralAnimation : public Ogre::Animation
{
public:
ProceduralAnimation(const String& name);
void apply(Real timePos, Real weight, Real scale);
ProceduralAnimationTrack* createProceduralTrack(unsigned short handle, Node* target);
bool hasProceduralTrack(unsigned short handle) const;
private:
typedef std::map<unsigned short, ProceduralAnimationTrack*> ProceduralTrackList;
typedef ConstMapIterator<ProceduralTrackList> ProcTrackIterator;
ProceduralTrackList mProceduralTrackList;
};
//-----------------------------------------------------------------------------
class ProceduralSkeleton : public Ogre::Skeleton
{
public:
ProceduralSkeleton(Skeleton* skeleton);
ProceduralAnimation* createProceduralAnimation(const String& name);
private:
Skeleton* _skeleton;
};
A keyframe should be calculated according the IK contraints (an some other kind of contraints too). This way, the procedural animation could be blended with other regular animations. For now, I tried to create a key inside this method with some constant rotation to see if it works :
Code: Select all
void ProceduralAnimationTrack::getInterpolatedKeyFrame(const TimeIndex& timeIndex, KeyFrame* kf) const
{
TransformKeyFrame* kret = static_cast<TransformKeyFrame*>(kf);
kret->setRotation(Quaternion(Degree(50), Vector3(1, 0, 0)));
kret->setTranslate(Vector3::ZERO);
kret->setScale(Vector3(1, 1, 1));
}
Code: Select all
Bone* _boneLeftHand;
Skeleton* skeleton;
ProceduralSkeleton* _proceduralSkeleton;
ProceduralAnimation* _proceduralAnimation;
ProceduralAnimationTrack* _trackLeftHand
init :
_proceduralSkeleton = new ProceduralSkeleton(_skeleton);
_proceduralAnimation = _proceduralSkeleton->createProceduralAnimation("BipedAnimation");
_trackLeftHand= _proceduralAnimation->createProceduralTrack(0, _boneLeftHand);
update:
_proceduralAnimation->apply(0.0f, 1.0f, 1.0f);
The apply method is copy pasted from NodeAnimationTrack::apply :
Code: Select all
void ProceduralAnimationTrack::apply(const TimeIndex& timeIndex, Real weight, Real scale)
{
TransformKeyFrame kf(0, timeIndex.getTimePos());
getInterpolatedKeyFrame(timeIndex, &kf);
// add to existing. Weights are not relative, but treated as absolute multipliers for the animation
Vector3 translate = kf.getTranslate() * weight * scale;
node->translate(translate);
// interpolate between no-rotation and full rotation, to point 'weight', so 0 = no rotate, 1 = full
Quaternion rotate;
Animation::RotationInterpolationMode rim =
mParent->getRotationInterpolationMode();
if (rim == Animation::RIM_LINEAR)
{
rotate = Quaternion::nlerp(weight, Quaternion::IDENTITY, kf.getRotation(), true);
}
else //if (rim == Animation::RIM_SPHERICAL)
{
rotate = Quaternion::Slerp(weight, Quaternion::IDENTITY, kf.getRotation(), true);
}
node->rotate(rotate);
Vector3 scl = kf.getScale();
// Not sure how to modify scale for cumulative anims... leave it alone
//scale = ((Vector3::UNIT_SCALE - kf.getScale()) * weight) + Vector3::UNIT_SCALE;
if (scale != 1.0f && scl != Vector3::UNIT_SCALE)
{
scl = Vector3::UNIT_SCALE + (scl - Vector3::UNIT_SCALE) * scale;
}
node->scale(scl);
}
-
- OGRE Retired Moderator
- Posts: 9481
- Joined: Fri Feb 18, 2005 2:03 am
- Location: Dublin, CA, US
- x 22
Animations are blended using AnimationState -- you get them from the Entity. Bones either are controlled by an animation track, or they aren't -- I don't really know if what you are doing there will work or not, but if you have named animations on an entity that can be found with getAnimationState() then you can blend them together.
-
- Kobold
- Posts: 29
- Joined: Sun Apr 15, 2007 1:35 am
Do you know if there is a way to add a custom animation type or should I modify ogre source code ?xavier wrote:Animations are blended using AnimationState -- you get them from the Entity. Bones either are controlled by an animation track, or they aren't -- I don't really know if what you are doing there will work or not, but if you have named animations on an entity that can be found with getAnimationState() then you can blend them together.
-
- Kobold
- Posts: 29
- Joined: Sun Apr 15, 2007 1:35 am
Finaly I modified Ogre source code. I added a procedual animation track that inherit from NodeAnimationTrack :
It has a controller. The controller will be responsible for calculating the keyframe. It must implement this interface :
I added the creation of this kind of animation track in the Animation class.
The track is added in the mNodeTrackList, since a ProceduralAnimationTrack is a NodeAnimationTrack :
Here is a part of the applyToNode code. It's the same as NodeAnimationTrack but it doesn't check if a key exist, and it asks the controller to set the key.
Finaly here is a test of a ProceduralAnimationTrackController that rotate and translate a bone :
Also the code that create the procedural animation :
Now its the time to do some IK 
Code: Select all
class _OgreExport ProceduralAnimationTrack : public NodeAnimationTrack
{
public:
ProceduralAnimationTrack(Animation* parent, unsigned short handle, Node* targetNode, ProceduralAnimationTrackController* controller);
virtual ~ProceduralAnimationTrack();
virtual void apply(const TimeIndex& timeIndex, Real weight = 1.0, Real scale = 1.0f);
virtual void applyToNode(Node* node, const TimeIndex& timeIndex, Real weight = 1.0, Real scale = 1.0f);
virtual void getInterpolatedKeyFrame(const TimeIndex& timeIndex, KeyFrame* kf) const;
protected:
KeyFrame* createKeyFrameImpl(Real time);
ProceduralAnimationTrackController* _controller;
};
Code: Select all
class _OgreExport ProceduralAnimationTrackController
{
public:
virtual void getInterpolatedKeyFrame(const TimeIndex& timeIndex, KeyFrame* kf) const = 0;
};
The track is added in the mNodeTrackList, since a ProceduralAnimationTrack is a NodeAnimationTrack :
Code: Select all
ProceduralAnimationTrack* Animation::createProceduralTrack(unsigned short handle, Node* node, ProceduralAnimationTrackController* controller)
{
if (hasNodeTrack(handle))
{
OGRE_EXCEPT(Exception::ERR_DUPLICATE_ITEM,
"Node track with the specified handle " +
StringConverter::toString(handle) + " already exists",
"Animation::createProceduralAnimationTrack");
}
ProceduralAnimationTrack* ret = new ProceduralAnimationTrack(this, handle, node, controller);
mNodeTrackList[handle] = ret;
ret->setAssociatedNode(node);
return ret;
}
Code: Select all
void ProceduralAnimationTrack::applyToNode(Node* node, const TimeIndex& timeIndex, Real weight, Real scl)
{
// if ( mKeyFrames.empty() || !weight || !node)
if (!weight || !node)
return;
TransformKeyFrame kf(0, timeIndex.getTimePos());
_controller->getInterpolatedKeyFrame(timeIndex, kf);
....
}
Code: Select all
class MyController : public ProceduralAnimationTrackController
{
void getInterpolatedKeyFrame(const TimeIndex& timeIndex, KeyFrame* kf) const
{
static float angle = 0;
angle += 0.1f;
TransformKeyFrame* kret = static_cast<TransformKeyFrame*>(kf);
kret->setRotation(Quaternion(Degree(angle), Vector3(1, 0, 0)));
kret->setTranslate(Vector3(Math::Sin(angle), 0, 0));
kret->setScale(Vector3(1, 1, 1));
}
}
Also the code that create the procedural animation :
Code: Select all
_procAnimation = _skeleton->createAnimation("BipedAnimation", 1.0f);
_leftArmTrack = _procAnimation->createProceduralTrack(leftArm->getHandle(), leftArm, &armController);
_entity->refreshAvailableAnimationState();
AnimationState* state = _entity->getAnimationState("BipedAnimation");
state->setEnabled(true);
state->setWeight(0.5f);

-
- OGRE Retired Moderator
- Posts: 2060
- Joined: Thu Feb 26, 2004 12:11 am
- Location: Toronto, Canada
- x 3
Sweet, can't wait to see what you come up with!
I'm actually thinking of using the animation system to blend between ragdoll physics and animations. For example, let's say a character can be shot where he temporarily falls down using ragdoll, then stands back up using an animation and returns to normal.
It'd also be interesting to see if it's possible to mix them together, so while a character is falling he's waving his arms, etc. though I believe that would require something different (attempt to apply forces to the ragdoll physics based on an animation).
I'm actually thinking of using the animation system to blend between ragdoll physics and animations. For example, let's say a character can be shot where he temporarily falls down using ragdoll, then stands back up using an animation and returns to normal.
It'd also be interesting to see if it's possible to mix them together, so while a character is falling he's waving his arms, etc. though I believe that would require something different (attempt to apply forces to the ragdoll physics based on an animation).
Last edited by Falagard on Thu Sep 13, 2007 4:30 pm, edited 1 time in total.
-
- Kobold
- Posts: 29
- Joined: Sun Apr 15, 2007 1:35 am
I wonder if there is a way to specify in Ogre that an animation state is played in an additive mode with another animation ? It seems weights are only used to interpolate (average) between different animations.
It would be nice to have the choice of the blending type. This way a walking animation could be used for the lower body, and a shooting animation or a procedural animation for the upper body.
It would be nice to have the choice of the blending type. This way a walking animation could be used for the lower body, and a shooting animation or a procedural animation for the upper body.
-
- Kobold
- Posts: 29
- Joined: Sun Apr 15, 2007 1:35 am
-
- OGRE Retired Moderator
- Posts: 2060
- Joined: Thu Feb 26, 2004 12:11 am
- Location: Toronto, Canada
- x 3
There's a flag that does this, I believe, when blending animations. Or at least there's a flag that definitely does somethingI wonder if there is a way to specify in Ogre that an animation state is played in an additive mode with another animation ? It seems weights are only used to interpolate (average) between different animations.

Nice video by the way

-
- Kobold
- Posts: 29
- Joined: Sun Apr 15, 2007 1:35 am
I didn't find the one that does something about additive animations. There is the Animation::setInterpolationModeFalagard wrote: There's a flag that does this, I believe, when blending animations. Or at least there's a flag that definitely does something
that define how it should interpolate (linear or spline) but its still about blending (averaging) N animations.
I may have to add an Additive mode in ogre, otherwise my work will be almost useless.
-
- OGRE Retired Moderator
- Posts: 9481
- Joined: Fri Feb 18, 2005 2:03 am
- Location: Dublin, CA, US
- x 22
There is ANIMBLEND_CUMULATIVE and ANIMBLEND_AVERAGE -- it's on the Skeleton class though.
Note the Eihort notes on the difference:
Note the Eihort notes on the difference:
ANIMBLEND_AVERAGE now only rebalances animation weights when the cumulative weight exceeds 1.0f. Therefore the only difference between ANIMBLEND_CUMULATIVE and ANIMBLEND_AVERAGE is now when you have total animation weights above this value, when all weights will be renormalised to sum to 1.0f. This means you can have weightings under 1.0f in average blending mode which is more convenient.
-
- OGRE Retired Moderator
- Posts: 2060
- Joined: Thu Feb 26, 2004 12:11 am
- Location: Toronto, Canada
- x 3
-
- Kobold
- Posts: 29
- Joined: Sun Apr 15, 2007 1:35 am
I missed this one
Thx a lot guys !
I also wonder what would be the way to get the inital world position and orientation of a bone, at any time. Right now I must save the position and orientation before the skeleton gets animated :
_initalWorldPosition = bone->getWorldPosition();
Is there a way to get it while the animation is played ? I think Bone::getInitialPosition returns local coordinates, but I would need them in world space.

I also wonder what would be the way to get the inital world position and orientation of a bone, at any time. Right now I must save the position and orientation before the skeleton gets animated :
_initalWorldPosition = bone->getWorldPosition();
Is there a way to get it while the animation is played ? I think Bone::getInitialPosition returns local coordinates, but I would need them in world space.
-
- OGRE Retired Moderator
- Posts: 2060
- Joined: Thu Feb 26, 2004 12:11 am
- Location: Toronto, Canada
- x 3
Convert them to world space then. Take a look at Node's code for converting local to world space. Might have been SceneNode. Anyhow, one of them does it to keep the world position and orientation cached variables up to date.noche wrote:I missed this oneThx a lot guys !
I also wonder what would be the way to get the inital world position and orientation of a bone, at any time. Right now I must save the position and orientation before the skeleton gets animated :
_initalWorldPosition = bone->getWorldPosition();
Is there a way to get it while the animation is played ? I think Bone::getInitialPosition returns local coordinates, but I would need them in world space.
-
- Kobold
- Posts: 29
- Joined: Sun Apr 15, 2007 1:35 am
Yes I know I could convert them to world space, but this sound overkill because this means to runs all the hierarchy from my bone to the root, to multiply all the transformations. And since the result I want is constant, I was hoping there was some cache in ogre that store the initial world transformations of the skeleton.Falagard wrote:Convert them to world space then.
Thanks for your answer.
-
- Kobold
- Posts: 29
- Joined: Sun Apr 15, 2007 1:35 am
Here is a little video of my results for now : video
The skeleton is using a cumulative blend mode.
First there is only an IK animation played.
Second there is the IK animation and an animation exported from 3dsmax that has only rotation keyframes on the arm.
Third there is the IK animation and another animation exported from 3dsmax that move the spine.
The result is still not really good foor the 3rd test, I guess I dont use the right world matrices. The nice thing is to be able to play with animation state weights to use more or less the IK animation.
The skeleton is using a cumulative blend mode.
First there is only an IK animation played.
Second there is the IK animation and an animation exported from 3dsmax that has only rotation keyframes on the arm.
Third there is the IK animation and another animation exported from 3dsmax that move the spine.
The result is still not really good foor the 3rd test, I guess I dont use the right world matrices. The nice thing is to be able to play with animation state weights to use more or less the IK animation.
-
- OGRE Retired Moderator
- Posts: 9481
- Joined: Fri Feb 18, 2005 2:03 am
- Location: Dublin, CA, US
- x 22
I really like that you've taken this on -- it's a different direction than what I had planned to do but it's far simpler, less intrusive and a more elegant solution.
If you need help analyzing the problem, go ahead and post again some of the code in question.
I hope in the end that you plan to submit a patch to Ogre for this -- it really does solve a whole set of problems that the current Ogre animation system cannot address.
If you need help analyzing the problem, go ahead and post again some of the code in question.
I hope in the end that you plan to submit a patch to Ogre for this -- it really does solve a whole set of problems that the current Ogre animation system cannot address.
-
- OGRE Retired Moderator
- Posts: 2060
- Joined: Thu Feb 26, 2004 12:11 am
- Location: Toronto, Canada
- x 3
Awesome!
So, for each bone you have to set up joint constraints - only rotate along a certain axis within certain angles, etc.
Very very nice. Are you planning on sharing the code when you're finished?
I assume this could be used for walking on uneven ground so the feet touch the ground at the proper place, as well as for things like turning the head in a direction of interest, such as something you can pick up, or turning the whole torso for something like.. aiming a gun? Though I assume for it to look right in most cases it'd be a combination of animation blending between two animations, as well as the IK blending.
Anyhow, very impressive!
So, for each bone you have to set up joint constraints - only rotate along a certain axis within certain angles, etc.
Very very nice. Are you planning on sharing the code when you're finished?
I assume this could be used for walking on uneven ground so the feet touch the ground at the proper place, as well as for things like turning the head in a direction of interest, such as something you can pick up, or turning the whole torso for something like.. aiming a gun? Though I assume for it to look right in most cases it'd be a combination of animation blending between two animations, as well as the IK blending.
Anyhow, very impressive!
-
- OGRE Contributor
- Posts: 2087
- Joined: Thu Mar 03, 2005 7:11 am
- Location: WA, USA
- x 16
-
- OGRE Retired Moderator
- Posts: 4011
- Joined: Fri Sep 19, 2003 6:28 pm
- Location: Burgos, Spain
- x 2