} // ProcessRootAnimation #endregion #region Process Rigid Animation /// <summary> /// Converts an intermediate format content pipeline AnimationContent object to our runtime AnimationClip format. /// </summary> static ModelAnimationClip ProcessRigidAnimation(string animationName, Dictionary<string, int> boneMap, NodeContent input, ModelContent model) { List<ModelKeyframe> keyframes = new List<ModelKeyframe>(); TimeSpan duration = TimeSpan.Zero; AddTransformationNodes(animationName, boneMap, input, keyframes, ref duration); // Sort the merged keyframes by time. keyframes.Sort(CompareKeyframeTimes); if (keyframes.Count == 0) throw new InvalidContentException("Animation has no keyframes."); if (duration <= TimeSpan.Zero) throw new InvalidContentException("Animation has a zero duration."); ModelKeyframe[] keyframesArray = new ModelKeyframe[keyframes.Count]; for (int i = 0; i < keyframes.Count; i++) { keyframesArray[i] = keyframes[i]; } return new ModelAnimationClip((float)(duration.TotalSeconds), keyframesArray); } // ProcessRigidAnimation
/// <summary> /// Comparison function for sorting keyframes into ascending time order. /// </summary> static int CompareKeyframeTimes(ModelKeyframe a, ModelKeyframe b) { return(a.Time.CompareTo(b.Time)); }
} // ProcessAnimations #endregion #region Process Animation /// <summary> /// Converts an intermediate format content pipeline AnimationContent object to our runtime AnimationClip format. /// </summary> static ModelAnimationClip ProcessAnimation(AnimationContent animation, Dictionary <string, int> boneMap) { List <ModelKeyframe> keyframes = new List <ModelKeyframe>(); // For each input animation channel. foreach (KeyValuePair <string, AnimationChannel> channel in animation.Channels) { // Look up what bone this channel is controlling. int boneIndex; if (!boneMap.TryGetValue(channel.Key, out boneIndex)) { throw new InvalidContentException(string.Format("Found animation for bone '{0}', which is not part of the skeleton.", channel.Key)); } // Convert the keyframe data. foreach (AnimationKeyframe keyframe in channel.Value) { keyframes.Add(new ModelKeyframe((ushort)boneIndex, (float)(keyframe.Time.TotalSeconds), keyframe.Transform)); } } // Sort the merged keyframes by time. keyframes.Sort(CompareKeyframeTimes); #region Key Frame Reduction // We drop key frame data where the bone transformation is equal to the previous key frame. List <ModelKeyframe> keyframesReduced = new List <ModelKeyframe>(); for (int i = 0; i < ModelAnimationClip.MaxBones; i++) { int currentBone = i; ModelKeyframe lastKeyFrame = new ModelKeyframe(255, 0, Matrix.Identity); foreach (ModelKeyframe modelKeyframe in keyframes) { if (modelKeyframe.Bone == (ushort)currentBone && (lastKeyFrame.Bone != (ushort)currentBone || lastKeyFrame.Position != modelKeyframe.Position || lastKeyFrame.Rotation != modelKeyframe.Rotation || lastKeyFrame.Scale != modelKeyframe.Scale)) { keyframesReduced.Add(modelKeyframe); } lastKeyFrame = modelKeyframe; } } keyframes = keyframesReduced; // Sort the merged keyframes by time. keyframes.Sort(CompareKeyframeTimes); #endregion if (keyframes.Count == 0) { throw new InvalidContentException("Animation has no keyframes."); } if (animation.Duration <= TimeSpan.Zero) { throw new InvalidContentException("Animation has a zero duration."); } ModelKeyframe[] keyframesArray = new ModelKeyframe[keyframes.Count]; for (int i = 0; i < keyframes.Count; i++) { keyframesArray[i] = keyframes[i]; } return(new ModelAnimationClip((float)(animation.Duration.TotalSeconds), keyframesArray)); } // ProcessAnimation