Example #1
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));
        }
Example #2
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);
        }