Engines/FlatRedBallXNA/FlatRedBall.Content/ModelAnimation/AnimationProcessor.cs
/// <summary>
/// Interpolates an AnimationContent object to 60 fps.
/// </summary>
/// <param name="input">The AnimationContent to interpolate.</param>
/// <returns>The interpolated AnimationContent.</returns>
Interpolates an AnimationContent object to 60 fps.
Interpolates an AnimationContent object to 60 fps .
public virtual AnimationContent Interpolate(AnimationContent input)
        {
            AnimationContent output = new AnimationContent();
            long time = 0;
            long animationDuration = input.Duration.Ticks;
            foreach (KeyValuePair<string, AnimationChannel> c in input.Channels)
            {
                if (c.Value[c.Value.Count - 1].Time.Ticks > animationDuration)
                    animationDuration = c.Value[c.Value.Count - 1].Time.Ticks;
            }
            foreach (KeyValuePair<string, AnimationChannel> c in input.Channels)
            {
                time = 0;
                string channelName = c.Key;
                AnimationChannel channel = c.Value;
                AnimationChannel outChannel = new AnimationChannel();
                int currentFrame = 0;
                while (time <= animationDuration)
                {
                    AnimationKeyframe keyframe;
                    if (time >= animationDuration)
                    {
                        time = animationDuration;
                        keyframe = new AnimationKeyframe(new TimeSpan(time),
                            channel[channel.Count - 1].Transform);
                    }
                    else
                    {
                        if (channel.Count == 1 || time < channel[0].Time.Ticks)
                        {
                            keyframe = new AnimationKeyframe(new TimeSpan(time), channel[0].Transform);
                        }
                        else if (channel[channel.Count - 1].Time.Ticks <= time)
                        {
                            keyframe = new AnimationKeyframe(new TimeSpan(time), channel[channel.Count - 1].Transform);
                        }
                        else 
                        {
                            while (channel[currentFrame + 1].Time.Ticks < time)
                            {
                                currentFrame++;
                            }
                            double interpNumerator = (double)(time - channel[currentFrame].Time.Ticks);
                            double interpDenom = (double)(channel[currentFrame + 1].Time.Ticks - channel[currentFrame].Time.Ticks);
                            double interpAmount = interpNumerator / interpDenom;
                            if (channel[currentFrame + 1].Time.Ticks - channel[currentFrame].Time.Ticks
                                <= ContentUtil.TICKS_PER_60FPS * 1.05)
                            {
                                keyframe = new AnimationKeyframe(new TimeSpan(time),
                                    Matrix.Lerp(
                                    channel[currentFrame].Transform,
                                    channel[currentFrame + 1].Transform,
                                    (float)interpAmount));
                            }
                            else 
                                if (channel[currentFrame].Transform != channel[currentFrame + 1].Transform)
                            {
                                keyframe = new AnimationKeyframe(new TimeSpan(time),
                                    ContentUtil.SlerpMatrix(
                                    channel[currentFrame].Transform,
                                    channel[currentFrame + 1].Transform,
                                    (float)interpAmount));
                            }
                            else 
                            {
                                keyframe = new AnimationKeyframe(new TimeSpan(time),
                                    channel[currentFrame].Transform);
                            }
                        }
                    }
                    outChannel.Add(keyframe);
                    time += ContentUtil.TICKS_PER_60FPS;
                }
                if (outChannel[outChannel.Count - 1].Time.Ticks < animationDuration)
                {
                    outChannel.Add(new AnimationKeyframe(
                        TimeSpan.FromTicks(animationDuration),
                        channel[channel.Count - 1].Transform));
                }
                outChannel.Add(new AnimationKeyframe(input.Duration, 
                    channel[channel.Count-1].Transform));
                output.Channels.Add(channelName, outChannel);
            }
            output.Duration = TimeSpan.FromTicks(animationDuration);
            return output;
        }
public virtual AnimationContent Interpolate ( AnimationContent input ) { AnimationContent output = new AnimationContent ( ) ; long time = 0 ; long animationDuration = input . Duration . Ticks ; foreach ( KeyValuePair < string , AnimationChannel > c in input . Channels ) { if ( c . Value [ c . Value . Count - 1 ] . Time . Ticks > animationDuration ) animationDuration = c . Value [ c . Value . Count - 1 ] . Time . Ticks ; } foreach ( KeyValuePair < string , AnimationChannel > c in input . Channels ) { time = 0 ; string channelName = c . Key ; AnimationChannel channel = c . Value ; AnimationChannel outChannel = new AnimationChannel ( ) ; int currentFrame = 0 ; while ( time <= animationDuration ) { AnimationKeyframe keyframe ; if ( time >= animationDuration ) { time = animationDuration ; keyframe = new AnimationKeyframe ( new TimeSpan ( time ) , channel [ channel . Count - 1 ] . Transform ) ; } else { if ( channel . Count == 1 || time < channel [ 0 ] . Time . Ticks ) { keyframe = new AnimationKeyframe ( new TimeSpan ( time ) , channel [ 0 ] . Transform ) ; } else if ( channel [ channel . Count - 1 ] . Time . Ticks <= time ) { keyframe = new AnimationKeyframe ( new TimeSpan ( time ) , channel [ channel . Count - 1 ] . Transform ) ; } else { while ( channel [ currentFrame + 1 ] . Time . Ticks < time ) { currentFrame ++ ; } double interpNumerator = ( double ) ( time - channel [ currentFrame ] . Time . Ticks ) ; double interpDenom = ( double ) ( channel [ currentFrame + 1 ] . Time . Ticks - channel [ currentFrame ] . Time . Ticks ) ; double interpAmount = interpNumerator / interpDenom ; if ( channel [ currentFrame + 1 ] . Time . Ticks - channel [ currentFrame ] . Time . Ticks <= ContentUtil . TICKS_PER_60FPS * 1.05 ) { keyframe = new AnimationKeyframe ( new TimeSpan ( time ) , Matrix . Lerp ( channel [ currentFrame ] . Transform , channel [ currentFrame + 1 ] . Transform , ( float ) interpAmount ) ) ; } else if ( channel [ currentFrame ] . Transform != channel [ currentFrame + 1 ] . Transform ) { keyframe = new AnimationKeyframe ( new TimeSpan ( time ) , ContentUtil . SlerpMatrix ( channel [ currentFrame ] . Transform , channel [ currentFrame + 1 ] . Transform , ( float ) interpAmount ) ) ; } else { keyframe = new AnimationKeyframe ( new TimeSpan ( time ) , channel [ currentFrame ] . Transform ) ; } } } outChannel . Add ( keyframe ) ; time += ContentUtil . TICKS_PER_60FPS ; } if ( outChannel [ outChannel . Count - 1 ] . Time . Ticks < animationDuration ) { outChannel . Add ( new AnimationKeyframe ( TimeSpan . FromTicks ( animationDuration ) , channel [ channel . Count - 1 ] . Transform ) ) ; } outChannel . Add ( new AnimationKeyframe ( input . Duration , channel [ channel . Count - 1 ] . Transform ) ) ; output . Channels . Add ( channelName , outChannel ) ; } output . Duration = TimeSpan . FromTicks ( animationDuration ) ; return output ; }
Interpolates an AnimationContent object to 60 fps.
Interpolates an AnimationContent object to 60 fps .
// default XNA importers, due to floating point errors or TimeSpan // estimation, sometimes  have channels with a duration slightly longer than // the animation duration.  So, set the animation duration to its true // value // Step through time until the time passes the animation duration // Clamp the time to the duration of the animation and make this  // keyframe equal to the last animation frame. // If the channel only has one keyframe, set the transform for the current time // to that keyframes transform // If the current track duration is less than the animation duration, // use the last transform in the track once the time surpasses the duration // proceed as normal // Go to the next frame that is less than the current time // Numerator of the interpolation factor // Denominator of the interpolation factor // The interpolation factor, or amount to interpolate between the current // and next frame // If the frames are roughly 60 frames per second apart, use linear interpolation // else if the transforms between the current frame and the next aren't identical // decompose the matrix and interpolate the rotation separately // Else the adjacent frames have identical transforms and we can use // the current frames transform for the current keyframe. // Add the interpolated keyframe to the new channel. // Step the time forward by 1/60th of a second // Compensate for the time error,(animation duration % TICKS_PER_60FPS), // caused by the interpolation by setting the last keyframe in the // channel to the animation duration. // Add the interpolated channel to the animation // Set the interpolated duration to equal the inputs duration for consistency
The interpolated AnimationContent.
The interpolated AnimationContent .
input
AnimationContent
The AnimationContent to interpolate.
The AnimationContent to interpolate .