private bool ValidateModel(NodeContent input, BoneContent rootBone,
                                   ContentProcessorContext context)
        {
            // Finds the root bone
            if (rootBone == null)
            {
                throw new InvalidContentException("Input model does not contain a skeleton.");
            }

            // Validate maximum supported bones
            IList <BoneContent> boneList = MeshHelper.FlattenSkeleton(rootBone);

            if (boneList.Count > MaxBones)
            {
                throw new InvalidContentException(string.Format(
                                                      "Model's skeleton has {0} bones, but the maximum supported is {1}.",
                                                      boneList.Count, MaxBones));
            }

            // Find animations
            AnimationContentDictionary animationDictionary = rootBone.Animations;

            if (animationDictionary.Count == 0)
            {
                context.Logger.LogWarning(null, rootBone.Identity,
                                          "Input model does not contain any animation.");
            }

            return(true);
        }
示例#2
0
        /// <summary>
        /// This function processes the animation content of the model, and stores the data in the Matrix[] List
        /// </summary>
        /// <param name="animations"></param>
        /// <param name="bones"></param>
        /// <param name="outKeyFrames"></param>
        /// <returns></returns>
        private Dictionary <string, InstancedAnimationClip> ProcessAnimations(
            AnimationContentDictionary animations,
            IList <BoneContent> bones,
            List <Matrix[]> outKeyFrames)
        {
            // Create a map of bones - just like in the SkinnedModel Smaple
            Dictionary <string, int> boneMap = new Dictionary <string, int>();

            for (int i = 0; i < bones.Count; i++)
            {
                string boneName = bones[i].Name;

                if (!string.IsNullOrEmpty(boneName))
                {
                    boneMap.Add(boneName, i);
                }
            }

            // This is a dictionary of all the animations in the model
            Dictionary <string, InstancedAnimationClip> animationDictionary = new Dictionary <string, InstancedAnimationClip>();

            // Loop through each animation, and add that stuff to our animation texture, as well as to our dictionary we are going to output
            foreach (KeyValuePair <string, AnimationContent> data in animations)
            {
                string           animationName = data.Key;
                AnimationContent animation     = data.Value;

                InstancedAnimationClip clip = ProcessAnimation(animation, outKeyFrames, boneMap);
                animationDictionary.Add(animationName, clip);
            }

            return(animationDictionary);
        }
示例#3
0
        /// <summary>
        /// Converts an intermediate format content pipeline AnimationContentDictionary
        /// object to our runtime AnimationClip format.
        /// </summary>
        static Dictionary <string, Clip> ProcessAnimations(
            AnimationContentDictionary animations,
            IList <BoneContent> bones,
            List <ClipData> clipInfo)
        {
            // Build up a table mapping bone names to indices.
            Dictionary <string, int> boneMap = new Dictionary <string, int>();

            for (int i = 0; i < bones.Count; i++)
            {
                string boneName = bones[i].Name;

                if (!string.IsNullOrEmpty(boneName))
                {
                    boneMap.Add(boneName, i);
                }
            }

            // Convert each animation in turn.
            Dictionary <string, Clip> animationClips = new Dictionary <string, Clip>();

            foreach (ClipData clip in clipInfo)
            {
                Clip processed = ProcessAnimation(animations[clip.SourceTake], boneMap, clip);

                animationClips.Add(clip.Alias, processed);
            }

            if (animationClips.Count == 0)
            {
                throw new InvalidContentException("Input file does not contain any animations.");
            }

            return(animationClips);
        }
        /// <summary>
        /// Converts an intermediate format content pipeline AnimationContentDictionary
        /// object to our runtime AnimationClip format.
        /// </summary>
        static Dictionary<string, AnimationClip> ProcessAnimations(
            AnimationContentDictionary animations, IList<BoneContent> bones)
        {
            // Build up a table mapping bone names to indices.
            Dictionary<string, int> boneMap = new Dictionary<string, int>();

            for (int i = 0; i < bones.Count; i++)
            {
                string boneName = bones[i].Name;

                if (!string.IsNullOrEmpty(boneName))
                    boneMap.Add(boneName, i);
            }

            // Convert each animation in turn.
            Dictionary<string, AnimationClip> animationClips;
            animationClips = new Dictionary<string, AnimationClip>();

            foreach (KeyValuePair<string, AnimationContent> animation in animations)
            {
                AnimationClip processed = ProcessAnimation(animation.Value, boneMap);

                animationClips.Add(animation.Key, processed);
            }

            if (animationClips.Count == 0)
            {
                throw new InvalidContentException(
                            "Input file does not contain any animations.");
            }

            return animationClips;
        }
示例#5
0
        protected virtual AnimationContentDictionary MergeAnimatedBones(NodeContent root)
        {
            AnimationContentDictionary ret = new AnimationContentDictionary();

            CollectAnimatedBones(ret, root);
            return(ret);
        }
        /// <summary>
        /// Converts an intermediate format content pipeline AnimationContentDictionary
        /// object to our runtime AnimationClip format.
        /// </summary>
        /// <param name="animations">Animation content dictionary.</param>
        /// <param name="bones">List of bones.</param>
        /// <returns>Dictionary of animation clips ordered by name.</returns>
        static Dictionary <string, AnimationClip> ProcessAnimations(
            AnimationContentDictionary animations, IList <BoneContent> bones)
        {
            // Build up a table mapping bone names to indices.
            Dictionary <string, int> boneMap = new Dictionary <string, int>();

            for (int i = 0; i < bones.Count; i++)
            {
                string boneName = bones[i].Name;

                if (!string.IsNullOrEmpty(boneName))
                {
                    boneMap.Add(boneName, i);
                }
            }

            // Convert each animation in turn.
            Dictionary <string, AnimationClip> animationClips = new Dictionary <string, AnimationClip>();

            foreach (KeyValuePair <string, AnimationContent> animation in animations)
            {
                AnimationClip processed = ProcessAnimation(animation.Value, boneMap);

                animationClips.Add(animation.Key, processed);
            }

            if (animationClips.Count == 0)
            {
                throw new InvalidContentException(
                          "Input file does not contain any animations.");
            }

            return(animationClips);
        }
示例#7
0
        /// <summary>
        /// Converts an intermediate format content pipeline AnimationContentDictionary
        /// object to our runtime AnimationClip format.
        /// </summary>
        static Dictionary <string, Clip> ProcessAnimations(AnimationContentDictionary animations, IList <BoneContent> bones)
        {
            // Build up a table mapping bone names to indices.
            Dictionary <string, int> boneMap = new Dictionary <string, int>();

            for (int i = 0; i < bones.Count; i++)
            {
                string boneName = bones[i].Name;

                if (!string.IsNullOrEmpty(boneName))
                {
                    boneMap.Add(boneName, i);
                }
            }

            // Convert each animation in turn.
            Dictionary <string, Clip> animationClips;

            animationClips = new Dictionary <string, Clip>();

            foreach (KeyValuePair <string, AnimationContent> animation in animations)
            {
                Clip processed = ProcessAnimation(animation.Value, boneMap);
                processed.Name = animation.Key;

                animationClips.Add(animation.Key, processed);
            }

            return(animationClips);
        }
示例#8
0
        /// <summary>
        /// NodeContentに含まれているアニメーションデータから独自形式のアニメーションデータを構築
        /// </summary>
        static Dictionary <string, AnimationClip> ProcessAnimations(AnimationContentDictionary animations, IList <BoneContent> bones)
        {
            // ボーン名をキーにしたボーンインデックス配列を作成
            Dictionary <string, int> boneMap = new Dictionary <string, int>();

            for (int i = 0; i < bones.Count; i++)
            {
                string boneName = bones[i].Name;

                if (!string.IsNullOrEmpty(boneName))
                {
                    boneMap.Add(boneName, i);
                }
            }

            // クリップ名をキーにしたアニメショーン配列を作成
            Dictionary <string, AnimationClip> animationClips;

            animationClips = new Dictionary <string, AnimationClip>();

            foreach (KeyValuePair <string, AnimationContent> animation in animations)
            {
                AnimationClip processed = ProcessAnimation(animation.Value, boneMap);

                animationClips.Add(animation.Key, processed);
            }

            if (animationClips.Count == 0)
            {
                throw new InvalidContentException(
                          "Input file does not contain any animations.");
            }

            return(animationClips);
        }
示例#9
0
        private static void MergeAnimation(string animationFilePath, AnimationContentDictionary animationDictionary,
                                       ContentIdentity contentIdentity, ContentProcessorContext context)
        {
            // Use content pipeline to build the asset.
              NodeContent mergeModel = context.BuildAndLoadAsset<NodeContent, NodeContent>(new ExternalReference<NodeContent>(animationFilePath), null);

              // Find the skeleton.
              BoneContent mergeRoot = MeshHelper.FindSkeleton(mergeModel);
              if (mergeRoot == null)
              {
            context.Logger.LogWarning(null, contentIdentity, "Animation model file '{0}' has no root bone. Cannot merge animations.", animationFilePath);
            return;
              }

              // Merge all animations of the skeleton root node.
              foreach (string animationName in mergeRoot.Animations.Keys)
              {
            if (animationDictionary.ContainsKey(animationName))
            {
              context.Logger.LogWarning(null, contentIdentity,
              "Replacing animation '{0}' from '{1}' with merged animation.",
              animationName, animationFilePath);

              animationDictionary[animationName] = mergeRoot.Animations[animationName];
            }
            else
            {
              context.Logger.LogImportantMessage("Merging animation '{0}' from '{1}'.", animationName, animationFilePath);

              animationDictionary.Add(animationName, mergeRoot.Animations[animationName]);
            }
              }
        }
示例#10
0
 static void ProcessAnimations(AnimationContentDictionary xnaAnimations, SerializableModel model)
 {
     foreach (KeyValuePair <string, AnimationContent> xnaAnimation in xnaAnimations)
     {
         SerializableAnimation animation = ProcessAnimation(xnaAnimation.Value);
         model.animationList.Add(animation);
     }
 }
        private static Dictionary <string, AnimationClip> ProcessAnimations(AnimationContentDictionary animations, IList <BoneContent> bones)
        {
            bool count;
            Dictionary <string, int> strs = new Dictionary <string, int>();
            int num = 0;

            while (true)
            {
                count = num < bones.Count;
                if (!count)
                {
                    break;
                }
                string name = bones[num].Name;
                count = string.IsNullOrEmpty(name);
                if (!count)
                {
                    strs.Add(name, num);
                }
                num++;
            }
            Dictionary <string, AnimationClip> strs1 = new Dictionary <string, AnimationClip>();
            IEnumerator <KeyValuePair <string, AnimationContent> > enumerator = animations.GetEnumerator();

            try {
                while (true)
                {
                    count = enumerator.MoveNext();
                    if (!count)
                    {
                        break;
                    }
                    KeyValuePair <string, AnimationContent> current = enumerator.Current;
                    AnimationClip animationClip = SkinnedModelProcessor.ProcessAnimation(current.Value, strs);
                    strs1.Add(current.Key, animationClip);
                }
            } finally {
                count = enumerator == null;
                if (!count)
                {
                    enumerator.Dispose();
                }
            }
            count = strs1.Count != 0;
            if (count)
            {
                Dictionary <string, AnimationClip> strs2 = strs1;
                return(strs2);
            }
            else
            {
                throw new InvalidContentException("Input file does not contain any animations.");
            }
        }
示例#12
0
        public static void Split(AnimationContentDictionary animationDictionary, string splitFile, ContentIdentity contentIdentity, ContentProcessorContext context)
        {
            if (animationDictionary == null)
            return;

              if (string.IsNullOrEmpty(splitFile))
            return;

              if (contentIdentity == null)
            throw new ArgumentNullException("contentIdentity");

              if (context == null)
            throw new ArgumentNullException("context");

              if (animationDictionary.Count == 0)
              {
            context.Logger.LogWarning(null, contentIdentity, "The model does not have an animation. Animation splitting is skipped.");
            return;
              }

              if (animationDictionary.Count > 1)
            context.Logger.LogWarning(null, contentIdentity, "The model contains more than 1 animation. The animation splitting is performed on the first animation. Other animations are deleted!");

              // Load XML file.
              splitFile = ContentHelper.FindFile(splitFile, contentIdentity);
              XDocument document = XDocument.Load(splitFile, LoadOptions.SetLineInfo);

              // Let the content pipeline know that we depend on this file and we need to
              // rebuild the content if the file is modified.
              context.AddDependency(splitFile);

              // Parse XML.
              var animationsElement = document.Element("Animations");
              if (animationsElement == null)
              {
            context.Logger.LogWarning(null, contentIdentity, "The animation split file \"{0}\" does not contain an <Animations> root node.", splitFile);
            return;
              }

              var wrappedContext = new ContentPipelineContext(context);
              var splits = ParseAnimationSplitDefinitions(animationsElement, contentIdentity, wrappedContext);
              if (splits == null || splits.Count == 0)
              {
            context.Logger.LogWarning(null, contentIdentity, "The XML file with the animation split definitions is invalid or empty. Animation is not split.");
            return;
              }

              // Split animations.
              Split(animationDictionary, splits, contentIdentity, context);
        }
示例#13
0
        /// <summary>
        /// Merges the specified animation files to the specified animation dictionary.
        /// </summary>
        /// <param name="animationFiles">
        /// The animation files as a string separated by semicolon (relative to the folder of the model 
        /// file). For example: "run.fbx;jump.fbx;turn.fbx".
        /// </param>
        /// <param name="animationDictionary">The animation dictionary.</param>
        /// <param name="contentIdentity">The content identity.</param>
        /// <param name="context">The content processor context.</param>
        public static void Merge(string animationFiles, AnimationContentDictionary animationDictionary,
            ContentIdentity contentIdentity, ContentProcessorContext context)
        {
            if (string.IsNullOrEmpty(animationFiles))
            return;

              // Get path of the model file.
              var files = animationFiles.Split(';', ',')
                                .Select(s => s.Trim())
                                .Where(s => !string.IsNullOrEmpty(s));
              foreach (string file in files)
              {
            MergeAnimation(file, animationDictionary, contentIdentity, context);
              }
        }
示例#14
0
    /// <summary>
    /// Merges the specified animation files to the specified animation dictionary.
    /// </summary>
    /// <param name="animationFiles">
    /// The animation files as a string separated by semicolon (relative to the folder of the model 
    /// file). For example: "run.fbx;jump.fbx;turn.fbx".
    /// </param>
    /// <param name="animationDictionary">The animation dictionary.</param>
    /// <param name="contentIdentity">The content identity.</param>
    /// <param name="context">The content processor context.</param>
    public static void Merge(string animationFiles, AnimationContentDictionary animationDictionary,
                             ContentIdentity contentIdentity, ContentProcessorContext context)
    {
      if (string.IsNullOrEmpty(animationFiles))
        return;

      // Get path of the model file.
      var files = animationFiles.Split(';', ',')
                                .Select(s => s.Trim())
                                .Where(s => !string.IsNullOrEmpty(s));
      foreach (string file in files)
      {
        MergeAnimation(file, animationDictionary, contentIdentity, context);
      }
    }
        Dictionary <string, AnimationClip> ProcessSplitAnimations(
            AnimationContentDictionary animations,
            Dictionary <string, int> boneMap)
        {
            IEnumerator <KeyValuePair <string, AnimationContent> > aniIter = animations.GetEnumerator();

            aniIter.MoveNext();
            Dictionary <string, AnimationClip> processed =
                SplitAndCreateAnimation(ProcessAnimationKeyframe(aniIter.Current.Value, boneMap));

            if (processed.Count == 0)
            {
                throw new InvalidContentException("Input file does not contain any animations.");
            }

            return(processed);
        }
        private Dictionary <string, AnimationClip> ProcessAnimations(AnimationContentDictionary animations, IList <BoneContent> boneContents)
        {
            Dictionary <string, int> boneMap = new Dictionary <string, int>();

            for (int i = 0; i < boneContents.Count; i++)
            {
                boneMap.Add(boneContents[i].Name, i);
            }

            Dictionary <string, AnimationClip> animationClips = new Dictionary <string, AnimationClip>();

            foreach (KeyValuePair <string, AnimationContent> animation in animations)
            {
                AnimationClip processed = ProcessAnimation(animation.Value, boneMap);
                animationClips.Add(animation.Key, processed);
            }
            return(animationClips);
        }
示例#17
0
        /// <summary>
        /// Merges the specified animation files to the specified animation dictionary.
        /// </summary>
        /// <param name="animationFiles">
        /// The animation files as a string separated by semicolon (relative to the folder of the model 
        /// file). For example: "run.fbx;jump.fbx;turn.fbx".
        /// </param>
        /// <param name="animationDictionary">The animation dictionary.</param>
        /// <param name="contentIdentity">The content identity.</param>
        /// <param name="context">The content processor context.</param>
        public static void Merge(string animationFiles, AnimationContentDictionary animationDictionary,
                             ContentIdentity contentIdentity, ContentProcessorContext context)
        {
            if (string.IsNullOrEmpty(animationFiles))
            return;

            // Get path of the model file.
            string sourcePath = Path.GetDirectoryName(contentIdentity.SourceFilename);

              var files = animationFiles.Split(';')
                                .Select(s => s.Trim())
                                .Where(s => !string.IsNullOrEmpty(s));
              foreach (string file in files)
            {
              string filePath = Path.GetFullPath(Path.Combine(sourcePath, file));
              MergeAnimation(filePath, animationDictionary, contentIdentity, context);
            }
        }
示例#18
0
        protected virtual void CollectAnimatedBones(AnimationContentDictionary dict, NodeContent bone)
        {
            AnimationContentDictionary acd = bone.Animations;

            if (acd != null)
            {
                foreach (string name in acd.Keys)
                {
                    //  merge each animation into the dictionary
                    AnimationContent ac = acd[name];
                    AnimationContent xac;
                    if (!dict.TryGetValue(name, out xac))
                    {
                        //  create it if we haven't already seen it, and there's something there
                        if (ac.Channels.Count > 0)
                        {
                            xac = ac;
                            dict.Add(name, xac);
                        }
                    }
                    else
                    {
                        //  merge the animation content
                        foreach (KeyValuePair <string, AnimationChannel> kvp in ac.Channels)
                        {
                            AnimationChannel ov;
                            if (xac.Channels.TryGetValue(kvp.Key, out ov))
                            {
                                throw new System.ArgumentException(
                                          String.Format("The animation {0} has multiple channels named {1}.",
                                                        name, kvp.Key));
                            }
                            xac.Channels.Add(kvp.Key, kvp.Value);
                        }
                        xac.Duration = new TimeSpan((long)
                                                    (Math.Max(xac.Duration.TotalSeconds, ac.Duration.TotalSeconds) * 1e7));
                    }
                }
            }
            foreach (NodeContent nc in bone.Children)
            {
                CollectAnimatedBones(dict, nc);
            }
        }
示例#19
0
        private static void MergeAnimation(string animationFile, AnimationContentDictionary animationDictionary,
                                           ContentIdentity contentIdentity, ContentProcessorContext context)
        {
            if (string.IsNullOrEmpty(animationFile))
            {
                return;
            }
            if (animationDictionary == null)
            {
                throw new ArgumentNullException("animationDictionary");
            }
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            // Use content pipeline to build the asset.
            animationFile = ContentHelper.FindFile(animationFile, contentIdentity);
            NodeContent mergeModel = context.BuildAndLoadAsset <NodeContent, NodeContent>(new ExternalReference <NodeContent>(animationFile), null);

            // Find the skeleton.
            BoneContent mergeRoot = MeshHelper.FindSkeleton(mergeModel);

            if (mergeRoot == null)
            {
                context.Logger.LogWarning(null, contentIdentity, "Animation model file '{0}' has no root bone. Cannot merge animations.", animationFile);
                return;
            }

            // Merge all animations of the skeleton root node.
            foreach (string animationName in mergeRoot.Animations.Keys)
            {
                if (animationDictionary.ContainsKey(animationName))
                {
                    context.Logger.LogWarning(null, contentIdentity, "Replacing animation '{0}' with merged animation from '{1}'.", animationName, animationFile);
                    animationDictionary[animationName] = mergeRoot.Animations[animationName];
                }
                else
                {
                    context.Logger.LogImportantMessage("Merging animation '{0}' from '{1}'.", animationName, animationFile);
                    animationDictionary.Add(animationName, mergeRoot.Animations[animationName]);
                }
            }
        }
        /// <summary>
        /// Converts an intermediate format content pipeline AnimationContentDictionary
        /// object to our runtime AnimationClip format.
        /// </summary>
        Dictionary <string, AnimationClip> ProcessAnimations(
            AnimationContentDictionary animations,
            Dictionary <string, int> boneMap)
        {
            // Convert each animation in turn.
            Dictionary <string, AnimationClip> animationClips = new Dictionary <string, AnimationClip>();

            foreach (KeyValuePair <string, AnimationContent> animation in animations)
            {
                animationClips.Add(animation.Key, ProcessAnimation(animation.Value, boneMap));
            }

            if (animationClips.Count == 0)
            {
                throw new InvalidContentException("Input file does not contain any animations.");
            }

            return(animationClips);
        }
示例#21
0
        private AnimationClip[] ExtractAnimations(
            AnimationContentDictionary animationDictionary,
            List <string> boneNameList,
            ContentProcessorContext context)
        {
            if (animationDictionary.Count < 1)
            {
                context.Logger.LogImportantMessage("Warning: No animations found.");
            }

            AnimationClip[] animations = new AnimationClip[animationDictionary.Count];

            int animationCount = 0;

            foreach (AnimationContent animationContent in animationDictionary.Values)
            {
                List <Keyframe> keyframes = new List <Keyframe>();

                // Each bone has its own channel
                foreach (string bone in animationContent.Channels.Keys)
                {
                    AnimationChannel animationChannel = animationContent.Channels[bone];
                    int boneIndex = boneNameList.IndexOf(bone);

                    foreach (AnimationKeyframe keyframe in animationChannel)
                    {
                        keyframes.Add(new Keyframe(
                                          keyframe.Time, boneIndex, keyframe.Transform));
                    }
                }

                // Sort all animation frames by time
                keyframes.Sort();

                animations[animationCount++] = new AnimationClip(
                    animationContent.Name,
                    animationContent.Duration,
                    keyframes.ToArray());
            }

            return(animations);
        }
        /// <summary>
        /// Converts an intermediate format content pipeline AnimationContentDictionary
        /// object to our runtime AnimationClip format.
        /// </summary>
        static Dictionary <string, AnimationClip> ProcessAnimations(
            AnimationContentDictionary animations, IList <BoneContent> bones)
        {
            // Build up a table mapping bone names to indices.
            Dictionary <string, int> boneMap = new Dictionary <string, int>();

            for (int i = 0; i < bones.Count; i++)
            {
                string boneName = bones[i].Name;

                if (!string.IsNullOrEmpty(boneName))
                {
                    boneMap.Add(boneName, i);
                }
            }

            // Convert each animation in turn.
            Dictionary <string, AnimationClip> animationClips;

            animationClips = new Dictionary <string, AnimationClip>();

            foreach (KeyValuePair <string, AnimationContent> animation in animations)
            {
                //sbLog.Append("Animation Name:" + animation.Key);
                //sbLog.Append(" Identity: " + animation.Value.Identity);
                //sbLog.AppendLine(" Duration: " + animation.Value.Duration.ToString());
                //sbLog.AppendLine(" Channels.Keys: " + animation.Value.Channels.Values.GetEnumerator().Current.

                Console.WriteLine("animation.Value.Name=" + animation.Value.Name);
                AnimationClip processed = ProcessAnimation(animation.Value, boneMap);

                animationClips.Add(animation.Key, processed);
            }

            if (animationClips.Count == 0)
            {
                throw new InvalidContentException(
                          "Input file does not contain any animations.");
            }

            return(animationClips);
        }
示例#23
0
        private AnimationData[] ExtractAnimations(AnimationContentDictionary animationDictionary, List <string> boneNameList,
                                                  ContentProcessorContext context)
        {
            context.Logger.LogImportantMessage("{0} animations found.", animationDictionary.Count);
            AnimationData[] animations = new AnimationData[animationDictionary.Count];

            int count = 0;

            foreach (AnimationContent animationContent in animationDictionary.Values)
            {
                // Store all keyframes of the animation
                List <Keyframe> keyframes = new List <Keyframe>();

                // Go through all animation channels (Each bone has it's own channel)
                foreach (string animationKey in animationContent.Channels.Keys)
                {
                    AnimationChannel animationChannel = animationContent.Channels[animationKey];
                    int boneIndex = boneNameList.IndexOf(animationKey);

                    //context.Logger.LogImportantMessage("{0} - Bone: ", animationKey, boneIndex);
                    foreach (AnimationKeyframe keyframe in animationChannel)
                    {
                        keyframes.Add(new Keyframe(keyframe.Time, boneIndex, keyframe.Transform));
                    }
                }

                context.Logger.LogImportantMessage("Animation {0}: {1} channels found, {2} keyframes found.",
                                                   animationContent.Name, animationContent.Channels.Count, keyframes.Count);

                // Sort all animation frames by time
                keyframes.Sort();

                animations[count++] = new
                                      AnimationData(animationContent.Name, animationContent.Duration, keyframes.ToArray());
            }

            return(animations);
        }
        /// <summary>
        /// Converts an intermediate format content pipeline AnimationContentDictionary
        /// object to our runtime AnimationClip format.
        /// </summary>
        static Dictionary<string, AnimationClip> ProcessAnimations(
            AnimationContentDictionary animations, IList<BoneContent> bones,
            ContentProcessorContext context, ContentIdentity sourceIdentity)
        {
            // Build up a table mapping bone names to indices.
            Dictionary<string, int> boneMap = new Dictionary<string, int>();

            for (int i = 0; i < bones.Count; i++)
            {
                string boneName = bones[i].Name;

                if (!string.IsNullOrEmpty(boneName))
                    boneMap.Add(boneName, i);
            }

            // Convert each animation in turn.
            Dictionary<string, AnimationClip> animationClips;
            animationClips = new Dictionary<string, AnimationClip>();

            foreach (KeyValuePair<string, AnimationContent> animation in animations)
            {
                AnimationClip processed = ProcessAnimation(animation.Value, boneMap, animation.Key);

                animationClips.Add(animation.Key, processed);
            }

            // 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))
            {
                context.AddDependency(AnimPath);

                AnimationDefinition AnimDef = context.BuildAndLoadAsset<XmlImporter, AnimationDefinition>(new ExternalReference<XmlImporter>(AnimPath), null);

                //breaks up original animation clips into new clips
                if (animationClips.ContainsKey(AnimDef.originalClipName))
                {
                    //graps main clip
                    AnimationClip MainClip = animationClips[AnimDef.originalClipName];
                    //remove original clip from animations
                    animationClips.Remove(AnimDef.originalClipName);

                    foreach (AnimationDefinition.clipPart Part in AnimDef.ClipParts)
                    {
                        //calculate frame times
                        TimeSpan StartTime = GetTimeSpanForFrame(Part.StartFrame, AnimDef.originalFrameCount, MainClip.Duration.Ticks);
                        TimeSpan EndTime = GetTimeSpanForFrame(Part.EndFrame, AnimDef.originalFrameCount, MainClip.Duration.Ticks);

                        //get keyframes for animation clip thats in start and end time
                        List<Keyframe> Keyframes = new List<Keyframe>();
                        foreach (Keyframe AnimFrame in MainClip.Keyframes)
                        {
                            if ((AnimFrame.Time >= StartTime) && (AnimFrame.Time <= EndTime))
                            {
                                Keyframe NewFrame = new Keyframe(AnimFrame.Bone, AnimFrame.Time - StartTime, AnimFrame.Transform);
                                Keyframes.Add(NewFrame);
                            }
                        }

                        //process events
                        /*List<AnimationEvent> Events = new List<AnimationEvent>();
                        if (Part.Events != null)
                        {
                            foreach (AnimationDefinition.clipPart.Event Event in Part.Events)
                            {
                                TimeSpan EventTime = GetTimeSpanForFrame(Event.Keyframe, AnimDef.originalFrameCount, MainClip.Duration.Ticks);
                                EventTime -= StartTime;

                                AnimationEvent newEvent = new AnimationEvent();
                                newEvent.EventTime = EventTime;
                                newEvent.EventName = Event.Name;
                                Events.Add(newEvent);
                            }
                        }*/

                        AnimationClip newClip = new AnimationClip(EndTime - StartTime, Keyframes, Part.ClipName);
                        animationClips[Part.ClipName] = newClip;
                    }
                }
            }

               /* if (animationClips.Count == 0)
            {
                throw new InvalidContentException(
                            "Input file does not contain any animations.");
            }*/

            return animationClips;
        }
示例#25
0
        /// <summary>
        /// Called when an XML document is read that specifies how animations
        /// should be split.
        /// </summary>
        /// <param name="animDict">The dictionary of animation name/AnimationContent
        /// pairs. </param>
        /// <param name="doc">The Xml document that contains info on how to split
        /// the animations.</param>
        protected virtual void SubdivideAnimations(
            AnimationContentDictionary animDict, XmlDocument doc)
        {
            string[] animNames = new string[animDict.Keys.Count];
            animDict.Keys.CopyTo(animNames, 0);
            if (animNames.Length == 0)
            {
                return;
            }

            // Traverse each xml node that represents an animation to be subdivided
            foreach (XmlNode node in doc)
            {
                XmlElement child = node as XmlElement;
                if (child == null || child.Name != "animation")
                {
                    continue;
                }

                string animName = null;
                if (child["name"] != null)
                {
                    // The name of the animation to be split
                    animName = child["name"].InnerText;
                }
                else if (child["index"] != null)
                {
                    animName = animNames[int.Parse(child["index"].InnerText)];
                }
                else
                {
                    animName = animNames[0];
                }

                // If the tickspersecond node is filled, use that to calculate seconds per tick
                double animTicksPerSecond = 1.0, secondsPerTick = 0;
                try
                {
                    if (child["tickspersecond"] != null)
                    {
                        animTicksPerSecond = double.Parse(child["tickspersecond"].InnerText);
                    }
                }
                catch
                {
                    throw new Exception("Error parsing tickspersecond in xml file.");
                }
                if (animTicksPerSecond <= 0)
                {
                    throw new InvalidDataException("AnimTicksPerSecond in XML file must be " +
                                                   "a positive number.");
                }
                secondsPerTick = 1.0 / animTicksPerSecond;

                AnimationContent anim = null;
                // Get the animation and remove it from the dict
                // Check to see if the animation specified in the xml file exists
                try
                {
                    anim = animDict[animName];
                }
                catch
                {
                    throw new Exception("Animation named " + animName + " specified in XML file does not exist in model.");
                }
                animDict.Remove(anim.Name);
                // Get the list of new animations
                XmlNodeList subAnimations = child.GetElementsByTagName("animationsubset");

                foreach (XmlElement subAnim in subAnimations)
                {
                    // Create the new sub animation
                    AnimationContent newAnim            = new AnimationContent();
                    XmlElement       subAnimNameElement = subAnim["name"];

                    if (subAnimNameElement != null)
                    {
                        newAnim.Name = subAnimNameElement.InnerText;
                    }

                    // If a starttime node exists, use that to get the start time
                    long startTime, endTime;
                    if (subAnim["starttime"] != null)
                    {
                        try
                        {
                            startTime = TimeSpan.FromSeconds(double.Parse(subAnim["starttime"].InnerText)).Ticks;
                        }
                        catch
                        {
                            throw new Exception("Error parsing starttime node in XML file.  Node inner text "
                                                + "must be a non negative number.");
                        }
                    }
                    else if (subAnim["startframe"] != null)// else use the secondspertick combined with the startframe node value
                    {
                        try
                        {
                            double seconds =
                                double.Parse(subAnim["startframe"].InnerText) * secondsPerTick;

                            startTime = TimeSpan.FromSeconds(
                                seconds).Ticks;
                        }
                        catch
                        {
                            throw new Exception("Error parsing startframe node in XML file.  Node inner text "
                                                + "must be a non negative number.");
                        }
                    }
                    else
                    {
                        throw new Exception("Sub animation in XML file must have either a starttime or startframe node.");
                    }

                    // Same with endtime/endframe
                    if (subAnim["endtime"] != null)
                    {
                        try
                        {
                            endTime = TimeSpan.FromSeconds(double.Parse(subAnim["endtime"].InnerText)).Ticks;
                        }
                        catch
                        {
                            throw new Exception("Error parsing endtime node in XML file.  Node inner text "
                                                + "must be a non negative number.");
                        }
                    }
                    else if (subAnim["endframe"] != null)
                    {
                        try
                        {
                            double seconds = double.Parse(subAnim["endframe"].InnerText)
                                             * secondsPerTick;
                            endTime = TimeSpan.FromSeconds(
                                seconds).Ticks;
                        }
                        catch
                        {
                            throw new Exception("Error parsing endframe node in XML file.  Node inner text "
                                                + "must be a non negative number.");
                        }
                    }
                    else
                    {
                        throw new Exception("Sub animation in XML file must have either an endtime or endframe node.");
                    }

                    if (endTime < startTime)
                    {
                        throw new Exception("Start time must be <= end time in XML file.");
                    }

                    // Now that we have the start and end times, we associate them with
                    // start and end indices for each animation track/channel
                    foreach (KeyValuePair <string, AnimationChannel> k in anim.Channels)
                    {
                        // The current difference between the start time and the
                        // time at the current index
                        long currentStartDiff;
                        // The current difference between the end time and the
                        // time at the current index
                        long currentEndDiff;
                        // The difference between the start time and the time
                        // at the start index
                        long bestStartDiff = long.MaxValue;
                        // The difference between the end time and the time at
                        // the end index
                        long bestEndDiff = long.MaxValue;

                        // The start and end indices
                        int startIndex = -1;
                        int endIndex   = -1;

                        // Create a new channel and reference the old channel
                        AnimationChannel newChan = new AnimationChannel();
                        AnimationChannel oldChan = k.Value;

                        // Iterate through the keyframes in the channel
                        for (int i = 0; i < oldChan.Count; i++)
                        {
                            // Update the startIndex, endIndex, bestStartDiff,
                            // and bestEndDiff
                            long ticks = oldChan[i].Time.Ticks;
                            currentStartDiff = Math.Abs(startTime - ticks);
                            currentEndDiff   = Math.Abs(endTime - ticks);
                            if (startIndex == -1 || currentStartDiff < bestStartDiff)
                            {
                                startIndex    = i;
                                bestStartDiff = currentStartDiff;
                            }
                            if (endIndex == -1 || currentEndDiff < bestEndDiff)
                            {
                                endIndex    = i;
                                bestEndDiff = currentEndDiff;
                            }
                        }


                        // Now we have our start and end index for the channel
                        for (int i = startIndex; i <= endIndex; i++)
                        {
                            AnimationKeyframe frame = oldChan[i];
                            long time;
                            // Clamp the time so that it can't be less than the
                            // start time
                            if (frame.Time.Ticks < startTime)
                            {
                                time = 0;
                            }
                            // Clamp the time so that it can't be greater than the
                            // end time
                            else if (frame.Time.Ticks > endTime)
                            {
                                time = endTime - startTime;
                            }
                            else // Else get the time
                            {
                                time = frame.Time.Ticks - startTime;
                            }

                            // Finally... create the new keyframe and add it to the new channel
                            AnimationKeyframe keyframe = new AnimationKeyframe(
                                TimeSpan.FromTicks(time),
                                frame.Transform);

                            newChan.Add(keyframe);
                        }

                        // Add the channel and update the animation duration based on the
                        // length of the animation track.
                        newAnim.Channels.Add(k.Key, newChan);
                        if (newChan[newChan.Count - 1].Time > newAnim.Duration)
                        {
                            newAnim.Duration = newChan[newChan.Count - 1].Time;
                        }
                    }
                    try
                    {
                        // Add the subdived animation to the dictionary.
                        animDict.Add(newAnim.Name, newAnim);
                    }
                    catch
                    {
                        throw new Exception("Attempt to add an animation when one by the same name already exists. " +
                                            "Name: " + newAnim.Name);
                    }
                }
            }
        }
示例#26
0
        /// <summary>
        /// Converts an intermediate format content pipeline AnimationContentDictionary
        /// object to our runtime AnimationClip format.
        /// </summary>
        Dictionary <string, ClipContent> ProcessAnimations(NodeContent input, ContentProcessorContext context, AnimationContentDictionary animations, IList <BoneContent> bones, int generateKeyframesFrequency)
        {
            // Build up a table mapping bone names to indices.
            Dictionary <string, int> boneMap = new Dictionary <string, int>();

            for (int i = 0; i < bones.Count; i++)
            {
                string boneName = bones[i].Name;

                if (!string.IsNullOrEmpty(boneName))
                {
                    boneMap.Add(boneName, i);
                }
            }

            // Convert each animation in turn.
            Dictionary <string, ClipContent> animationClips;

            animationClips = new Dictionary <string, ClipContent>();

            foreach (KeyValuePair <string, AnimationContent> animation in animations)
            {
                ClipContent clip = ProcessAnimation(input, context, animation.Value, boneMap, generateKeyframesFrequency);

                animationClips.Add(animation.Key, clip);
            }

            if (animationClips.Count == 0)
            {
                //throw new InvalidContentException("Input file does not contain any animations.");
                context.Logger.LogWarning(null, null, "Input file does not contain any animations.");
            }

            return(animationClips);
        }
示例#27
0
		private static Dictionary<string, AnimationClip> ProcessAnimations(AnimationContentDictionary animations, IList<BoneContent> bones) {
			bool count;
			Dictionary<string, int> strs = new Dictionary<string, int>();
			int num = 0;
			while (true) {
				count = num < bones.Count;
				if (!count) {
					break;
				}
				string name = bones[num].Name;
				count = string.IsNullOrEmpty(name);
				if (!count) {
					strs.Add(name, num);
				}
				num++;
			}
			Dictionary<string, AnimationClip> strs1 = new Dictionary<string, AnimationClip>();
			IEnumerator<KeyValuePair<string, AnimationContent>> enumerator = animations.GetEnumerator();
			try {
				while (true) {
					count = enumerator.MoveNext();
					if (!count) {
						break;
					}
					KeyValuePair<string, AnimationContent> current = enumerator.Current;
					AnimationClip animationClip = SkinnedModelProcessor.ProcessAnimation(current.Value, strs);
					strs1.Add(current.Key, animationClip);
				}
			} finally {
				count = enumerator == null;
				if (!count) {
					enumerator.Dispose();
				}
			}
			count = strs1.Count != 0;
			if (count) {
				Dictionary<string, AnimationClip> strs2 = strs1;
				return strs2;
			} else {
				throw new InvalidContentException("Input file does not contain any animations.");
			}
		}
示例#28
0
        /// <summary>
        /// コンテント・パイプライン内の中間フォーマットである
        /// AnimationContentDictionaryから、ランタイムフォーマットである
        /// AnimationClipフォーマットに変換する
        /// </summary>
        static Dictionary<string, AnimationClip> ProcessAnimations(
            AnimationContentDictionary animations, IList<BoneContent> bones)
        {
            // ボーン名からインデックスに変換する辞書テーブルを作る
            Dictionary<string, int> boneMap = new Dictionary<string, int>();

            for (int i = 0; i < bones.Count; i++)
            {
                string boneName = bones[i].Name;

                if (!string.IsNullOrEmpty(boneName))
                    boneMap.Add(boneName, i);
            }

            // それぞれのアニメーションを変換する
            Dictionary<string, AnimationClip> animationClips;
            animationClips = new Dictionary<string, AnimationClip>();

            foreach (KeyValuePair<string, AnimationContent> animation in animations)
            {
                AnimationClip processed = ProcessAnimation(animation.Value, boneMap);
                
                animationClips.Add(animation.Key, processed);
            }

            if (animationClips.Count == 0)
            {
                throw new InvalidContentException(
                            "入力ファイルはアニメーションが含まれていません。");
            }

            return animationClips;
        }
        static Dictionary<String, AnimationClip> ProcessAnimations(AnimationContentDictionary animations, IList<BoneContent> bones)
        {
            // Build up a table mapping bones to indices.
            Dictionary<String, int> boneMap = new Dictionary<String, int>();

            for (int i = 0; i < bones.Count; i++)
                boneMap.Add(bones[i].Name, i);

            Dictionary<String, AnimationClip> animationsClips = new Dictionary<String, AnimationClip>();

            // Convert each animation
            foreach (KeyValuePair<String, AnimationContent> animation in animations)
            {
                // Rotate animation
                //RotateAll(animation.Value);

                // Get animation clip
                AnimationClip processed = ProcessAnimation(animation.Value, boneMap);
                processed.Name = animation.Key;

                // Add the clip
                animationsClips.Add(animation.Key, processed);
            }

            // Return the animations clips
            return animationsClips;
        }
        /// <summary>
        /// Converts an intermediate format content pipeline AnimationContentDictionary
        /// object to our runtime AnimationClip format.
        /// </summary>
        static Dictionary<string, AnimationClip> ProcessAnimations(
            AnimationContentDictionary animations, IList<BoneContent> bones)
        {
            // Build up a table mapping bone names to indices.
            Dictionary<string, int> boneMap = new Dictionary<string, int>();

            for (int i = 0; i < bones.Count; i++)
            {
                string boneName = bones[i].Name;

                if (!string.IsNullOrEmpty(boneName))
                    boneMap.Add(boneName, i);
            }

            // Convert each animation in turn.
            Dictionary<string, AnimationClip> animationClips;
            animationClips = new Dictionary<string, AnimationClip>();

            foreach (KeyValuePair<string, AnimationContent> animation in animations)
            {
                string[] animationProps = animation.Key.Split('_');

                if (animationProps.Length != 2)
                    throw new InvalidContentException(string.Format("[AnimationName: {0}]\r\nYou need to specify animatons like: AnimationName;Frames\r\nAlso make sure your first animation has enough frames to cover the maximum animation length due to an XNA bug.", animation.Key));

                string name = animationProps[0];
                int frames = int.Parse(animationProps[1]) - 1;

                animation.Value.Duration = TimeSpan.FromSeconds(frames * SecondsPerFrame);
                AnimationClip processed = ProcessAnimation(animation.Value, boneMap);

                animationClips.Add(name, processed);
            }

            if (animationClips.Count == 0)
            {
                throw new InvalidContentException(
                            "Input file does not contain any animations.");
            }

            return animationClips;
        }
        /// <summary>
        /// Called when an XML document is read that specifies how animations
        /// should be split.
        /// </summary>
        /// <param name="animDict">The dictionary of animation name/AnimationContent
        /// pairs. </param>
        /// <param name="doc">The Xml document that contains info on how to split
        /// the animations.</param>
        protected virtual void SubdivideAnimations(
            AnimationContentDictionary animDict, XmlDocument doc)
        {
            string[] animNames = new string[animDict.Keys.Count];
            animDict.Keys.CopyTo(animNames, 0);
            if (animNames.Length == 0)
                return;

            // Traverse each xml node that represents an animation to be subdivided
            foreach (XmlNode node in doc)
            {
                XmlElement child = node as XmlElement;
                if (child == null || child.Name != "animation")
                    continue;

                string animName = null;
                if (child["name"] != null)
                {
                    // The name of the animation to be split
                    animName = child["name"].InnerText;
                }
                else if (child["index"] != null)
                {
                    animName = animNames[int.Parse(child["index"].InnerText)];
                }
                else
                {
                    animName = animNames[0];
                }

                // If the tickspersecond node is filled, use that to calculate seconds per tick
                double animTicksPerSecond = 1.0, secondsPerTick = 0;
                try
                {
                    if (child["tickspersecond"] != null)
                    {
                        animTicksPerSecond = double.Parse(child["tickspersecond"].InnerText);
                    }
                }
                catch
                {
                    throw new Exception("Error parsing tickspersecond in xml file.");
                }
                if (animTicksPerSecond <= 0)
                    throw new InvalidDataException("AnimTicksPerSecond in XML file must be " +
                        "a positive number.");
                secondsPerTick = 1.0 / animTicksPerSecond;

                AnimationContent anim = null;
                // Get the animation and remove it from the dict
                // Check to see if the animation specified in the xml file exists
                try
                {
                    anim = animDict[animName];
                }
                catch
                {
                    throw new Exception("Animation named " + animName + " specified in XML file does not exist in model.");
                }
                animDict.Remove(anim.Name);
                // Get the list of new animations
                XmlNodeList subAnimations = child.GetElementsByTagName("animationsubset");

                foreach (XmlElement subAnim in subAnimations)
                {
                    // Create the new sub animation
                    AnimationContent newAnim = new AnimationContent();
                    XmlElement subAnimNameElement = subAnim["name"];

                    if (subAnimNameElement != null)
                        newAnim.Name = subAnimNameElement.InnerText;

                    // If a starttime node exists, use that to get the start time
                    long startTime, endTime;
                    if (subAnim["starttime"] != null)
                    {
                        try
                        {
                            startTime = TimeSpan.FromSeconds(double.Parse(subAnim["starttime"].InnerText)).Ticks;
                        }
                        catch
                        {
                            throw new Exception("Error parsing starttime node in XML file.  Node inner text "
                                + "must be a non negative number.");
                        }
                    }
                    else if (subAnim["startframe"] != null)// else use the secondspertick combined with the startframe node value
                    {
                        try
                        {
                            double seconds =
                                double.Parse(subAnim["startframe"].InnerText) * secondsPerTick;

                            startTime = TimeSpan.FromSeconds(
                                seconds).Ticks;
                        }
                        catch
                        {
                            throw new Exception("Error parsing startframe node in XML file.  Node inner text "
                              + "must be a non negative number.");
                        }
                    }
                    else
                        throw new Exception("Sub animation in XML file must have either a starttime or startframe node.");

                    // Same with endtime/endframe
                    if (subAnim["endtime"] != null)
                    {
                        try
                        {
                            endTime = TimeSpan.FromSeconds(double.Parse(subAnim["endtime"].InnerText)).Ticks;
                        }
                        catch
                        {
                            throw new Exception("Error parsing endtime node in XML file.  Node inner text "
                                + "must be a non negative number.");
                        }
                    }
                    else if (subAnim["endframe"] != null)
                    {
                        try
                        {
                            double seconds = double.Parse(subAnim["endframe"].InnerText)
                                * secondsPerTick;
                            endTime = TimeSpan.FromSeconds(
                                seconds).Ticks;
                        }
                        catch
                        {
                            throw new Exception("Error parsing endframe node in XML file.  Node inner text "
                                + "must be a non negative number.");
                        }
                    }
                    else
                        throw new Exception("Sub animation in XML file must have either an endtime or endframe node.");

                    if (endTime < startTime)
                        throw new Exception("Start time must be <= end time in XML file.");

                    // Now that we have the start and end times, we associate them with
                    // start and end indices for each animation track/channel
                    foreach (KeyValuePair<string, AnimationChannel> k in anim.Channels)
                    {
                        // The current difference between the start time and the
                        // time at the current index
                        long currentStartDiff;
                        // The current difference between the end time and the
                        // time at the current index
                        long currentEndDiff;
                        // The difference between the start time and the time
                        // at the start index
                        long bestStartDiff=long.MaxValue;
                        // The difference between the end time and the time at
                        // the end index
                        long bestEndDiff=long.MaxValue;

                        // The start and end indices
                        int startIndex = -1;
                        int endIndex = -1;

                        // Create a new channel and reference the old channel
                        AnimationChannel newChan = new AnimationChannel();
                        AnimationChannel oldChan = k.Value;

                        // Iterate through the keyframes in the channel
                        for (int i = 0; i < oldChan.Count; i++)
                        {
                            // Update the startIndex, endIndex, bestStartDiff,
                            // and bestEndDiff
                            long ticks = oldChan[i].Time.Ticks;
                            currentStartDiff = Math.Abs(startTime - ticks);
                            currentEndDiff = Math.Abs(endTime - ticks);
                            if (startIndex == -1 || currentStartDiff<bestStartDiff)
                            {
                                startIndex = i;
                                bestStartDiff = currentStartDiff;
                            }
                            if (endIndex == -1 || currentEndDiff<bestEndDiff)
                            {
                                endIndex = i;
                                bestEndDiff = currentEndDiff;
                            }
                        }

                        // Now we have our start and end index for the channel
                        for (int i = startIndex; i <= endIndex; i++)
                        {
                            AnimationKeyframe frame = oldChan[i];
                            long time;
                            // Clamp the time so that it can't be less than the
                            // start time
                            if (frame.Time.Ticks < startTime)
                                time = 0;
                            // Clamp the time so that it can't be greater than the
                            // end time
                            else if (frame.Time.Ticks > endTime)
                                time = endTime - startTime;
                            else // Else get the time
                                time = frame.Time.Ticks - startTime;

                            // Finally... create the new keyframe and add it to the new channel
                            AnimationKeyframe keyframe = new AnimationKeyframe(
                                TimeSpan.FromTicks(time),
                                frame.Transform);

                            newChan.Add(keyframe);
                        }

                        // Add the channel and update the animation duration based on the
                        // length of the animation track.
                        newAnim.Channels.Add(k.Key, newChan);
                        if (newChan[newChan.Count - 1].Time > newAnim.Duration)
                            newAnim.Duration = newChan[newChan.Count - 1].Time;

                    }
                    try
                    {
                        // Add the subdived animation to the dictionary.
                        animDict.Add(newAnim.Name, newAnim);
                    }
                    catch
                    {
                        throw new Exception("Attempt to add an animation when one by the same name already exists. " +
                            "Name: " + newAnim.Name);
                    }
                }

            }
        }
示例#32
0
 /// <summary>
 /// Creates an instance of NodeContent.
 /// </summary>
 public NodeContent()
 {
     children   = new NodeContentCollection(this);
     animations = new AnimationContentDictionary();
     Transform  = Matrix.Identity;
 }
        /// <summary>
        /// Extracts all animations and stores them in a dictionary of timelines.
        /// </summary>
        private Dictionary<string, SkeletonKeyFrameAnimation> ProcessAnimations(AnimationContentDictionary animationContentDictionary, Skeleton skeleton, ContentProcessorContext context)
        {
            var animations = new Dictionary<string, SkeletonKeyFrameAnimation>();
              foreach (var item in animationContentDictionary)
              {
            string animationName = item.Key;
            AnimationContent animationContent = item.Value;

            // Convert the AnimationContent to a SkeletonKeyFrameAnimation.
            SkeletonKeyFrameAnimation skeletonAnimation = ProcessAnimation(animationContent, skeleton, context);
            animations.Add(animationName, skeletonAnimation);
              }

              if (animations.Count == 0)
            context.Logger.LogWarning(null, null, "Skinned model does not contain any animations.");

              return animations;
        }
示例#34
0
 protected virtual void CollectAnimatedBones(AnimationContentDictionary dict, NodeContent bone)
 {
     AnimationContentDictionary acd = bone.Animations;
       if (acd != null)
       {
     foreach (string name in acd.Keys)
     {
       //  merge each animation into the dictionary
       AnimationContent ac = acd[name];
       AnimationContent xac;
       if (!dict.TryGetValue(name, out xac))
       {
     //  create it if we haven't already seen it, and there's something there
     if (ac.Channels.Count > 0)
     {
       xac = ac;
       dict.Add(name, xac);
     }
       }
       else
       {
     //  merge the animation content
     foreach (KeyValuePair<string, AnimationChannel> kvp in ac.Channels)
     {
       AnimationChannel ov;
       if (xac.Channels.TryGetValue(kvp.Key, out ov))
       {
         throw new System.ArgumentException(
             String.Format("The animation {0} has multiple channels named {1}.",
                 name, kvp.Key));
       }
       xac.Channels.Add(kvp.Key, kvp.Value);
     }
     xac.Duration = new TimeSpan((long)
         (Math.Max(xac.Duration.TotalSeconds, ac.Duration.TotalSeconds) * 1e7));
       }
     }
       }
       foreach (NodeContent nc in bone.Children)
     CollectAnimatedBones(dict, nc);
 }
示例#35
0
        /// <summary>
        /// The workhorse of the animation processor. It loops through all
        /// animations, all tracks, and all keyframes, and converts to the format
        /// expected by the runtime animation classes.
        /// </summary>
        /// <param name="input">The NodeContent to process. Comes from the base ModelProcessor.</param>
        /// <param name="output">The ModelContent that was produced. You don't typically change this.</param>
        /// <param name="context">The build context (logger, etc).</param>
        /// <returns>An allocated AnimationSet with the animations to include.</returns>
        public virtual AnimationSet BuildAnimationSet(NodeContent input, ref ModelContent output,
                                                      ContentProcessorContext context)
        {
            AnimationSet ret = new AnimationSet();

            if (!DoAnimations)
            {
                context.Logger.LogImportantMessage("DoAnimation is set to false for {0}; not generating animations.", input.Name);
                return(ret);
            }

            //  go from name to index
            Dictionary <string, ModelBoneContent> nameToIndex = new Dictionary <string, ModelBoneContent>();

            foreach (ModelBoneContent mbc in output.Bones)
            {
                nameToIndex.Add(GetBoneName(mbc), mbc);
            }

            AnimationContentDictionary adict = MergeAnimatedBones(input);

            if (adict == null || adict.Count == 0)
            {
                context.Logger.LogWarning("http://kwxport.sourceforge.net/", input.Identity,
                                          "Model processed with AnimationProcessor has no animations.");
                return(ret);
            }

            foreach (AnimationContent ac in adict.Values)
            {
                if (!IncludeAnimation(ac))
                {
                    context.Logger.LogImportantMessage(String.Format("Not including animation named {0}.", ac.Name));
                    continue;
                }
                context.Logger.LogImportantMessage(
                    "Processing animation {0} duration {1} sample rate {2} reduction tolerance {3}.",
                    ac.Name, ac.Duration, SampleRate, Tolerance);
                AnimationChannelDictionary acdict = ac.Channels;
                AnimationTrackDictionary   tracks = new AnimationTrackDictionary();
                foreach (string name in acdict.Keys)
                {
                    if (!IncludeTrack(ac, name))
                    {
                        context.Logger.LogImportantMessage(String.Format("Not including track named {0}.", name));
                        continue;
                    }

                    int ix = 0;
                    AnimationChannel achan = acdict[name];
                    int bix = nameToIndex[name].Index;
                    context.Logger.LogMessage("Processing bone {0}:{1}.", name, bix);
                    AnimationTrack at;
                    if (tracks.TryGetValue(bix, out at))
                    {
                        throw new System.ArgumentException(
                                  String.Format("Bone index {0} is used by multiple animations in the same clip (name {1}).",
                                                bix, name));
                    }

                    //  Sample at given frame rate from 0 .. Duration
                    List <Keyframe> kfl     = new List <Keyframe>();
                    int             nFrames = (int)Math.Floor(ac.Duration.TotalSeconds * SampleRate + 0.5);
                    for (int i = 0; i < nFrames; ++i)
                    {
                        Keyframe k = SampleChannel(achan, i / SampleRate, ref ix);
                        kfl.Add(k);
                    }

                    //  Run keyframe elimitation
                    Keyframe[] frames   = kfl.ToArray();
                    int        nReduced = 0;
                    if (tolerance_ > 0)
                    {
                        nReduced = ReduceKeyframes(frames, tolerance_);
                    }
                    if (nReduced > 0)
                    {
                        context.Logger.LogMessage("Reduced '{2}' from {0} to {1} frames.",
                                                  frames.Length, frames.Length - nReduced, name);
                    }

                    //  Create an AnimationTrack
                    at = new AnimationTrack(bix, frames);
                    tracks.Add(bix, at);
                }

                Animation a = new Animation(ac.Name, tracks, SampleRate);
                ret.AddAnimation(a);
            }

            //  build the special "identity" and "bind pose" animations
            AnimationTrackDictionary atd_id   = new AnimationTrackDictionary();
            AnimationTrackDictionary atd_bind = new AnimationTrackDictionary();

            foreach (KeyValuePair <string, ModelBoneContent> nip in nameToIndex)
            {
                Keyframe[] frames_id = new Keyframe[2];
                frames_id[0] = new Keyframe();
                frames_id[1] = new Keyframe();
                AnimationTrack at_id = new AnimationTrack(nip.Value.Index, frames_id);
                atd_id.Add(nip.Value.Index, at_id);

                Keyframe[] frames_bind = new Keyframe[2];
                Matrix     mat         = nip.Value.Transform;
                frames_bind[0] = Keyframe.CreateFromMatrix(mat);
                frames_bind[1] = new Keyframe();
                frames_bind[1].CopyFrom(frames_bind[0]);
                AnimationTrack at_bind = new AnimationTrack(nip.Value.Index, frames_bind);
                atd_bind.Add(nip.Value.Index, at_bind);
            }
            ret.AddAnimation(new Animation("$id$", atd_id, 1.0f));
            ret.AddAnimation(new Animation("$bind$", atd_bind, 1.0f));

            return(ret);
        }
示例#36
0
 protected virtual AnimationContentDictionary MergeAnimatedBones(NodeContent root)
 {
     AnimationContentDictionary ret = new AnimationContentDictionary();
       CollectAnimatedBones(ret, root);
       return ret;
 }
示例#37
0
        /// <summary>Processes a SkinnedModelImporter NodeContent root</summary>
        /// <param name="input">The root of the X file tree</param>
        /// <param name="context">The context for this processor</param>
        /// <returns>A model with animation data on its tag</returns>
        public override ModelContent Process(NodeContent input, ContentProcessorContext context)
        {
            context.Logger.LogImportantMessage("starting acl processing");
            ModelSplitter splitter;

            if (context.TargetPlatform != TargetPlatform.Xbox360)
            {
                splitter = new ModelSplitter(input, 56);
            }
            else
            {
                splitter = new ModelSplitter(input, 40);
            }
            modelSplit   = splitter.Split();
            splitter     = null;
            this.input   = input;
            this.context = context;
            FindMeshes(input);
            indexers = new BoneIndexer[numMeshes];
            for (int i = 0; i < indexers.Length; i++)
            {
                indexers[i] = new BoneIndexer();
            }
            foreach (MeshContent meshContent in meshes)
            {
                CreatePaletteIndices(meshContent);
            }

            // Get the process model minus the animation data
            ModelContent c = base.Process(input, context);

            if (!modelSplit && input.OpaqueData.ContainsKey("AbsoluteMeshTransforms"))
            {
                absoluteMeshTransforms =
                    (List <Matrix>)input.OpaqueData["AbsoluteMeshTransforms"];
            }
            else
            {
                foreach (MeshContent mesh in meshes)
                {
                    if (!ValidateMeshSkeleton(mesh))
                    {
                        context.Logger.LogWarning(null, mesh.Identity, "Warning: Mesh found that has a parent that exists as "
                                                  + "one of the bones in the skeleton attached to the mesh.  Change the mesh "
                                                  + "skeleton structure or use X - File Animation Library importer if transforms are incorrect.");
                    }
                }
            }

            Dictionary <string, object> dict = new Dictionary <string, object>();



            // Attach the animation and skinning data to the models tag
            FindAnimations(input);
            // Test to see if any animations have zero duration
            foreach (AnimationContent anim in animations.Values)
            {
                string errorMsg = "One or more AnimationContent objects have an extremely small duration.  If the animation "
                                  + "was intended to last more than one frame, please add \n AnimTicksPerSecond \n{0} \nY; \n{1}\n to your .X "
                                  + "file, where Y is a positive integer.";
                if (anim.Duration.Ticks < ContentUtil.TICKS_PER_60FPS)
                {
                    context.Logger.LogWarning("", anim.Identity, errorMsg, "{", "}");

                    break;
                }
            }

            XmlDocument xmlDoc = ReadAnimationXML(input);

            if (xmlDoc != null)
            {
                SubdivideAnimations(animations, xmlDoc);
            }

            AnimationContentDictionary processedAnims
                = new AnimationContentDictionary();

            try
            {
                foreach (KeyValuePair <string, AnimationContent> animKey in animations)
                {
                    AnimationContent processedAnim = ProcessAnimation(animKey.Value);
                    processedAnims.Add(animKey.Key, processedAnim);
                }
                dict.Add("Animations", processedAnims);
            }
            catch
            {
                throw new Exception("Error processing animations.");
            }

            foreach (ModelMeshContent meshContent in c.Meshes)
            {
                ReplaceBasicEffects(meshContent);
            }
            skinInfo = ProcessSkinInfo(c);
            dict.Add("SkinInfo", skinInfo);
            c.Tag = dict;
            return(c);
        }
示例#38
0
        public static void Split(AnimationContentDictionary animationDictionary, IList<AnimationSplitDefinition> splits, ContentIdentity contentIdentity, ContentProcessorContext context)
        {
            if (splits == null || splits.Count == 0)
            return;

              if (animationDictionary == null)
            return;

              if (contentIdentity == null)
            throw new ArgumentNullException("contentIdentity");

              if (context == null)
            throw new ArgumentNullException("context");

              if (animationDictionary.Count == 0)
              {
            context.Logger.LogWarning(null, contentIdentity, "The model does not have an animation. Animation splitting is skipped.");
            return;
              }

              if (animationDictionary.Count > 1)
            context.Logger.LogWarning(null, contentIdentity, "The model contains more than 1 animation. The animation splitting is performed on the first animation. Other animations are deleted!");

              // Get first animation.
              var originalAnimation = animationDictionary.First().Value;

              // Clear animation dictionary. - We do not keep the original animations!
              animationDictionary.Clear();

              // Add an animation to animationDictionary for each split.
              foreach (var split in splits)
              {
            TimeSpan startTime = split.StartTime;
            TimeSpan endTime = split.EndTime;

            var newAnimation = new AnimationContent
            {
              Name = split.Name,
              Duration = endTime - startTime
            };

            // Process all channels.
            foreach (var item in originalAnimation.Channels)
            {
              string channelName = item.Key;
              AnimationChannel originalChannel = item.Value;
              if (originalChannel.Count == 0)
            return;

              AnimationChannel newChannel = new AnimationChannel();

              // Add all key frames to the channel that are in the split interval.
              foreach (AnimationKeyframe keyFrame in originalChannel)
              {
            TimeSpan time = keyFrame.Time;
            if (startTime <= time && time <= endTime)
            {
              newChannel.Add(new AnimationKeyframe(keyFrame.Time - startTime, keyFrame.Transform));
            }
              }

              // Add channel if it contains key frames.
              if (newChannel.Count > 0)
            newAnimation.Channels.Add(channelName, newChannel);
            }

            if (newAnimation.Channels.Count == 0)
            {
              var message = string.Format(CultureInfo.InvariantCulture, "The split animation '{0}' is empty.", split.Name);
              throw new InvalidContentException(message, contentIdentity);
            }

            if (animationDictionary.ContainsKey(split.Name))
            {
              var message = string.Format(CultureInfo.InvariantCulture, "Cannot add split animation '{0}' because an animation with the same name already exits.", split.Name);
              throw new InvalidContentException(message, contentIdentity);
            }

            animationDictionary.Add(split.Name, newAnimation);
              }
        }
示例#39
0
 /// <summary>
 /// Creates an instance of NodeContent.
 /// </summary>
 public NodeContent()
 {
     children   = new NodeContentCollection(this);
     animations = new AnimationContentDictionary();
 }
        private AnimationClipContentDictionary ProcessAnimations(NodeContent input,
                                                                 AnimationContentDictionary animationDictionary,
                                                                 SkinnedModelBoneContentCollection boneCollection,
                                                                 ContentProcessorContext context)
        {
            // Create a collection here (Does not need a dictionary here)
            Dictionary <string, AnimationClipContent> animationClipDictionary =
                new Dictionary <string, AnimationClipContent>();

            foreach (AnimationContent animation in animationDictionary.Values)
            {
                // Validate animation
                if (!ValidateAnimation(animation, context))
                {
                    continue;
                }

                Dictionary <string, AnimationChannelContent> animationChannelDictionary =
                    new Dictionary <string, AnimationChannelContent>();

                // Process each animation channel (One channel per bone)
                foreach (KeyValuePair <string, AnimationChannel> animationChannelPair in
                         animation.Channels)
                {
                    // Validate animation channel
                    if (!ValidateAnimationChannel(animationChannelPair, animation, boneCollection,
                                                  context))
                    {
                        continue;
                    }

                    List <AnimationKeyframeContent> keyframeList =
                        new List <AnimationKeyframeContent>(animationChannelPair.Value.Count);

                    // Process all the keyframes of that channel
                    foreach (AnimationKeyframe channelKeyframe in animationChannelPair.Value)
                    {
                        // Extract the keyframe pose from its transform matrix
                        Pose keyframePose;
                        channelKeyframe.Transform.Decompose(out keyframePose.Scale,
                                                            out keyframePose.Orientation, out keyframePose.Translation);

                        keyframeList.Add(
                            new AnimationKeyframeContent(channelKeyframe.Time, keyframePose));
                    }

                    // Sort the keyframes by time
                    keyframeList.Sort();

                    animationChannelDictionary.Add(animationChannelPair.Key,
                                                   new AnimationChannelContent(keyframeList));
                }

                AnimationClipContent animationClip = new AnimationClipContent(
                    animation.Name, new AnimationChannelContentDictionary(animationChannelDictionary),
                    animation.Duration);

                animationClipDictionary.Add(animation.Name, animationClip);
            }

            // Split animations
            if (!string.IsNullOrEmpty(splitAnimationFilename))
            {
                SplitAnimations(input, animationClipDictionary, context);
            }

            return(new AnimationClipContentDictionary(animationClipDictionary));
        }
示例#41
0
        /// <summary>
        /// Converts an intermediate format content pipeline AnimationContentDictionary
        /// object to our runtime AnimationClip format.
        /// </summary>
        static Dictionary<string, Clip> ProcessAnimations(AnimationContentDictionary animations, IList<BoneContent> bones)
        {
            // Build up a table mapping bone names to indices.
            Dictionary<string, int> boneMap = new Dictionary<string, int>();

            for (int i = 0; i < bones.Count; i++)
            {
                string boneName = bones[i].Name;

                if (!string.IsNullOrEmpty(boneName))
                    boneMap.Add(boneName, i);
            }

            // Convert each animation in turn.
            Dictionary<string, Clip> animationClips;
            animationClips = new Dictionary<string, Clip>();

            foreach (KeyValuePair<string, AnimationContent> animation in animations)
            {
                Clip processed = ProcessAnimation(animation.Value, boneMap);
                processed.Name = animation.Key;

                animationClips.Add(animation.Key, processed);
            }

            return animationClips;
        }
示例#42
0
        public static void Split(AnimationContentDictionary animationDictionary, string splitFile, ContentIdentity contentIdentity, ContentProcessorContext context)
        {
            if (animationDictionary == null)
            {
                return;
            }

            if (string.IsNullOrEmpty(splitFile))
            {
                return;
            }

            if (contentIdentity == null)
            {
                throw new ArgumentNullException("contentIdentity");
            }

            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            if (animationDictionary.Count == 0)
            {
                context.Logger.LogWarning(null, contentIdentity, "The model does not have an animation. Animation splitting is skipped.");
                return;
            }

            if (animationDictionary.Count > 1)
            {
                context.Logger.LogWarning(null, contentIdentity, "The model contains more than 1 animation. The animation splitting is performed on the first animation. Other animations are deleted!");
            }

            // Load XML file.
            splitFile = ContentHelper.FindFile(splitFile, contentIdentity);
            XDocument document = XDocument.Load(splitFile, LoadOptions.SetLineInfo);

            // Let the content pipeline know that we depend on this file and we need to
            // rebuild the content if the file is modified.
            context.AddDependency(splitFile);

            // Parse XML.
            var animationsElement = document.Element("Animations");

            if (animationsElement == null)
            {
                context.Logger.LogWarning(null, contentIdentity, "The animation split file \"{0}\" does not contain an <Animations> root node.", splitFile);
                return;
            }

            var wrappedContext = new ContentPipelineContext(context);
            var splits         = ParseAnimationSplitDefinitions(animationsElement, contentIdentity, wrappedContext);

            if (splits == null || splits.Count == 0)
            {
                context.Logger.LogWarning(null, contentIdentity, "The XML file with the animation split definitions is invalid or empty. Animation is not split.");
                return;
            }

            // Split animations.
            Split(animationDictionary, splits, contentIdentity, context);
        }
示例#43
0
        public static void Split(AnimationContentDictionary animationDictionary, IList <AnimationSplitDefinition> splits, ContentIdentity contentIdentity, ContentProcessorContext context)
        {
            if (splits == null || splits.Count == 0)
            {
                return;
            }

            if (animationDictionary == null)
            {
                return;
            }

            if (contentIdentity == null)
            {
                throw new ArgumentNullException("contentIdentity");
            }

            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            if (animationDictionary.Count == 0)
            {
                context.Logger.LogWarning(null, contentIdentity, "The model does not have an animation. Animation splitting is skipped.");
                return;
            }

            if (animationDictionary.Count > 1)
            {
                context.Logger.LogWarning(null, contentIdentity, "The model contains more than 1 animation. The animation splitting is performed on the first animation. Other animations are deleted!");
            }

            // Get first animation.
            var originalAnimation = animationDictionary.First().Value;

            // Clear animation dictionary. - We do not keep the original animations!
            animationDictionary.Clear();

            // Add an animation to animationDictionary for each split.
            foreach (var split in splits)
            {
                TimeSpan startTime = split.StartTime;
                TimeSpan endTime   = split.EndTime;

                var newAnimation = new AnimationContent
                {
                    Name     = split.Name,
                    Duration = endTime - startTime
                };

                // Process all channels.
                foreach (var item in originalAnimation.Channels)
                {
                    string           channelName     = item.Key;
                    AnimationChannel originalChannel = item.Value;
                    if (originalChannel.Count == 0)
                    {
                        return;
                    }

                    AnimationChannel newChannel = new AnimationChannel();

                    // Add all key frames to the channel that are in the split interval.
                    foreach (AnimationKeyframe keyFrame in originalChannel)
                    {
                        TimeSpan time = keyFrame.Time;
                        if (startTime <= time && time <= endTime)
                        {
                            newChannel.Add(new AnimationKeyframe(keyFrame.Time - startTime, keyFrame.Transform));
                        }
                    }

                    // Add channel if it contains key frames.
                    if (newChannel.Count > 0)
                    {
                        newAnimation.Channels.Add(channelName, newChannel);
                    }
                }

                if (newAnimation.Channels.Count == 0)
                {
                    var message = string.Format(CultureInfo.InvariantCulture, "The split animation '{0}' is empty.", split.Name);
                    throw new InvalidContentException(message, contentIdentity);
                }

                if (animationDictionary.ContainsKey(split.Name))
                {
                    var message = string.Format(CultureInfo.InvariantCulture, "Cannot add split animation '{0}' because an animation with the same name already exits.", split.Name);
                    throw new InvalidContentException(message, contentIdentity);
                }

                animationDictionary.Add(split.Name, newAnimation);
            }
        }
示例#44
0
        /// <summary>
        /// Converts an intermediate format content pipeline AnimationContentDictionary
        /// object to our runtime AnimationClip format.
        /// </summary>
        /// <param name="animations">
        /// The animations.
        /// </param>
        /// <param name="bones">
        /// The bones.
        /// </param>
        /// <param name="context">
        /// The context.
        /// </param>
        /// <param name="source">
        /// The source.
        /// </param>
        private static Dictionary <string, AnimationClip> ProcessAnimations(
            AnimationContentDictionary animations,
            IList <BoneContent> bones,
            ContentProcessorContext context,
            string source)
        {
            // Build up a table mapping bone names to indices.
            var boneMap = new Dictionary <string, int>();

            for (int i = 0; i < bones.Count; i++)
            {
                string boneName = bones[i].Name;

                if (!string.IsNullOrEmpty(boneName))
                {
                    boneMap.Add(boneName, i);
                }
            }

            // Convert each animation in turn.
            Dictionary <string, AnimationClip> animationClips;

            animationClips = new Dictionary <string, AnimationClip>();

            string xmlFileName = source.Substring(0, source.IndexOf(".fbx")) + "Animation.xml";

            if (File.Exists(xmlFileName))
            {
                animationXML = new XmlDocument();
                animationXML.Load(xmlFileName);

                // get all animations
                XmlNodeList animationList = animationXML.GetElementsByTagName("animation");

                string name = string.Empty;
                int    keyframestart = -1, keyframeend = -1;

                foreach (XmlNode animationNode in animationList)
                {
                    foreach (XmlNode child in animationNode.ChildNodes)
                    {
                        if (child.Name == "name")
                        {
                            name = child.InnerText;
                        }
                        else if (child.Name == "startframe")
                        {
                            keyframestart = int.Parse(child.InnerText);
                        }
                        else if (child.Name == "endframe")
                        {
                            keyframeend = int.Parse(child.InnerText);
                        }
                    }

                    foreach (var animation in animations)
                    {
                        AnimationClip processed = ProcessAnimation(animation.Value, boneMap, keyframestart, keyframeend);

                        animationClips.Add(name, processed);
                    }
                }
            }
            else
            {
                foreach (var animation in animations)
                {
                    AnimationClip processed = ProcessAnimation(animation.Value, boneMap);

                    animationClips.Add(animation.Key, processed);
                }
            }

            if (animationClips.Count == 0)
            {
                throw new InvalidContentException("Input file does not contain any animations.");
            }

            return(animationClips);
        }
示例#45
0
        /// <summary>
        /// Converts an intermediate format content pipeline AnimationContentDictionary
        /// object to our runtime AnimationClip format.
        /// </summary>
        static Dictionary<string, AnimationClip> ProcessAnimations(
            AnimationContentDictionary animations, IList<BoneContent> bones)
        {
            // Build up a table mapping bone names to indices.
            Dictionary<string, int> boneMap = new Dictionary<string, int>();

            for (int i = 0; i < bones.Count; i++)
            {
                string boneName = bones[i].Name;

                if (!string.IsNullOrEmpty(boneName))
                    boneMap.Add(boneName, i);
            }

            // Convert each animation in turn.
            Dictionary<string, AnimationClip> animationClips;
            animationClips = new Dictionary<string, AnimationClip>();

            foreach (KeyValuePair<string, AnimationContent> animation in animations)
            {
                if (new[] {
                    "Stand",
                    "Walk",
                    "AttackUnarmed",
                    "Death",
                    "Fly",
                    "Idle",
                    "Run",
                    "ReadySpellCastDirectional",
                    "ReadySpellCastOmni",
                }.Contains(animation.Key))
                {
                    AnimationClip processed = ProcessAnimation(animation.Value, boneMap);

                    animationClips.Add(animation.Key, processed);
                }
            }

            if (animationClips.Count == 0)
            {
                throw new InvalidContentException("Input file does not contain any animations.");
            }

            return animationClips;
        }
        /// <summary>
        /// Converts an intermediate format content pipeline AnimationContentDictionary
        /// object to our runtime AnimationClip format.
        /// </summary>
        static Dictionary<string, AnimationClip> ProcessAnimations(
            AnimationContentDictionary animations, IList<BoneContent> bones,
            ContentProcessorContext context, ContentIdentity sourceIdentity)
        {
            // Build up a table mapping bone names to indices.
            Dictionary<string, int> boneMap = new Dictionary<string, int>();

            for (int i = 0; i < bones.Count; i++)
            {
                string boneName = bones[i].Name;

                if (!string.IsNullOrEmpty(boneName))
                    boneMap.Add(boneName, i);
            }

            // Convert each animation in turn.
            Dictionary<string, AnimationClip> animationClips;
            animationClips = new Dictionary<string, AnimationClip>();

            // We process the original animation first, so we can use their keyframes
            foreach (KeyValuePair<string, AnimationContent> animation in animations)
            {
                AnimationClip processed = ProcessAnimation(animation.Value, boneMap, animation.Key);

                animationClips.Add(animation.Key, processed);
            }

            // 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);

                // Break up the original animation clips into our new clips
                // First, we check if the clips contains our clip to break up
                if (animationClips.ContainsKey(AnimDef.OriginalClipName))
                {
                    // Grab the main clip that we are using
                    AnimationClip MainClip = animationClips[AnimDef.OriginalClipName];

                    // Now remove the original clip from our animations
                    animationClips.Remove(AnimDef.OriginalClipName);

                    // Process each of our new animation clip parts
                    foreach (AnimationDefinition.ClipPart Part in AnimDef.ClipParts)
                    {
                        // Calculate the frame times
                        TimeSpan StartTime = GetTimeSpanForFrame(Part.StartFrame, AnimDef.OriginalFrameCount, MainClip.Duration.Ticks);
                        TimeSpan EndTime = GetTimeSpanForFrame(Part.EndFrame, AnimDef.OriginalFrameCount, MainClip.Duration.Ticks);

                        // Get all the keyframes for the animation clip
                        // that fall within the start and end time
                        List<Keyframe> Keyframes = new List<Keyframe>();
                        foreach (Keyframe AnimFrame in MainClip.Keyframes)
                        {
                            if ((AnimFrame.Time >= StartTime) && (AnimFrame.Time <= EndTime))
                            {
                                Keyframe NewFrame = new Keyframe(AnimFrame.Bone, AnimFrame.Time - StartTime, AnimFrame.Transform);
                                Keyframes.Add(NewFrame);
                            }
                        }

                        // Process the events
                        List<AnimationEvent> Events = new List<AnimationEvent>();
                        if (Part.Events != null)
                        {
                            // Process each event
                            foreach (AnimationDefinition.ClipPart.Event Event in Part.Events)
                            {
                                // Get the event time within the animation
                                TimeSpan EventTime = GetTimeSpanForFrame(Event.Keyframe, AnimDef.OriginalFrameCount, MainClip.Duration.Ticks);

                                // Offset the event time so it is relative to the start of the animation
                                EventTime -= StartTime;

                                // Create the event
                                AnimationEvent NewEvent = new AnimationEvent();
                                NewEvent.EventTime = EventTime;
                                NewEvent.EventName = Event.Name;
                                Events.Add(NewEvent);
                            }
                        }

                        // Create the clip
                        AnimationClip NewClip = new AnimationClip(EndTime - StartTime, Keyframes, Events, Part.ClipName);
                        animationClips[Part.ClipName] = NewClip;
                    }
                }
            }

            if (animationClips.Count == 0)
            {
                throw new InvalidContentException(
                            "Input file does not contain any animations.");
            }

            return animationClips;
        }
        /// <summary>
        /// Converts an intermediate format content pipeline AnimationContentDictionary
        /// object to our runtime AnimationClip format.
        /// </summary>
        static Dictionary<string, Clip> ProcessAnimations(
            AnimationContentDictionary animations,
            IList<BoneContent> bones,
            List<ClipData> clipInfo)
        {
            // Build up a table mapping bone names to indices.
            Dictionary<string, int> boneMap = new Dictionary<string, int>();

            for (int i = 0; i < bones.Count; i++)
            {
                string boneName = bones[i].Name;

                if (!string.IsNullOrEmpty(boneName))
                    boneMap.Add(boneName, i);
            }

            // Convert each animation in turn.
            Dictionary<string, Clip> animationClips = new Dictionary<string, Clip>();
            foreach (ClipData clip in clipInfo)
            {
                Clip processed = ProcessAnimation(animations[clip.SourceTake], boneMap, clip);

                animationClips.Add(clip.Alias, processed);
            }

            if (animationClips.Count == 0)
            {
                throw new InvalidContentException("Input file does not contain any animations.");
            }

            return animationClips;
        }
        /// <summary>Processes a SkinnedModelImporter NodeContent root</summary>
        /// <param name="input">The root of the X file tree</param>
        /// <param name="context">The context for this processor</param>
        /// <returns>A model with animation data on its tag</returns>
        public override ModelContent Process(NodeContent input, ContentProcessorContext context)
        {
            ModelSplitter splitter;
            if (context.TargetPlatform != TargetPlatform.Xbox360)
            {
                splitter = new ModelSplitter(input, 56);
            }
            else
            {
                splitter = new ModelSplitter(input, 40);
            }
            modelSplit = splitter.Split();
            splitter = null;
            this.input = input;
            this.context = context;
            FindMeshes(input);
            indexers = new BoneIndexer[numMeshes];
            for (int i = 0; i < indexers.Length; i++)
            {
                indexers[i] = new BoneIndexer();
            }
            foreach (MeshContent meshContent in meshes)
                CreatePaletteIndices(meshContent);

            // Get the process model minus the animation data
            ModelContent c = base.Process(input, context);

            if (!modelSplit && input.OpaqueData.ContainsKey("AbsoluteMeshTransforms"))
            {
                absoluteMeshTransforms =
                    (List<Matrix>)input.OpaqueData["AbsoluteMeshTransforms"];
            }
            else
            {

                foreach (MeshContent mesh in meshes)
                {
                    if (!ValidateMeshSkeleton(mesh))
                    {
                        context.Logger.LogWarning(null, mesh.Identity, "Warning: Mesh found that has a parent that exists as "
                            + "one of the bones in the skeleton attached to the mesh.  Change the mesh "
                            + "skeleton structure or use X - File Animation Library importer if transforms are incorrect.");
                    }
                }

            }

            Dictionary<string, object> dict = new Dictionary<string, object>();

            // Attach the animation and skinning data to the models tag
            FindAnimations(input);
            // Test to see if any animations have zero duration
            foreach (AnimationContent anim in animations.Values)
            {
                string errorMsg =                         "One or more AnimationContent objects have an extremely small duration.  If the animation "
                        + "was intended to last more than one frame, please add \n AnimTicksPerSecond \n{0} \nY; \n{1}\n to your .X "
                        + "file, where Y is a positive integer.";
                if (anim.Duration.Ticks < ContentUtil.TICKS_PER_60FPS)
                {
                    context.Logger.LogWarning("", anim.Identity, errorMsg, "{", "}");

                    break;
                }
            }

            XmlDocument xmlDoc = ReadAnimationXML(input);

            if (xmlDoc != null)
            {
                SubdivideAnimations(animations, xmlDoc);
            }

            AnimationContentDictionary processedAnims
                = new AnimationContentDictionary();
            try
            {
                foreach (KeyValuePair<string, AnimationContent> animKey in animations)
                {
                    AnimationContent processedAnim = ProcessAnimation(animKey.Value);
                    processedAnims.Add(animKey.Key, processedAnim);

                }
                dict.Add("Animations", processedAnims);
            }
            catch
            {
                throw new Exception("Error processing animations.");
            }

            foreach (ModelMeshContent meshContent in c.Meshes)
                ReplaceBasicEffects(meshContent);
            skinInfo = ProcessSkinInfo(c);
            dict.Add("SkinInfo", skinInfo);
            c.Tag = dict;
            return c;
        }
示例#49
0
 /// <summary>
 /// Creates an instance of NodeContent.
 /// </summary>
 public NodeContent()
 {
     children = new NodeContentCollection(this);
     animations = new AnimationContentDictionary();
 }
示例#50
0
        /// <summary>
        /// Converts an intermediate format content pipeline AnimationContentDictionary
        /// object to our runtime AnimationClip format.
        /// </summary>
        static Dictionary <string, AnimationClip> ProcessAnimations(
            AnimationContentDictionary animations, IList <BoneContent> bones,
            ContentProcessorContext context, ContentIdentity sourceIdentity)
        {
            // Build up a table mapping bone names to indices.
            Dictionary <string, int> boneMap = new Dictionary <string, int>();

            for (int i = 0; i < bones.Count; i++)
            {
                string boneName = bones[i].Name;

                if (!string.IsNullOrEmpty(boneName))
                {
                    boneMap.Add(boneName, i);
                }
            }

            // Convert each animation in turn.
            Dictionary <string, AnimationClip> animationClips;

            animationClips = new Dictionary <string, AnimationClip>();

            // We process the original animation first, so we can use their keyframes
            foreach (KeyValuePair <string, AnimationContent> animation in animations)
            {
                AnimationClip processed = ProcessAnimation(animation.Value, boneMap, animation.Key);

                animationClips.Add(animation.Key, processed);
            }

            // 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);

                // Break up the original animation clips into our new clips
                // First, we check if the clips contains our clip to break up
                if (animationClips.ContainsKey(AnimDef.OriginalClipName))
                {
                    // Grab the main clip that we are using
                    AnimationClip MainClip = animationClips[AnimDef.OriginalClipName];

                    // Now remove the original clip from our animations
                    animationClips.Remove(AnimDef.OriginalClipName);

                    // Process each of our new animation clip parts
                    foreach (AnimationDefinition.ClipPart Part in AnimDef.ClipParts)
                    {
                        // Calculate the frame times
                        TimeSpan StartTime = GetTimeSpanForFrame(Part.StartFrame, AnimDef.OriginalFrameCount, MainClip.Duration.Ticks);
                        TimeSpan EndTime   = GetTimeSpanForFrame(Part.EndFrame, AnimDef.OriginalFrameCount, MainClip.Duration.Ticks);

                        // Get all the keyframes for the animation clip
                        // that fall within the start and end time
                        List <Keyframe> Keyframes = new List <Keyframe>();
                        foreach (Keyframe AnimFrame in MainClip.Keyframes)
                        {
                            if ((AnimFrame.Time >= StartTime) && (AnimFrame.Time <= EndTime))
                            {
                                Keyframe NewFrame = new Keyframe(AnimFrame.Bone, AnimFrame.Time - StartTime, AnimFrame.Transform);
                                Keyframes.Add(NewFrame);
                            }
                        }

                        // Process the events
                        List <AnimationEvent> Events = new List <AnimationEvent>();
                        if (Part.Events != null)
                        {
                            // Process each event
                            foreach (AnimationDefinition.ClipPart.Event Event in Part.Events)
                            {
                                // Get the event time within the animation
                                TimeSpan EventTime = GetTimeSpanForFrame(Event.Keyframe, AnimDef.OriginalFrameCount, MainClip.Duration.Ticks);

                                // Offset the event time so it is relative to the start of the animation
                                EventTime -= StartTime;

                                // Create the event
                                AnimationEvent NewEvent = new AnimationEvent();
                                NewEvent.EventTime = EventTime;
                                NewEvent.EventName = Event.Name;
                                Events.Add(NewEvent);
                            }
                        }

                        // Create the clip
                        AnimationClip NewClip = new AnimationClip(EndTime - StartTime, Keyframes, Events, Part.ClipName);
                        animationClips[Part.ClipName] = NewClip;
                    }
                }
            }

            if (animationClips.Count == 0)
            {
                throw new InvalidContentException(
                          "Input file does not contain any animations.");
            }

            return(animationClips);
        }