void ProcessAnimation(AnimationContent anim, ContentProcessorContext context, List <AnimationData> animations, Dictionary <string, int> indices, SkeletonData skeleton) { SortedDictionary <TimeSpan, bool> allFrameTimes = new SortedDictionary <TimeSpan, bool>(); SortedDictionary <TimeSpan, Matrix[]> transforms = new SortedDictionary <TimeSpan, Matrix[]>(); int totalChannels = 0; foreach (KeyValuePair <string, AnimationChannel> channelKVP in anim.Channels) { if (indices.ContainsKey(CleanBoneName(channelKVP.Key)) == false) { continue; } AnimationChannel channel = channelKVP.Value; foreach (AnimationKeyframe frame in channel) { if (allFrameTimes.ContainsKey(frame.Time) == false) { allFrameTimes.Add(frame.Time, true); } } totalChannels++; } foreach (TimeSpan time in allFrameTimes.Keys) { transforms.Add(time, new Matrix[totalChannels]); } SortedDictionary <TimeSpan, Matrix> keyFrames = new SortedDictionary <TimeSpan, Matrix>(); List <KeyValuePair <TimeSpan, Matrix> > newFrames = new List <KeyValuePair <TimeSpan, Matrix> >(); int index = 0; foreach (KeyValuePair <string, AnimationChannel> channelKVP in anim.Channels) { int boneIndex = 0; if (indices.TryGetValue(CleanBoneName(channelKVP.Key), out boneIndex) == false) { continue; } AnimationChannel channel = channelKVP.Value; Matrix transform; foreach (AnimationKeyframe frame in channel) { transform = frame.Transform; if (boneIndex == 0) { CorrectRootBoneTransform(ref transform, skeleton); } else { //remove translation transform.Translation = new Vector3(); } keyFrames.Add(frame.Time, transform); } SortedDictionary <TimeSpan, Matrix> .Enumerator frames = keyFrames.GetEnumerator(); SortedDictionary <TimeSpan, bool> .Enumerator times = allFrameTimes.GetEnumerator(); if (!times.MoveNext()) { continue; } if (!frames.MoveNext()) { continue; } TimeSpan time = frames.Current.Key; transform = frames.Current.Value; while (true) { Matrix previousTransform = transform; TimeSpan previousTime = time; time = frames.Current.Key; transform = frames.Current.Value; if (times.Current.Key.Ticks == frames.Current.Key.Ticks) { if (!times.MoveNext()) { break; } if (!frames.MoveNext()) { //frames ends early... while (true) { newFrames.Add(new KeyValuePair <TimeSpan, Matrix>(times.Current.Key, transform)); if (!times.MoveNext()) { break; } } break; } continue; } if (times.Current.Key.Ticks > frames.Current.Key.Ticks) { //frame is behind if (!frames.MoveNext()) { //frames ends early... while (true) { newFrames.Add(new KeyValuePair <TimeSpan, Matrix>(times.Current.Key, transform)); if (!times.MoveNext()) { break; } } break; } continue; } else { //frame is ahead.. create an inbetween double amount = (times.Current.Key - previousTime).TotalSeconds / (frames.Current.Key - previousTime).TotalSeconds; Matrix newTransform = Matrix.Lerp(previousTransform, frames.Current.Value, (float)amount); //Matrix newTransform = frames.Current.Value.Interpolate(ref previousTransform, (float)(1 - amount)); newFrames.Add(new KeyValuePair <TimeSpan, Matrix>(times.Current.Key, newTransform)); transform = newTransform; time = times.Current.Key; if (!times.MoveNext()) { break; } } } foreach (KeyValuePair <TimeSpan, Matrix> newFrame in newFrames) { keyFrames.Add(newFrame.Key, newFrame.Value); } foreach (KeyValuePair <TimeSpan, Matrix> kvp in keyFrames) { Matrix[] array; if (transforms.TryGetValue(kvp.Key, out array)) { array[index] = kvp.Value; } else { continue; } } newFrames.Clear(); keyFrames.Clear(); index++; } KeyFrameData[] boneKeyFrames = new KeyFrameData[transforms.Count]; int[] boneIndices = new int[totalChannels]; index = 0; foreach (KeyValuePair <string, AnimationChannel> channelKVP in anim.Channels) { if (indices.ContainsKey(CleanBoneName(channelKVP.Key)) == false) { continue; } boneIndices[index++] = indices[CleanBoneName(channelKVP.Key)]; } //compute world space bone default skeleton Matrix[] worldBoneTransforms = skeleton.BoneLocalMatrices.ToArray(); skeleton.TransformHierarchy(worldBoneTransforms); index = 0; float duration = 0; foreach (KeyValuePair <TimeSpan, Matrix[]> kvp in transforms) { float seconds = (float)kvp.Key.TotalSeconds; /* * //make transforms realtive to skeleton * //first get static bone transforms * Matrix[] worldTransform = new Matrix[skeleton.BoneCount]; * for (int i = 0; i < worldTransform.Length; i++) * worldTransform[i] = skeleton.BoneLocalMatrices[i]; * * //replace the animated bones.. * for (int i = 0; i < kvp.Value.Length; i++) * worldTransform[boneIndices[i]] = kvp.Value[i]; * * //transform into a world space skeleton * skeleton.TransformHierarchy(worldTransform); * * //multiply the world space transforms with the inverse of the world space static skeleton * for (int i = 0; i < worldTransform.Length; i++) * { * Matrix m = worldBoneTransforms[i]; * Matrix.Invert(ref m, out m); * * worldTransform[i] = m * worldTransform[i]; * } * * //transform back out of world space into joint space * skeleton.TransformHierarchyInverse(worldTransform); * * * for (int i = 0; i < kvp.Value.Length; i++) * kvp.Value[i] = worldTransform[boneIndices[i]]; */ boneKeyFrames[index++] = new KeyFrameData(seconds, kvp.Value); duration = Math.Max(seconds, duration); } if (boneIndices.Length > 0 && boneKeyFrames.Length > 0) { AnimationData animation = new AnimationData(anim.Name, boneIndices, boneKeyFrames, duration, animationCompressionTolerancePercent); animations.Add(animation); } }