/// <summary>
        /// Entry point for animation processing. 
        /// </summary>
        /// <param name="model"></param>
        /// <param name="input"></param>
        /// <param name="context"></param>
        private void ProcessAnimations(ModelContent model, NodeContent input, ContentProcessorContext context, ContentIdentity sourceIdentity)
        {
            // First build a lookup table so we can determine the
            // index into the list of bones from a bone name.
            for (int i = 0; i < model.Bones.Count; i++)
            {
                bones[model.Bones[i].Name] = i;
            }

            // For saving the bone transforms
            boneTransforms = new Matrix[model.Bones.Count];

            //
            // Collect up all of the animation data
            //

            ProcessAnimationsRecursive(input);

            // Check to see if there's an animation clip definition
            // Here, we're checking for a file with the _Anims suffix.
            // So, if your model is named dude.fbx, we'd add dude_Anims.xml in the same folder
            // and the pipeline will see the file and use it to override the animations in the
            // original model file.
            string SourceModelFile = sourceIdentity.SourceFilename;
            string SourcePath = Path.GetDirectoryName(SourceModelFile);
            string AnimFilename = Path.GetFileNameWithoutExtension(SourceModelFile);
            AnimFilename += "_Anims.xml";
            string AnimPath = Path.Combine(SourcePath, AnimFilename);
            if (File.Exists(AnimPath))
            {
                // Add the filename as a dependency, so if it changes, the model is rebuilt
                context.AddDependency(AnimPath);

                // Load the animation definition from the XML file
                AnimationDefinition AnimDef = context.BuildAndLoadAsset<XmlImporter, AnimationDefinition>(new ExternalReference<XmlImporter>(AnimPath), null);

                if (modelExtra.Clips.Count > 0) //if there are some animations in our model
                {
                    foreach (AnimationDefinition.ClipPart Part in AnimDef.ClipParts)
                    {
                        // Grab the main clip that we are using and copy to MainClip

                        AnimationClip MainClip = new AnimationClip();

                        float StartTime = GetTimeSpanForFrame(Part.StartFrame, AnimDef.OriginalFrameCount, modelExtra.Clips[AnimDef.OriginalClipName].Duration);
                        float EndTime = GetTimeSpanForFrame(Part.EndFrame, AnimDef.OriginalFrameCount, modelExtra.Clips[AnimDef.OriginalClipName].Duration);

                        MainClip.Duration = EndTime-StartTime;
                        MainClip.Name = modelExtra.Clips[AnimDef.OriginalClipName].Name;

                        // Process each of our new animation clip parts
                        for (int i = 0; i < modelExtra.Clips[AnimDef.OriginalClipName].Bones.Count; i++)
                        {
                            AnimationClip.Bone clipBone = new AnimationClip.Bone();
                            clipBone.Name = modelExtra.Clips[AnimDef.OriginalClipName].Bones[i].Name;
                            LinkedList<AnimationClip.Keyframe> keyframes = new LinkedList<AnimationClip.Keyframe>();

                            if (modelExtra.Clips[AnimDef.OriginalClipName].Bones[i].Keyframes.Count != 0)
                            {

                                for (int j = 0; j < modelExtra.Clips[AnimDef.OriginalClipName].Bones[i].Keyframes.Count; j++)
                                {

                                    if ((modelExtra.Clips[AnimDef.OriginalClipName].Bones[i].Keyframes[j].Time >= StartTime) && (modelExtra.Clips[AnimDef.OriginalClipName].Bones[i].Keyframes[j].Time <= EndTime))
                                    {
                                        AnimationClip.Keyframe frame = new AnimationClip.Keyframe();
                                        frame.Rotation = modelExtra.Clips[AnimDef.OriginalClipName].Bones[i].Keyframes[j].Rotation;
                                        frame.Time = modelExtra.Clips[AnimDef.OriginalClipName].Bones[i].Keyframes[j].Time - StartTime;
                                        frame.Translation = modelExtra.Clips[AnimDef.OriginalClipName].Bones[i].Keyframes[j].Translation;
                                        keyframes.AddLast(frame);
                                       //clipBone.Keyframes.Add(frame);
                                    }

                                }
                            }
                           // LinearKeyframeReduction(keyframes);
                            clipBone.Keyframes = keyframes.ToList<AnimationClip.Keyframe>();
                            MainClip.Bones.Add(clipBone);

                        }
                        modelExtra.Clips.Add(Part.ClipName, MainClip);

                    }
                }
            }

            // Ensure there is always a clip, even if none is included in the FBX
            // That way we can create poses using FBX files as one-frame
            // animation clips
            if (modelExtra.Clips.Count == 0)
            {
                AnimationClip clip = new AnimationClip();
                modelExtra.Clips.Add("Take 001",clip);

                string clipName = "Take 001";

                // Retain by name
                clips[clipName] = clip;

                clip.Name = clipName;
                foreach (ModelBoneContent bone in model.Bones)
                {
                    AnimationClip.Bone clipBone = new AnimationClip.Bone();
                    clipBone.Name = bone.Name;

                    clip.Bones.Add(clipBone);
                }
            }

            //Ensure all animations have a first key frame for every bone
            foreach (KeyValuePair<string,AnimationClip> clip in modelExtra.Clips)
            {
                for (int b = 0; b < bones.Count; b++)
                {
                    List<AnimationClip.Keyframe> keyframes = clip.Value.Bones[b].Keyframes;
                    if (keyframes.Count == 0 || keyframes[0].Time > 0)
                    {
                        AnimationClip.Keyframe keyframe = new AnimationClip.Keyframe();
                        keyframe.Time = 0;
                        keyframe.Transform = boneTransforms[b];
                        keyframes.Insert(0, keyframe);
                    }
                }
            }
        }
        /// <summary>
        /// Recursive function that processes the entire scene graph, collecting up
        /// all of the animation data.
        /// </summary>
        private void ProcessAnimationsRecursive(NodeContent input)
        {
            // Look up the bone for this input channel
            int inputBoneIndex;
            if (bones.TryGetValue(input.Name, out inputBoneIndex))
            {
                // Save the transform
                boneTransforms[inputBoneIndex] = input.Transform;
            }

            foreach (KeyValuePair<string, AnimationContent> animation in input.Animations)
            {
                // Do we have this animation before?
                AnimationClip clip;
                string clipName = animation.Key;

                if (!clips.TryGetValue(clipName, out clip))
                {
                    // Never seen before clip
                    clip = new AnimationClip();
                    modelExtra.Clips.Add(clipName,clip);

                    // Retain by name
                    clips[clipName] = clip;

                    clip.Name = clipName;
                    foreach (ModelBoneContent bone in model.Bones)
                    {
                        AnimationClip.Bone clipBone = new AnimationClip.Bone();
                        clipBone.Name = bone.Name;

                        clip.Bones.Add(clipBone);
                    }
                }

                // Ensure the duration is always set
                if (animation.Value.Duration.TotalSeconds > clip.Duration)
                    clip.Duration = animation.Value.Duration.TotalSeconds;

                //
                // For each channel, determine the bone and then process all of the
                // keyframes for that bone.
                //

                foreach (KeyValuePair<string, AnimationChannel> channel in animation.Value.Channels)
                {
                    // What is the bone index?
                    int boneIndex;
                    if (!bones.TryGetValue(channel.Key, out boneIndex))
                        continue;           // Ignore if not a named bone

                    // An animation is useless if it is for a bone not assigned to any meshes at all
                    if (UselessAnimationTest(boneIndex))
                        continue;

                    // I'm collecting up in a linked list so we can process the data
                    // and remove redundant keyframes
                    LinkedList<AnimationClip.Keyframe> keyframes = new LinkedList<AnimationClip.Keyframe>();
                    foreach (AnimationKeyframe keyframe in channel.Value)
                    {
                        Matrix transform = keyframe.Transform;      // Keyframe transformation

                        AnimationClip.Keyframe newKeyframe = new AnimationClip.Keyframe();
                        newKeyframe.Time = keyframe.Time.TotalSeconds;
                        newKeyframe.Transform = transform;

                        keyframes.AddLast(newKeyframe);
                    }

                    foreach (AnimationClip.Keyframe keyframe in keyframes)
                    {
                        clip.Bones[boneIndex].Keyframes.Add(keyframe);
                    }

                }

            }

            foreach (NodeContent child in input.Children)
            {
                ProcessAnimationsRecursive(child);
            }
        }
Beispiel #3
0
 /// <summary>
 /// Set the keyframes to a valid value relative to 
 /// the current keyframe
 /// </summary>
 private void SetKeyframes()
 {
     if (ClipBone.Keyframes.Count > 0)
     {
         Keyframe1 = ClipBone.Keyframes[currentKeyframe];
         if (currentKeyframe == ClipBone.Keyframes.Count - 1)
             Keyframe2 = Keyframe1;
         else
             Keyframe2 = ClipBone.Keyframes[currentKeyframe + 1];
     }
     else
     {
         // If there are no keyframes, set both to null
         Keyframe1 = null;
         Keyframe2 = null;
     }
 }