A key frame of a joint animation describing the transformation of the joint at a given time. Transform matrices are decomposed for linear interpolation of SRT components.
Beispiel #1
0
        /// <summary>
        /// Linear interpolation of two keyframe transformations.
        /// </summary>
        /// <param name="frame1">One keyframe</param>
        /// <param name="frame2">Another keyframe</param>
        /// <param name="amount">Weight of second keyframe between 0.0 and 1.0</param>
        /// <returns>Interpolated transformation matrix</returns>
        public static Matrix LerpTransform(JointAnimationKeyFrame frame1,
                                           JointAnimationKeyFrame frame2, float amount)
        {
            // Lerp between components
            Vector3    scale       = Vector3.Lerp(frame1.Scale, frame2.Scale, amount);
            Quaternion rotation    = Quaternion.Lerp(frame1.Rotation, frame2.Rotation, amount);
            Vector3    translation = Vector3.Lerp(frame1.Translation, frame2.Translation, amount);

            return(Matrix.CreateScale(scale) * Matrix.CreateFromQuaternion(rotation) *
                   Matrix.CreateTranslation(translation));
        }
Beispiel #2
0
        /// <summary>
        /// Linear interpolation of two keyframes. The resulting keyframe will consist
        /// of the interpolated time and transformation.
        /// </summary>
        /// <param name="frame1">One keyframe</param>
        /// <param name="frame2">Another keyframe</param>
        /// <param name="amount">Weight of the second keyframe between 0.0 and 1.0</param>
        /// <returns>Interpolated keyframe</returns>
        public static JointAnimationKeyFrame Lerp(JointAnimationKeyFrame frame1,
                                                  JointAnimationKeyFrame frame2, float amount)
        {
            // Lerp between components
            Vector3    scale       = Vector3.Lerp(frame1.Scale, frame2.Scale, amount);
            Quaternion rotation    = Quaternion.Lerp(frame1.Rotation, frame2.Rotation, amount);
            Vector3    translation = Vector3.Lerp(frame1.Translation, frame2.Translation, amount);

            // Lerp time
            float time = frame1.Time + (frame2.Time - frame1.Time) * amount;

            return(new JointAnimationKeyFrame(time, scale, rotation, translation));
        }
        /// <summary>
        /// Calculates a key frame at given time by interpolating between the samples
        /// that are nearest (by time).
        /// </summary>
        /// <param name="time">Time</param>
        /// <returns>Interpolated key frame for given time key</returns>
        public JointAnimationKeyFrame GetInterpolatedKeyframe(float time)
        {
            if (time < StartTime)
            {
                switch (PreBehaviour)
                {
                case AnimationBehaviour.Constant:
                    time = StartTime;
                    break;

                case AnimationBehaviour.Cycle:
                    time = 0;
                    break;

                default:
                    // TODO: Implement other animation behaviours
                    throw new NotImplementedException("No animation behaviours " +
                                                      "other than Constant implemented yet");
                }
            }
            else if (time > EndTime)
            {
                switch (PostBehaviour)
                {
                case AnimationBehaviour.Constant:
                    time = EndTime;
                    break;

                case AnimationBehaviour.Cycle:
                    time %= EndTime;
                    break;

                default:
                    // TODO: Implement other animation behaviours
                    throw new NotImplementedException("No animation behaviours " +
                                                      "other than Constant implemented yet");
                }
            }

            int keyframeIndex = 0;

            // Find the two frames to interpolate between
            while (_keyframes[keyframeIndex].Time <= time)
            {
                keyframeIndex++;
            }

            if (keyframeIndex > 0)
            {
                keyframeIndex--;
            }

            JointAnimationKeyFrame frame1 = _keyframes[keyframeIndex];
            JointAnimationKeyFrame frame2 = _keyframes[keyframeIndex + 1];

            if (frame1.Time == time)
            {
                return(frame1);
            }

            switch (_interpolation)
            {
            case AnimationInterpolation.Linear:
                float amount = 1.0f / (frame2.Time - frame1.Time) * (time - frame1.Time);
                return(JointAnimationKeyFrame.Lerp(frame1, frame2, amount));

            default:
                // TODO: Implement other animation interpolations
                throw new NotImplementedException("No animation interpolation " +
                                                  "other than Linear implemented yet");
            }
        }
Beispiel #4
0
        /// <summary>
        /// Takes a group of animations which affect the same joint and combines them into
        /// one animation with one channel. For this all transformations of each individual
        /// keyframe are combined. Translations are added, Scales multiplied and rotations
        /// multiplied as well.
        /// </summary>
        /// <param name="animations">List of animations</param>
        /// <returns>Combined animation</returns>
        static JointAnimation CombineAnimations(IEnumerable<JointAnimation> animations)
        {
            if (animations.Count() == 1)
            {
                // If there is only one animation there's no need to join
                return animations.First();
            }

            // Number of frames that have to be combined
            int numFrames = animations.First().NumFrames;

            // All animations must have the same number of frames
            if(!animations.All(a => a.NumFrames == numFrames))
            {
                throw new NotImplementedException("Animations affecting the same joint must " +
                    "have the same number of keyframes");
            }

            var combinedKeyframes = new JointAnimationKeyFrame[numFrames];

            for (int i = 0; i < numFrames; i++)
            {
                // Create a combined key frame
                float time = animations.First().Channels[0].Sampler.Keyframes[i].Time;

                Vector3 scale = new Vector3(1,1,1);
                Quaternion rotation = Quaternion.Identity;
                Vector3 translation = new Vector3(0,0,0);

                foreach (var add in animations.Select(anim => anim.Channels[0].Sampler.Keyframes[i]))
                {
                    if (add.Scale != Vector3.One)
                        scale *= add.Scale;

                    if (add.Translation != Vector3.Zero)
                        translation += add.Translation;

                    // Single axis rotations are executed in order (as defined in the document)
                    // Note: Not sure if this is correct
                    if (add.Rotation != Quaternion.Identity)
                        rotation = add.Rotation * rotation;
                }

                var keyframe = new JointAnimationKeyFrame(time, scale, rotation, translation);
                combinedKeyframes[i] = keyframe;
            }

            Joint target = animations.First().Channels[0].Target;
            var sampler = new JointAnimationSampler(combinedKeyframes, AnimationInterpolation.Linear);

            JointAnimation animation = new JointAnimation(new JointAnimationChannel[]
                                          {
                                              new JointAnimationChannel(sampler, target)
                                          });

            // Names
            if (animations.Any(a => !String.IsNullOrEmpty(a.Name)))
            {
                animation.Name = animations.Where(a => !String.IsNullOrEmpty(a.Name)).
                    Select(a => a.Name).Aggregate((sum, name) => sum + "+" + name);
            }

            if (animations.Any(a => !String.IsNullOrEmpty(a.GlobalID)))
            {
                animation.GlobalID = animations.Where(a => !String.IsNullOrEmpty(a.GlobalID)).
                    Select(a => a.GlobalID).Aggregate((sum, name) => sum + "\n" + name);
            }

            return animation;
        }
Beispiel #5
0
        /// <summary>
        /// Imports an animation sampler.
        /// Right now only LINEAR interpolation is supported, thus any other definitions
        /// are simply ignored and LINEAR is used instead.
        /// </summary>
        /// <param name="xmlAnimation">XML animation node</param>
        /// <param name="xmlSampler">XML sampler node</param>
        /// <param name="target">Value of sampler's target attribute</param>
        /// <returns>Animation Sampler</returns>
        // TODO: Implement import of other interpolation methods than LINEAR
        static JointAnimationSampler ImportSampler(XmlNode xmlAnimation, XmlNode xmlSampler,
            string target)
        {
            // Input and Output sources
            Source input = Source.FromInput(xmlSampler.SelectSingleNode("input[@semantic='INPUT']"),
                                            xmlAnimation);
            Source output = Source.FromInput(xmlSampler.SelectSingleNode("input[@semantic='OUTPUT']"),
                                             xmlAnimation);

            // Target (matrix, translation.*, rotation.*, scale.*)
            target = target.Substring(target.IndexOf('/')+1);

            // It is assumed that TIME is used for input
            var times = input.GetData<float>();

            var keyframes = new JointAnimationKeyFrame[times.Count];

            if (target == "matrix")
            {
                // Baked matrices were used so that there is one animation per joint animating
                // the whole transform matrix. Now we just need to save these transforms in keyframes
                var transforms = output.GetData<Matrix>();
                Debug.Assert(transforms.Count == times.Count);

                for (int i = 0; i < times.Count; i++)
                {
                    keyframes[i] = new JointAnimationKeyFrame(times[i], transforms[i]);
                }
            }
            else if (output.DataType == typeof(float))
            {
                // No baked matrices, i.e. there is an animation for each component of the transform
                var data = output.GetData<float>();
                Debug.Assert(times.Count == data.Count);

                for (int i = 0; i < times.Count; i++)
                {
                    keyframes[i] = CreateKeyFrameFromSingle(target, data[i], times[i]);
                }
            }
            else if (output.DataType == typeof(Vector3))
            {
                var data = output.GetData<Vector3>();
                Debug.Assert(times.Count == data.Count);

                for (int i = 0; i < times.Count; i++)
                {
                    keyframes[i] = CreateKeyFrameFromVector(target, data[i], times[i]);
                }
            }

            return new JointAnimationSampler(keyframes, AnimationInterpolation.Linear);
        }
        /// <summary>
        /// Creates a new animation sampler from a list of keyframes
        /// </summary>
        /// <param name="keyframes">List of samples</param>
        /// <param name="interpolation">Interpolation method to use</param>
        public JointAnimationSampler(JointAnimationKeyFrame[] keyframes, 
            AnimationInterpolation interpolation)
        {
            _keyframes = keyframes;
            _interpolation = interpolation;

            if (_interpolation != AnimationInterpolation.Linear)
            {
                // Right now only linear interpolation is supported
                _interpolation = AnimationInterpolation.Linear;
            }

            if (keyframes == null || keyframes.Length == 0)
            {
                throw new ApplicationException("Sampler needs keyframes");
            }

            StartTime = keyframes[0].Time;
            EndTime = keyframes[keyframes.Length - 1].Time;

            PostBehaviour = AnimationBehaviour.Cycle;
        }
        /// <summary>
        /// Linear interpolation of two keyframe transformations.
        /// </summary>
        /// <param name="frame1">One keyframe</param>
        /// <param name="frame2">Another keyframe</param>
        /// <param name="amount">Weight of second keyframe between 0.0 and 1.0</param>
        /// <returns>Interpolated transformation matrix</returns>
        public static Matrix LerpTransform(JointAnimationKeyFrame frame1,
            JointAnimationKeyFrame frame2, float amount)
        {
            // Lerp between components
            Vector3 scale = Vector3.Lerp(frame1.Scale, frame2.Scale, amount);
            Quaternion rotation = Quaternion.Lerp(frame1.Rotation, frame2.Rotation, amount);
            Vector3 translation = Vector3.Lerp(frame1.Translation, frame2.Translation, amount);

            return Matrix.CreateScale(scale) * Matrix.CreateFromQuaternion(rotation) *
                Matrix.CreateTranslation(translation);
        }
        /// <summary>
        /// Linear interpolation of two keyframes. The resulting keyframe will consist
        /// of the interpolated time and transformation.
        /// </summary>
        /// <param name="frame1">One keyframe</param>
        /// <param name="frame2">Another keyframe</param>
        /// <param name="amount">Weight of the second keyframe between 0.0 and 1.0</param>
        /// <returns>Interpolated keyframe</returns>
        public static JointAnimationKeyFrame Lerp(JointAnimationKeyFrame frame1,
            JointAnimationKeyFrame frame2, float amount)
        {
            // Lerp between components
            Vector3 scale = Vector3.Lerp(frame1.Scale, frame2.Scale, amount);
            Quaternion rotation = Quaternion.Lerp(frame1.Rotation, frame2.Rotation, amount);
            Vector3 translation = Vector3.Lerp(frame1.Translation, frame2.Translation, amount);

            // Lerp time
            float time = frame1.Time + (frame2.Time - frame1.Time) * amount;

            return new JointAnimationKeyFrame(time, scale, rotation, translation);
        }