Skip to main content
GameDev.net gamedev.net
🔒 Locked

Animation-transitioning

Started by gnmgrl Dec 9, 2014 at 12:05 AM 4 replies 1.8k views
Original Post
gnmgrl
gnmgrl

Well met!

I have a question regarding the transitioning between two (bone-based) animations.

As an example, image a character running. Right in the middle of the stepping-cycle, with one foot in the air, the player decides to cast a spell.

If I now just start the casting-animation, a very noticeable jump is happening. Therefore, I have to transition from one the current skeleton to the first frame of the new one.

I expected that to be done like this:


Animation n;
for(int i=0; i<currentSkeleton.numBones; i++){ 
    KeyFrame start, end;
    AnimationTrack t;
    start.value = currentAnimation.Frames[currentFrame].matrices[i];
    start.time = 0.0f;
    end.value = nextAnimation.Frames[0].matrices[i];
    end.time = animationTransitionDuration;
    t.add(start);
    t.add(end);
    n.add(t);
}
//The Animation is interpolating like this:
float interpolation = (currentTime - lastKey.time) / (1000.0f/FPS);
*valueToModify = lastKey.value * (1.0f - interpolation) + nextKey.value * interpolation;

The final result is kind of right, but not really. Image a foot and a leg, with the foot bend upwards. Trying to transition that to a standing leg results in the foot becoming small and wierd, and then getting bigger again to stretch to the final pose.

I think this is what I am supposed to see with this method of animation-blending, so my question is:

What better method is there to blend from one animation into the other?

Or I am doing the correct thing and just messed something up?

Thank you for your time!

Buckeye
Buckeye

You don't mention what API you're using (Animation, AnimationTrack, and KeyFrame are unknown object types at this point), so it's impossible to tell what the expected results are for AnimationTrack.add( KeyFrame ) and Animation.add( AnimationTrack ).

However, just making a guess from only what you've posted, the equation for valueToModify looks suspicious. I.e., if lastKey.value and nextKey.value are matrices, how those matrices are composed being unknown, the purpose of multiplying each matrix by a scalar, and then adding those two results, is unclear.

A more common approach is with keyframes to be comprised of separate scaling, rotation and translation values. Interpolation between two keyframes is then done by interpolating the component values and then, if a matrix result is required, composing a matrix from the results. E.g., in pseudo-code:


scale = Interpolate( lastKey.scale, nextKey.scale, interpolationValue);
rotation = SLERP( lastKey.rotation, nextKey.rotation, interpolationValue);
translation = Interpolate( lastKey.translation, nextKey.translation, interpolationValue);
matrix = ComposeMatrix( scale, rotation, translation );


Commonly, in each keyframe, scale and translation are stored as vectors, and rotation is a quaternion.

Alternatively, depending on how the rest of your code is implemented, you could interpolate vertex positions. E.g., given an input vertex V,


Vlast = V * lastKey.value;
Vnext = V * nextKey.value;
Vresult = Vlast * (1.0f - interpolation) + Vnext * interpolation;


This article, which discusses blending animations together, may give you a better idea how the above processes can be implemented.

Please don't PM me with questions. Post them in the forums for everyone's benefit, and I can embarrass myself publicly. You don't forget how to play when you grow old; you grow old when you forget how to play.
gnmgrl
gnmgrl

I'm sorry, I can see the code beeing confusing. I tried to keep it simple, but that doesn't seem to be a good idea.

I am not storing the translation + rotation and then composing matrices from it each frame, I am simply using the finished matrix for each bone from the start.

Therefore, I am animating the 12 numbers of the matrix that change (rightmost numbers appear to be irrelevant).

Those 12 numbers are the ones I am interpolating between. Is this ok to do, or am I screwing something up in doing so?

Ashaman73
Ashaman73




I am not storing the translation + rotation and then composing matrices from it each frame, I am simply using the finished matrix for each bone from the start.

This will simply not work, if you want more advanced stuff like animation blending. The interpolation/blending between bones is always done locally, therefor if you do it globally(=working with the final matrix), bones will suddenly start to travel in really funny ways (especially extremities like hands/feets etc.).The global interpolation could result in temporary disconnected bones which looks like shrinking/stretching of mesh parts.

Aressera
Aressera

In addition to hierarchical transformations, if you do not enforce things like orthonormality in the matrix you will get strange stretching/shearing effects if you try to interpolate large rotations.

Sector0
Sector0

It seems that you are using bone transformation matrices in world or modelling space as Ashaman73 mentioned. All of the professional animation systems store the keyframe matrices relative to binding pose or maybe reference pose. During animation blending the keyframe matrices are being interpolated relative to ref or binding pose and the final pose will be calculated in the modeling or world space to be passed to the skinned mesh renderer.

Maybe you are calculating the blended pose in the world or modelling space and add it to the animation track and the animation system you are using is assuming that your blended transformation is calculated in local space and then it adds that local transformation to the final world space matrix.

For a more accurate blending you can interpolate position rotation and scale tracks separately just like what Buckeye suggested. However the way you are interpolating is not going to produce bad results on scale and translation if you are interpolating between two correct matrices. It can cause non-linear interpolation on rotations because you are using LERP instead of SLERP.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.