} // ProcessVertexChannel

        #endregion

        #region Process Animations

        /// <summary>
        /// Converts an intermediate format content pipeline AnimationContentDictionary object to our runtime AnimationClip format.
        /// </summary>
        static void ProcessAnimations(NodeContent input, ModelContent model,
                                      Dictionary<string, ModelAnimationClip> modelAnimationClips,
                                      Dictionary<string, RootAnimationClip> rootAnimationClips)
        {            
            // Build up a table mapping bone names to indices.
            Dictionary<string, int> boneMap = new Dictionary<string, int>();
            for (int i = 0; i < model.Bones.Count; i++)
            {
                string boneName = model.Bones[i].Name;
            
                if (!string.IsNullOrEmpty(boneName))
                    boneMap.Add(boneName, i);
            }

            // Convert each animation in the root of the object            
            foreach (KeyValuePair<string, AnimationContent> animation in input.Animations)
            {
                RootAnimationClip processed = ProcessRootAnimation(animation.Value, model.Bones[0].Name);

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

            // Get the unique names of the animations on the mesh children
            List<string> animationNames = new List<string>();
            AddAnimationNodes(animationNames, input);

            // Now create those animations
            foreach (string key in animationNames)
            {
                ModelAnimationClip processed = ProcessRigidAnimation(key, boneMap, input, model);
                
                modelAnimationClips.Add(key, processed);
            }
        } // ProcessAnimations
Пример #2
0
        /// <summary>
        /// The main Process method converts an intermediate format content pipeline
        /// NodeContent tree to a ModelContent object with embedded animation data.
        /// </summary>
        public override ModelContent Process(NodeContent input, ContentProcessorContext context)
        {
            ValidateMesh(input, context, null);

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

            if (skeleton == null)
            {
                throw new InvalidContentException("Input skeleton not found.");
            }

            // We don't want to have to worry about different parts of the model being in different local coordinate systems, so let's just bake everything.
            FlattenTransforms(input, skeleton);

            // Read the bind pose and skeleton hierarchy data.
            IList <BoneContent> bones = MeshHelper.FlattenSkeleton(skeleton);

            if (bones.Count > ModelAnimationClip.MaxBones)
            {
                throw new InvalidContentException(string.Format("Skeleton has {0} bones, but the maximum supported is {1}.", bones.Count, ModelAnimationClip.MaxBones));
            }

            List <Matrix>            bindPose          = new List <Matrix>();
            List <Matrix>            inverseBindPose   = new List <Matrix>();
            List <int>               skeletonHierarchy = new List <int>();
            Dictionary <string, int> boneIndices       = new Dictionary <string, int>();

            foreach (BoneContent bone in bones)
            {
                bindPose.Add(bone.Transform);
                inverseBindPose.Add(Matrix.Invert(bone.AbsoluteTransform));
                skeletonHierarchy.Add(bones.IndexOf(bone.Parent as BoneContent));
                boneIndices.Add(bone.Name, boneIndices.Count);
            }

            // Convert animation data to our runtime format.
            Dictionary <string, ModelAnimationClip> modelAnimationClips = ProcessAnimations(skeleton.Animations, bones, context);

            Dictionary <string, RootAnimationClip> rootAnimationClips = new Dictionary <string, RootAnimationClip>();

            // Chain to the base ModelProcessor class so it can convert the model data.
            ModelContent model = base.Process(input, context);

            // Convert each animation in the root of the object
            foreach (KeyValuePair <string, AnimationContent> animation in input.Animations)
            {
                RootAnimationClip processed = RigidModelProcessor.ProcessRootAnimation(animation.Value, model.Bones[0].Name);

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

            // Store our custom animation data in the Tag property of the model.
            model.Tag = new ModelAnimationData(modelAnimationClips, rootAnimationClips, bindPose, inverseBindPose, skeletonHierarchy, boneIndices);

            return(model);
        } // Process
Пример #3
0
        } // ResumeClip

        #endregion

        #region Stop

        /// <summary>
        /// Stops playing the sound.
        /// </summary>
        /// <param name="immediate">
        /// Specifies whether to stop playing immediately, or to break out of the loop region and play the release.
        /// Specify true to stop playing immediately, or false to break out of the loop region and play the release phase (the remainder of the sound).
        /// </param>
        public void Stop(bool immediate = true)
        {
            if (immediate)
            {
                currentAnimationClip = null;
            }
            else
            {
                stopWhenCicleFinishes = true;
            }
        } // Stop
Пример #4
0
        } // Initialize

        #endregion

        #region Uninitialize

        /// <summary>
        /// Uninitialize the component.
        /// Is important to remove event associations and any other reference.
        /// </summary>
        internal override void Uninitialize()
        {
            currentAnimationClip = null;
            cachedModel          = null;
            ((GameObject3D)Owner).ModelFilterChanged -= OnModelFilterChanged;
            if (((GameObject3D)Owner).ModelFilter != null)
            {
                ((GameObject3D)Owner).ModelFilter.ModelChanged -= OnModelChanged;
            }
            // Call this last because the owner information is needed.
            base.Uninitialize();
        } // Uninitialize
Пример #5
0
        } // Stop

        #endregion

        #region Update

        /// <summary>
        /// Called during the update loop to move the animation forward
        /// </summary>
        public virtual void Update()
        {
            if (currentAnimationClip == null)
            {
                return;
            }
            if (paused)
            {
                return;
            }

            // Adjust for the rate
            float time = Time.GameDeltaTime * playbackRate;

            elapsedPlaybackTime += time;

            // See if we should terminate
            if (elapsedPlaybackTime > duration && duration != 0 || elapsedPlaybackTime > currentAnimationClip.Duration && duration == 0)
            {
                // Animation Completed
                currentAnimationClip = null;
                return;
            }

            // Update the animation position.
            time += currentTimeValue;
            // If we reached the end, loop back to the start.
            while (time >= currentAnimationClip.Duration)
            {
                if (stopWhenCicleFinishes)
                {
                    currentAnimationClip = null;
                    return;
                }
                time -= currentAnimationClip.Duration;
            }

            CurrentTimeValue = time;

            // Update transform Matrix.
            // The animation information is absolute but we need relative information so that different transformations could be applied to the transform at the same time.
            ((GameObject3D)Owner).Transform.LocalMatrix = currentKeyFrame.Transform * Matrix.Invert(previousAnimationTransform) * ((GameObject3D)Owner).Transform.LocalMatrix;
            previousAnimationTransform = currentKeyFrame.Transform;
        } // Update
Пример #6
0
        } // RootAnimation

        /// <summary>
        /// Load root animation data from a .x or fbx file.
        /// </summary>
        public RootAnimation(string filename)
        {
            Name = filename;
            Filename = AssetContentManager.GameDataDirectory + "Animations\\" + filename;
            if (File.Exists(Filename + ".xnb") == false)
            {
                throw new ArgumentException("Failed to load animation data: File " + Filename + " does not exists!", "filename");
            }
            try
            {
                Resource = AssetContentManager.CurrentContentManager.XnaContentManager.Load<RootAnimationClip>(Filename);
            }
            catch (ObjectDisposedException)
            {
                throw new InvalidOperationException("Content Manager: Content manager disposed");
            }
            catch (Exception e)
            {
                throw new InvalidOperationException("Failed to load animation data: " + filename, e);
            }
        } // RootAnimation
Пример #7
0
        } // Play

        /// <summary>
        /// Starts playing a clip
        /// </summary>
        /// <param name="name">Animation name</param>
        /// <param name="playbackRate">Speed to playback</param>
        /// <param name="duration">Length of time to play in seconds (max is looping, 0 is once)</param>
        public void Play(string name, float playbackRate, float duration)
        {
            if (!rootAnimations.ContainsKey(name))
            {
                throw new ArgumentException("Root Animation Component: the animation name does not exist.");
            }

            // Store the clip and reset playing data
            currentAnimationClip = rootAnimations[name];
            currentKeyFrameIndex = 0;
            currentKeyFrame      = currentAnimationClip.Keyframes[0];
            CurrentTimeValue     = 0;
            elapsedPlaybackTime  = 0;
            paused = false;

            // Store the data about how we want to playback
            this.playbackRate = playbackRate;
            this.duration     = duration;

            previousAnimationTransform = ((GameObject3D)Owner).Transform.LocalMatrix;
        } // Play
Пример #8
0
        } // RootAnimation

        #endregion

        #region Recreate Resource

        /// <summary>
        /// Useful when the XNA device is disposed.
        /// </summary>
        internal override void RecreateResource()
        {
            Resource = AssetContentManager.CurrentContentManager.XnaContentManager.Load<RootAnimationClip>(Filename);
        } // RecreateResource
Пример #9
0
 /// <summary>
 /// Internal Constructor for File Model assets.
 /// </summary>
 internal RootAnimation(string name, RootAnimationClip resource)
 {
     Name = name;
     Resource = resource;
     ContentManager = null; // This is controled by the own file model.
 } // RootAnimation