Example #1
0
        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(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)
            {
                if (indices.ContainsKey(channelKVP.Key) == false)
                {
                    continue;
                }

                AnimationChannel channel = channelKVP.Value;

                foreach (AnimationKeyframe frame in channel)
                {
                    keyFrames.Add(frame.Time, frame.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;
                Matrix   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(channelKVP.Key) == false)
                {
                    continue;
                }
                boneIndices[index++] = indices[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);
            }
        }