/// <summary> /// Creates a new joint animation channel /// </summary> /// <param name="sampler">Sampler</param> /// <param name="target">Target Joint</param> public JointAnimationChannel(JointAnimationSampler sampler, Joint target) { _sampler = sampler; _target = target; }
/// <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; }