Exemple #1
0
        private AnimationContent CreateAnimation(Assimp.Animation aiAnimation)
        {
            var animation = new AnimationContent
            {
                Name     = FixupAnimationName(aiAnimation.Name),
                Duration = TimeSpan.FromSeconds(aiAnimation.DurationInTicks / aiAnimation.TicksPerSecond)
            };

            foreach (var aiChannel in aiAnimation.NodeAnimationChannels)
            {
                var channel = new AnimationChannel();

                // We can have different numbers of keyframes for each, so find the max index.
                var keyCount = Math.Max(aiChannel.PositionKeyCount, Math.Max(aiChannel.RotationKeyCount, aiChannel.ScalingKeyCount));

                // Get all unique keyframe times
                var times = aiChannel.PositionKeys.Select(k => k.Time)
                            .Union(aiChannel.RotationKeys.Select(k => k.Time))
                            .Union(aiChannel.ScalingKeys.Select(k => k.Time))
                            .Distinct().ToList();

                // The rest of this loop is almost certainly wrong. Don't trust it.
                // There's some magical combination, ordering, or transposition we have
                // to figure out to translate FBX->Assimp->XNA.
                // Possibilities: matrix offset transform, missing a base transform, an extra base transform, etc.

                var toBoneSpace = _objectToBone.ContainsKey(aiChannel.NodeName)
                    ? _objectToBone[aiChannel.NodeName] * _skeletonRoot.Transform
                    : _skeletonRoot.Transform;

                foreach (var aiKeyTime in times)
                {
                    var time          = TimeSpan.FromSeconds(aiKeyTime / aiAnimation.TicksPerSecond);
                    var translation   = Matrix4x4.FromTranslation(aiChannel.PositionKeys.FirstOrDefault(k => k.Time == aiKeyTime).Value);
                    var rotation      = new Matrix4x4(aiChannel.RotationKeys.FirstOrDefault(k => k.Time == aiKeyTime).Value.GetMatrix());
                    var scale         = Matrix4x4.FromScaling(aiChannel.ScalingKeys.FirstOrDefault(k => k.Time == aiKeyTime).Value);
                    var nodeTransform = translation * rotation * scale;

                    var xform = toBoneSpace * nodeTransform * _globalInverseXform;
                    channel.Add(new AnimationKeyframe(time, ToXna(xform)));
                }

                animation.Channels.Add(aiChannel.NodeName, channel);
            }

            return(animation);
        }
        List <AnimationContent> CreateAnimations()
        {
            var animations = new List <AnimationContent>();

            for (int i = 0; i < collada.JointAnimations.Count; i++)
            {
                var sourceAnim = collada.JointAnimations[i];

                AnimationContent animation = new AnimationContent();
                animation.Name     = sourceAnim.Name ?? String.Format("Take {0:000}", (i + 1));
                animation.Duration = TimeSpan.FromSeconds(sourceAnim.EndTime - sourceAnim.StartTime);

                foreach (var sourceChannel in sourceAnim.Channels)
                {
                    AnimationChannel channel = new AnimationChannel();

                    // Adds the different keyframes to the animation channel
                    // NOTE: Might be better to sample the keyframes
                    foreach (var sourceKeyframe in sourceChannel.Sampler.Keyframes)
                    {
                        TimeSpan time      = TimeSpan.FromSeconds(sourceKeyframe.Time);
                        Matrix   transform = sourceKeyframe.Transform;

                        AnimationKeyframe keyframe = new AnimationKeyframe(time, transform);
                        channel.Add(keyframe);
                    }

                    String key = GetJointKey(sourceChannel.Target);
                    animation.Channels.Add(key, channel);
                }

                animation.OpaqueData.Add("FPS", sourceAnim.FramesPerSecond);
                animations.Add(animation);
            }

            return(animations);
        }
        /// <summary>
        /// Interpolates an AnimationContent object to 60 fps.
        /// </summary>
        /// <param name="input">The AnimationContent to interpolate.</param>
        /// <returns>The interpolated AnimationContent.</returns>
        public virtual AnimationContent Interpolate(AnimationContent input)
        {
            AnimationContent output            = new AnimationContent();
            long             time              = 0;
            long             animationDuration = input.Duration.Ticks;

            // default XNA importers, due to floating point errors or TimeSpan
            // estimation, sometimes  have channels with a duration slightly longer than
            // the animation duration.  So, set the animation duration to its true
            // value
            foreach (KeyValuePair <string, AnimationChannel> c in input.Channels)
            {
                if (c.Value[c.Value.Count - 1].Time.Ticks > animationDuration)
                {
                    animationDuration = c.Value[c.Value.Count - 1].Time.Ticks;
                }
            }

            foreach (KeyValuePair <string, AnimationChannel> c in input.Channels)
            {
                time = 0;
                string           channelName = c.Key;
                AnimationChannel channel     = c.Value;
                AnimationChannel outChannel  = new AnimationChannel();
                int currentFrame             = 0;

                // Step through time until the time passes the animation duration
                while (time <= animationDuration)
                {
                    AnimationKeyframe keyframe;
                    // Clamp the time to the duration of the animation and make this
                    // keyframe equal to the last animation frame.
                    if (time >= animationDuration)
                    {
                        time     = animationDuration;
                        keyframe = new AnimationKeyframe(new TimeSpan(time),
                                                         channel[channel.Count - 1].Transform);
                    }
                    else
                    {
                        // If the channel only has one keyframe, set the transform for the current time
                        // to that keyframes transform
                        if (channel.Count == 1 || time < channel[0].Time.Ticks)
                        {
                            keyframe = new AnimationKeyframe(new TimeSpan(time), channel[0].Transform);
                        }
                        // If the current track duration is less than the animation duration,
                        // use the last transform in the track once the time surpasses the duration
                        else if (channel[channel.Count - 1].Time.Ticks <= time)
                        {
                            keyframe = new AnimationKeyframe(new TimeSpan(time), channel[channel.Count - 1].Transform);
                        }
                        else // proceed as normal
                        {
                            // Go to the next frame that is less than the current time
                            while (channel[currentFrame + 1].Time.Ticks < time)
                            {
                                currentFrame++;
                            }
                            // Numerator of the interpolation factor
                            double interpNumerator = (double)(time - channel[currentFrame].Time.Ticks);
                            // Denominator of the interpolation factor
                            double interpDenom = (double)(channel[currentFrame + 1].Time.Ticks - channel[currentFrame].Time.Ticks);
                            // The interpolation factor, or amount to interpolate between the current
                            // and next frame
                            double interpAmount = interpNumerator / interpDenom;

                            // If the frames are roughly 60 frames per second apart, use linear interpolation
                            if (channel[currentFrame + 1].Time.Ticks - channel[currentFrame].Time.Ticks
                                <= ContentUtil.TICKS_PER_60FPS * 1.05)
                            {
                                keyframe = new AnimationKeyframe(new TimeSpan(time),
                                                                 Matrix.Lerp(
                                                                     channel[currentFrame].Transform,
                                                                     channel[currentFrame + 1].Transform,
                                                                     (float)interpAmount));
                            }
                            else // else if the transforms between the current frame and the next aren't identical
                                 // decompose the matrix and interpolate the rotation separately
                            if (channel[currentFrame].Transform != channel[currentFrame + 1].Transform)
                            {
                                keyframe = new AnimationKeyframe(new TimeSpan(time),
                                                                 ContentUtil.SlerpMatrix(
                                                                     channel[currentFrame].Transform,
                                                                     channel[currentFrame + 1].Transform,
                                                                     (float)interpAmount));
                            }
                            else // Else the adjacent frames have identical transforms and we can use
                                 // the current frames transform for the current keyframe.
                            {
                                keyframe = new AnimationKeyframe(new TimeSpan(time),
                                                                 channel[currentFrame].Transform);
                            }
                        }
                    }
                    // Add the interpolated keyframe to the new channel.
                    outChannel.Add(keyframe);
                    // Step the time forward by 1/60th of a second
                    time += ContentUtil.TICKS_PER_60FPS;
                }

                // Compensate for the time error,(animation duration % TICKS_PER_60FPS),
                // caused by the interpolation by setting the last keyframe in the
                // channel to the animation duration.
                if (outChannel[outChannel.Count - 1].Time.Ticks < animationDuration)
                {
                    outChannel.Add(new AnimationKeyframe(
                                       TimeSpan.FromTicks(animationDuration),
                                       channel[channel.Count - 1].Transform));
                }

                outChannel.Add(new AnimationKeyframe(input.Duration,
                                                     channel[channel.Count - 1].Transform));
                // Add the interpolated channel to the animation
                output.Channels.Add(channelName, outChannel);
            }
            // Set the interpolated duration to equal the inputs duration for consistency
            output.Duration = TimeSpan.FromTicks(animationDuration);
            return(output);
        }
Exemple #4
0
        /*
         * template Animation
         * {
         * [...]
         * }
         */
        /// <summary>
        /// Fills in all the channels of an animation.  Each channel refers to
        /// a single bone's role in the animation.
        /// </summary>
        /// <param name="boneName">The name of the bone associated with the channel</param>
        /// <returns>The imported animation channel</returns>
        private AnimationChannel ImportAnimationChannel(out string boneName)
        {
            AnimationChannel anim = new AnimationChannel();

            // Store the frames in an array, which acts as an intermediate data set
            // This will allow us to more easily provide support for non Matrix
            // animation keys at a later time
            AnimationKeyframe[]      rotFrames    = null;
            AnimationKeyframe[]      transFrames  = null;
            AnimationKeyframe[]      scaleFrames  = null;
            List <AnimationKeyframe> matrixFrames = null;

            boneName = null;
            tokens.SkipName();
            for (string next = tokens.NextToken(); next != "}"; next = tokens.NextToken())
            {
                // A set of animation keys
                if (next == "AnimationKey")
                {
                    // These keys can be rotation (0),scale(1),translation(2), or matrix(3 or 4) keys.
                    int keyType;
                    AnimationKeyframe[] frames = ImportAnimationKey(out keyType);
                    if (keyType == 0)
                    {
                        rotFrames = frames;
                    }
                    else if (keyType == 1)
                    {
                        scaleFrames = frames;
                    }
                    else if (keyType == 2)
                    {
                        transFrames = frames;
                    }
                    else
                    {
                        matrixFrames = new List <AnimationKeyframe>(frames);
                    }
                }
                // A possible bone name
                else if (next == "{")
                {
                    string token = tokens.NextToken();
                    if (tokens.NextToken() != "}")
                    {
                        tokens.SkipNode();
                    }
                    else
                    {
                        boneName = token;
                    }
                }
            }
            // Fill in the channel with the frames
            if (matrixFrames != null)
            {
                matrixFrames.Sort(new Comparison <AnimationKeyframe>(delegate(AnimationKeyframe one,
                                                                              AnimationKeyframe two)
                {
                    return(one.Time.CompareTo(two.Time));
                }));
                if (matrixFrames[0].Time != TimeSpan.Zero)
                {
                    matrixFrames.Insert(0, new AnimationKeyframe(new TimeSpan(),
                                                                 matrixFrames[0].Transform));
                }
                for (int i = 0; i < matrixFrames.Count; i++)
                {
                    Matrix m = matrixFrames[i].Transform;
                    ContentUtil.ReflectMatrix(ref m);
                    matrixFrames[i].Transform = m;
                    anim.Add(matrixFrames[i]);
                }
            }
            else
            {
                List <AnimationKeyframe> combinedFrames = ContentUtil.MergeKeyFrames(
                    scaleFrames, transFrames, rotFrames);
                for (int i = 0; i < combinedFrames.Count; i++)
                {
                    Matrix m = combinedFrames[i].Transform;
                    ContentUtil.ReflectMatrix(ref m);
                    combinedFrames[i].Transform = m; //* Matrix.CreateRotationX(MathHelper.PiOver2);
                    anim.Add(combinedFrames[i]);
                }
            }
            return(anim);
        }
        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);
              }
        }
        /// <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);
                    }
                }
            }
        }
        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);
            }
        }
        /// <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);
                    }
                }

            }
        }
        /// <summary>
        /// Converts the specified animation to XNA.
        /// </summary>
        /// <param name="aiAnimation">The animation.</param>
        /// <returns>The animation converted to XNA.</returns>
        private AnimationContent ImportAnimation(Animation aiAnimation)
        {
            var animation = new AnimationContent
            {
                Name     = GetAnimationName(aiAnimation.Name),
                Identity = _identity,
                Duration = TimeSpan.FromSeconds(aiAnimation.DurationInTicks / aiAnimation.TicksPerSecond)
            };

            // In Assimp animation channels may be split into separate channels.
            //   "nodeXyz" --> "nodeXyz_$AssimpFbx$_Translation",
            //                 "nodeXyz_$AssimpFbx$_Rotation",
            //                 "nodeXyz_$AssimpFbx$_Scaling"
            // Group animation channels by name (strip the "_$AssimpFbx$" part).
            var channelGroups = aiAnimation.NodeAnimationChannels
                                .GroupBy(channel => GetNodeName(channel.NodeName));

            foreach (var channelGroup in channelGroups)
            {
                var boneName = channelGroup.Key;
                var channel  = new AnimationChannel();

                // Get transformation pivot for current bone.
                FbxPivot pivot;
                if (!_pivots.TryGetValue(boneName, out pivot))
                {
                    pivot = FbxPivot.Default;
                }

                var scaleKeys       = EmptyVectorKeys;
                var rotationKeys    = EmptyQuaternionKeys;
                var translationKeys = EmptyVectorKeys;

                foreach (var aiChannel in channelGroup)
                {
                    if (aiChannel.NodeName.EndsWith("_$AssimpFbx$_Scaling"))
                    {
                        scaleKeys = aiChannel.ScalingKeys;

                        Debug.Assert(pivot.Scaling.HasValue);
                        Debug.Assert(!aiChannel.HasRotationKeys || (aiChannel.RotationKeyCount == 1 && (aiChannel.RotationKeys[0].Value == new Assimp.Quaternion(1, 0, 0, 0) || aiChannel.RotationKeys[0].Value == new Assimp.Quaternion(0, 0, 0, 0))));
                        Debug.Assert(!aiChannel.HasPositionKeys || (aiChannel.PositionKeyCount == 1 && aiChannel.PositionKeys[0].Value == new Vector3D(0, 0, 0)));
                    }
                    else if (aiChannel.NodeName.EndsWith("_$AssimpFbx$_Rotation"))
                    {
                        rotationKeys = aiChannel.RotationKeys;

                        Debug.Assert(pivot.Rotation.HasValue);
                        Debug.Assert(!aiChannel.HasScalingKeys || (aiChannel.ScalingKeyCount == 1 && aiChannel.ScalingKeys[0].Value == new Vector3D(1, 1, 1)));
                        Debug.Assert(!aiChannel.HasPositionKeys || (aiChannel.PositionKeyCount == 1 && aiChannel.PositionKeys[0].Value == new Vector3D(0, 0, 0)));
                    }
                    else if (aiChannel.NodeName.EndsWith("_$AssimpFbx$_Translation"))
                    {
                        translationKeys = aiChannel.PositionKeys;

                        Debug.Assert(pivot.Translation.HasValue);
                        Debug.Assert(!aiChannel.HasScalingKeys || (aiChannel.ScalingKeyCount == 1 && aiChannel.ScalingKeys[0].Value == new Vector3D(1, 1, 1)));
                        Debug.Assert(!aiChannel.HasRotationKeys || (aiChannel.RotationKeyCount == 1 && (aiChannel.RotationKeys[0].Value == new Assimp.Quaternion(1, 0, 0, 0) || aiChannel.RotationKeys[0].Value == new Assimp.Quaternion(0, 0, 0, 0))));
                    }
                    else
                    {
                        scaleKeys       = aiChannel.ScalingKeys;
                        rotationKeys    = aiChannel.RotationKeys;
                        translationKeys = aiChannel.PositionKeys;
                    }
                }

                // Get all unique keyframe times. (Assuming that no two key frames
                // have the same time, which is usually a safe assumption.)
                var times = scaleKeys.Select(k => k.Time)
                            .Union(rotationKeys.Select(k => k.Time))
                            .Union(translationKeys.Select(k => k.Time))
                            .OrderBy(t => t)
                            .ToList();

                Debug.Assert(times.Count == times.Distinct().Count(), "Sequences combined with Union() should not have duplicates.");

                int        prevScaleIndex       = -1;
                int        prevRotationIndex    = -1;
                int        prevTranslationIndex = -1;
                double     prevScaleTime        = 0.0;
                double     prevRotationTime     = 0.0;
                double     prevTranslationTime  = 0.0;
                Vector3?   prevScale            = null;
                Quaternion?prevRotation         = null;
                Vector3?   prevTranslation      = null;

                foreach (var time in times)
                {
                    // Get scaling.
                    Vector3?scale;
                    int     scaleIndex = scaleKeys.FindIndex(k => k.Time == time);
                    if (scaleIndex != -1)
                    {
                        // Scaling key found.
                        scale          = ToXna(scaleKeys[scaleIndex].Value);
                        prevScaleIndex = scaleIndex;
                        prevScaleTime  = time;
                        prevScale      = scale;
                    }
                    else
                    {
                        // No scaling key found.
                        if (prevScaleIndex != -1 && prevScaleIndex + 1 < scaleKeys.Count)
                        {
                            // Lerp between previous and next scaling key.
                            var nextScaleKey  = scaleKeys[prevScaleIndex + 1];
                            var nextScaleTime = nextScaleKey.Time;
                            var nextScale     = ToXna(nextScaleKey.Value);
                            var amount        = (float)((time - prevScaleTime) / (nextScaleTime - prevScaleTime));
                            scale = Vector3.Lerp(prevScale.Value, nextScale, amount);
                        }
                        else
                        {
                            // Hold previous scaling value.
                            scale = prevScale;
                        }
                    }

                    // Get rotation.
                    Quaternion?rotation;
                    int        rotationIndex = rotationKeys.FindIndex(k => k.Time == time);
                    if (rotationIndex != -1)
                    {
                        // Rotation key found.
                        rotation          = ToXna(rotationKeys[rotationIndex].Value);
                        prevRotationIndex = rotationIndex;
                        prevRotationTime  = time;
                        prevRotation      = rotation;
                    }
                    else
                    {
                        // No rotation key found.
                        if (prevRotationIndex != -1 && prevRotationIndex + 1 < rotationKeys.Count)
                        {
                            // Lerp between previous and next rotation key.
                            var nextRotationKey  = rotationKeys[prevRotationIndex + 1];
                            var nextRotationTime = nextRotationKey.Time;
                            var nextRotation     = ToXna(nextRotationKey.Value);
                            var amount           = (float)((time - prevRotationTime) / (nextRotationTime - prevRotationTime));
                            rotation = Quaternion.Slerp(prevRotation.Value, nextRotation, amount);
                        }
                        else
                        {
                            // Hold previous rotation value.
                            rotation = prevRotation;
                        }
                    }

                    // Get translation.
                    Vector3?translation;
                    int     translationIndex = translationKeys.FindIndex(k => k.Time == time);
                    if (translationIndex != -1)
                    {
                        // Translation key found.
                        translation          = ToXna(translationKeys[translationIndex].Value);
                        prevTranslationIndex = translationIndex;
                        prevTranslationTime  = time;
                        prevTranslation      = translation;
                    }
                    else
                    {
                        // No translation key found.
                        if (prevTranslationIndex != -1 && prevTranslationIndex + 1 < translationKeys.Count)
                        {
                            // Lerp between previous and next translation key.
                            var nextTranslationKey  = translationKeys[prevTranslationIndex + 1];
                            var nextTranslationTime = nextTranslationKey.Time;
                            var nextTranslation     = ToXna(nextTranslationKey.Value);
                            var amount = (float)((time - prevTranslationTime) / (nextTranslationTime - prevTranslationTime));
                            translation = Vector3.Lerp(prevTranslation.Value, nextTranslation, amount);
                        }
                        else
                        {
                            // Hold previous translation value.
                            translation = prevTranslation;
                        }
                    }

                    // Apply transformation pivot.
                    var transform = Matrix.Identity;

                    if (pivot.GeometricScaling.HasValue)
                    {
                        transform *= pivot.GeometricScaling.Value;
                    }
                    if (pivot.GeometricRotation.HasValue)
                    {
                        transform *= pivot.GeometricRotation.Value;
                    }
                    if (pivot.GeometricTranslation.HasValue)
                    {
                        transform *= pivot.GeometricTranslation.Value;
                    }
                    if (pivot.ScalingPivotInverse.HasValue)
                    {
                        transform *= pivot.ScalingPivotInverse.Value;
                    }
                    if (scale.HasValue)
                    {
                        transform *= Matrix.CreateScale(scale.Value);
                    }
                    else if (pivot.Scaling.HasValue)
                    {
                        transform *= pivot.Scaling.Value;
                    }
                    if (pivot.ScalingPivot.HasValue)
                    {
                        transform *= pivot.ScalingPivot.Value;
                    }
                    if (pivot.ScalingOffset.HasValue)
                    {
                        transform *= pivot.ScalingOffset.Value;
                    }
                    if (pivot.RotationPivotInverse.HasValue)
                    {
                        transform *= pivot.RotationPivotInverse.Value;
                    }
                    if (pivot.PostRotation.HasValue)
                    {
                        transform *= pivot.PostRotation.Value;
                    }
                    if (rotation.HasValue)
                    {
                        transform *= Matrix.CreateFromQuaternion(rotation.Value);
                    }
                    else if (pivot.Rotation.HasValue)
                    {
                        transform *= pivot.Rotation.Value;
                    }
                    if (pivot.PreRotation.HasValue)
                    {
                        transform *= pivot.PreRotation.Value;
                    }
                    if (pivot.RotationPivot.HasValue)
                    {
                        transform *= pivot.RotationPivot.Value;
                    }
                    if (pivot.RotationOffset.HasValue)
                    {
                        transform *= pivot.RotationOffset.Value;
                    }
                    if (translation.HasValue)
                    {
                        transform *= Matrix.CreateTranslation(translation.Value);
                    }
                    else if (pivot.Translation.HasValue)
                    {
                        transform *= pivot.Translation.Value;
                    }

                    channel.Add(new AnimationKeyframe(TimeSpan.FromSeconds(time / aiAnimation.TicksPerSecond), transform));
                }

                animation.Channels[channelGroup.Key] = channel;
            }

            return(animation);
        }
        /// <summary>
        /// Imports Acclaim AMC (motion capture data).
        /// For a foo_bar.amc, expects skeleton in a file named foo.asf.
        /// Returns a skeleton with Animations in root bone.
        /// </summary>
        public override BoneContent Import(string filename, ContentImporterContext context)
        {
            this.context = context;
            contentId    = new ContentIdentity(filename, GetType().ToString());
            reader       = new StreamReader(filename);

            AnimationContent animation = new AnimationContent();

            animation.Name     = Path.GetFileNameWithoutExtension(filename);
            animation.Identity = contentId;

            string dir         = Path.GetDirectoryName(filename);
            string asfFilename = animation.Name + ".asf";

            if (animation.Name.Contains("_"))
            {
                //asfFilename = animation.Name.Split('_')[0] + ".asf";
            }
            asfFilename = dir + @"\" + asfFilename;
            context.Logger.LogWarning("", contentId, "using skeleton from {0}", asfFilename);
            AsfImporter asfImporter = new AsfImporter();
            BoneContent root        = asfImporter.Import(asfFilename, context);

            bones = asfImporter.Bones;

            int    frameNumber    = 1;
            int    maxFrameNumber = 0;
            string line;

            animation.Channels.Add("root", new AnimationChannel());
            while ((line = readLine()) != null)
            {
                if (line[0] != '#' && line[0] != ':')
                {
                    int fn = 0;
                    if (int.TryParse(line, NumberStyles.Float, CultureInfo.InvariantCulture.NumberFormat, out fn))
                    {
                        ++frameNumber;// = int.Parse(line, NumberStyles.Int, CultureInfo.InvariantCulture.NumberFormat);
                        maxFrameNumber = Math.Max(frameNumber, maxFrameNumber);
                        TimeSpan time = TimeSpan.FromTicks(frameNumber * ticksPerFrame);
                        animation.Channels["root"].Add(new AnimationKeyframe(time, Matrix.Identity));
                    }
                    else
                    {
                        string[] s    = line.Split(' ');
                        string   bone = s[0];
                        if (!animation.Channels.ContainsKey(bone))
                        {
                            animation.Channels.Add(bone, new AnimationChannel());
                        }
                        AnimationChannel  channel  = animation.Channels[bone];
                        AnimationKeyframe keyframe = importKeyframe(s, frameNumber);
                        if (keyframe != null)
                        {
                            channel.Add(keyframe);
                        }
                    }
                }
            }
            animation.Duration = TimeSpan.FromTicks(maxFrameNumber * ticksPerFrame);
            context.Logger.LogImportantMessage("imported {0} animation frames for {1} bones",
                                               maxFrameNumber, animation.Channels.Count);
            root.Animations.Add(animation.Name, animation);
            return(root);
        }
        /// <summary>
        /// The importer's entry point.
        /// Called by the framework when importing a game asset.
        /// </summary>
        /// <param name="filename">Name of a game asset file.</param>
        /// <param name="context">
        /// Contains information for importing a game asset, such as a logger interface.
        /// </param>
        /// <returns>Resulting game asset.</returns>
        public override NodeContent Import(string filename,
                                           ContentImporterContext context)
        {
            // Uncomment the following line to debug:
            //System.Diagnostics.Debugger.Launch();

            importerContext = context;

            // Reset all importer state
            // See field declarations for more information
            rootNode      = new NodeContent();
            meshBuilder   = null;
            this.filename = filename;
            // Model identity is tied to the file it is loaded from
            rootNode.Identity = new ContentIdentity(filename);

            var flags = (ppsteps |
                         aiPostProcessSteps.aiProcess_GenSmoothNormals |    // generate smooth normal vectors if not existing
                         aiPostProcessSteps.aiProcess_SplitLargeMeshes |    // split large, unrenderable meshes into submeshes
                         aiPostProcessSteps.aiProcess_Triangulate |         // triangulate polygons with more than 3 edges
                         aiPostProcessSteps.aiProcess_ConvertToLeftHanded | // convert everything to D3D left handed space
                         aiPostProcessSteps.aiProcess_SortByPType |         // make 'clean' meshes which consist of a single typ of primitives
                         aiPostProcessSteps.aiProcess_FixInfacingNormals |
                         aiPostProcessSteps.aiProcess_FlipWindingOrder |
                         (aiPostProcessSteps)0);

            Importer importer = new Importer();

            scene = importer.ReadFile(filename, flags);
            if (scene != null)
            {
                directory = Path.GetDirectoryName(filename);
            }
            else
            {
                throw new InvalidContentException("Failed to open file: " + filename + ". Either Assimp screwed up or the path is not valid.");
            }


            ///animacoes
            Dictionary <String, AnimationContent> AnimNameToAcontent = new Dictionary <string, AnimationContent>();

            for (int i = 0; i < scene.mNumAnimations; i++)
            {
                AnimationContent AnimationContent = new AnimationContent();
                AnimationContent.Duration = TimeSpan.FromMilliseconds(scene.mAnimations[i].mDuration);
                if (String.IsNullOrEmpty(scene.mAnimations[i].mName.Data))
                {
                    scene.mAnimations[i].mName.Data = "EMPTY";
                }
                AnimationContent.Name = scene.mAnimations[i].mName.Data;

                AnimNameToAcontent.Add(scene.mAnimations[i].mName.Data, AnimationContent);

                for (int j = 0; j < scene.mAnimations[i].mNumChannels; j++)
                {
                    AnimationChannel AnimationChannel;
                    String           boneName = scene.mAnimations[i].mChannels[j].mNodeName.Data;

                    if (AnimationContent.Channels.ContainsKey(boneName))
                    {
                        AnimationChannel = AnimationContent.Channels[boneName];
                    }
                    else
                    {
                        AnimationChannel = new AnimationChannel();
                        AnimationContent.Channels.Add(boneName, AnimationChannel);
                    }

                    Dictionary <double, Vector3>    position = new Dictionary <double, Vector3>();
                    Dictionary <double, Vector3>    scales   = new Dictionary <double, Vector3>();
                    Dictionary <double, Quaternion> rots     = new Dictionary <double, Quaternion>();

                    SortedSet <double> set = new SortedSet <double>();
                    for (int w = 0; w < scene.mAnimations[i].mChannels[j].mNumPositionKeys; w++)
                    {
                        position.Add(scene.mAnimations[i].mChannels[j].mPositionKeys[w].mTime, new Vector3(scene.mAnimations[i].mChannels[j].mPositionKeys[w].mValue.x, scene.mAnimations[i].mChannels[j].mPositionKeys[w].mValue.y, scene.mAnimations[i].mChannels[j].mPositionKeys[w].mValue.z));
                        set.Add(scene.mAnimations[i].mChannels[j].mPositionKeys[w].mTime);
                    }

                    for (int w = 0; w < scene.mAnimations[i].mChannels[j].mNumScalingKeys; w++)
                    {
                        scales.Add(scene.mAnimations[i].mChannels[j].mScalingKeys[w].mTime, new Vector3(scene.mAnimations[i].mChannels[j].mScalingKeys[w].mValue.x, scene.mAnimations[i].mChannels[j].mScalingKeys[w].mValue.y, scene.mAnimations[i].mChannels[j].mScalingKeys[w].mValue.z));
                        set.Add(scene.mAnimations[i].mChannels[j].mScalingKeys[w].mTime);
                    }

                    for (int w = 0; w < scene.mAnimations[i].mChannels[j].mNumRotationKeys; w++)
                    {
                        rots.Add(scene.mAnimations[i].mChannels[j].mRotationKeys[w].mTime, new Quaternion(scene.mAnimations[i].mChannels[j].mRotationKeys[w].mValue.x, scene.mAnimations[i].mChannels[j].mRotationKeys[w].mValue.y, scene.mAnimations[i].mChannels[j].mRotationKeys[w].mValue.z, scene.mAnimations[i].mChannels[j].mRotationKeys[w].mValue.w));
                        set.Add(scene.mAnimations[i].mChannels[j].mRotationKeys[w].mTime);
                    }

                    foreach (var item in set)
                    {
                        Vector3    pos;
                        Vector3    sca;
                        Quaternion rot;

                        if (position.TryGetValue(item, out pos) == false)
                        {
                            pos = Vector3.Zero;
                        }
                        if (rots.TryGetValue(item, out rot) == false)
                        {
                            rot = Quaternion.Identity;
                        }
                        if (scales.TryGetValue(item, out sca) == false)
                        {
                            sca = Vector3.One;
                        }

                        Matrix world = Matrix.CreateScale(sca) * Matrix.CreateFromQuaternion(rot) * Matrix.CreateTranslation(pos);

                        AnimationChannel.Add(new AnimationKeyframe(TimeSpan.FromMilliseconds(item), world));
                    }
                }
            }

            rootNode.Children.Add(extractNo(scene.mRootNode));

            aiNode boneRoot = null;
            aiBone broot    = null;
            int    distance = int.MaxValue;

            ///pega o root manow
            foreach (var item in bones)
            {
                aiNode ainode = scene.mRootNode.FindNode(item.mName);
                aiNode n      = ainode;
                int    d      = 0;
                //find the closest to the root =P
                while (n.mParent != null)
                {
                    d++;
                    n = n.mParent;
                }
                if (d < distance)
                {
                    broot    = item;
                    boneRoot = ainode;
                    distance = d;
                }
            }

            if (broot != null)
            {
                BoneContent BoneContent = new BoneContent();
                BoneContent.Name      = broot.mName.Data;
                BoneContent.Transform = tomatrix(broot.mOffsetMatrix);
                rootNode.Children.Add(BoneContent);

                foreach (var item2 in AnimNameToAcontent)
                {
                    BoneContent.Animations.Add(item2.Key, item2.Value);
                }

                foreach (var item in boneRoot.mChildren)
                {
                    BoneContent.Children.Add(createSkel(boneRoot));
                }

                ClearTree(rootNode);
            }



            return(rootNode);
        }
Exemple #12
0
        private AnimationContent ImportSkeletalAnimation(H3DModel model, H3DAnimation animation)
        {
            var framesCount = (int)animation.FramesCount + 1;

            var animationNode = new AnimationContent
            {
                Name     = animation.Name,
                Identity = _identity,
                Duration = TimeSpan.FromSeconds((float)1 / (float)30 * (float)framesCount)
            };


            foreach (var elem in animation.Elements)
            {
                if (elem.PrimitiveType != H3DPrimitiveType.Transform && elem.PrimitiveType != H3DPrimitiveType.QuatTransform)
                {
                    continue;
                }

                var sklBone = model.Skeleton.FirstOrDefault(x => x.Name == elem.Name);
                var parent  = sklBone != null && sklBone.ParentIndex != -1 ? model.Skeleton[sklBone.ParentIndex] : null;

                var channel = new AnimationChannel();
                for (var frame = 0; frame < framesCount; frame++)
                {
                    var translation = Matrix.Identity;
                    if (elem.Content is H3DAnimTransform transform0)
                    {
                        if (!transform0.TranslationExists)
                        {
                            continue;
                        }

                        translation = Matrix.CreateTranslation(new Vector3(
                                                                   transform0.TranslationX.Exists ? transform0.TranslationX.GetFrameValue(frame) : sklBone.Translation.X,
                                                                   transform0.TranslationY.Exists ? transform0.TranslationY.GetFrameValue(frame) : sklBone.Translation.Y,
                                                                   transform0.TranslationZ.Exists ? transform0.TranslationZ.GetFrameValue(frame) : sklBone.Translation.Z));
                    }
                    else if (elem.Content is H3DAnimQuatTransform quatTransform)
                    {
                        if (!quatTransform.HasTranslation)
                        {
                            continue;
                        }

                        translation = Matrix.CreateTranslation(quatTransform.GetTranslationValue(frame).ToXNA());
                    }

                    var rotation = Matrix.Identity;
                    if (elem.Content is H3DAnimTransform transform1)
                    {
                        if (!(transform1.RotationX.Exists || transform1.RotationY.Exists ||
                              transform1.RotationZ.Exists))
                        {
                            continue;
                        }

                        rotation = Matrix.CreateRotationX(transform1.RotationX.GetFrameValue(frame)) *
                                   Matrix.CreateRotationY(transform1.RotationY.GetFrameValue(frame)) *
                                   Matrix.CreateRotationZ(transform1.RotationZ.GetFrameValue(frame));
                    }
                    else if (elem.Content is H3DAnimQuatTransform quatTransform)
                    {
                        if (!quatTransform.HasRotation)
                        {
                            continue;
                        }

                        rotation = Matrix.CreateFromQuaternion(quatTransform.GetRotationValue(frame).ToXNA());
                    }

                    var scale    = Matrix.Identity;
                    var invScale = System.Numerics.Vector3.One;
                    var pElem    = animation.Elements.FirstOrDefault(x => x.Name == parent?.Name);
                    if (elem.Content is H3DAnimTransform transform2)
                    {
                        if (!transform2.ScaleExists)
                        {
                            continue;
                        }

                        //Compensate parent bone scale (basically, don't inherit scales)
                        if (parent != null && (sklBone.Flags & H3DBoneFlags.IsSegmentScaleCompensate) != 0)
                        {
                            if (pElem != null)
                            {
                                var pTrans = (H3DAnimTransform)pElem.Content;

                                invScale /= new System.Numerics.Vector3(
                                    pTrans.ScaleX.Exists ? pTrans.ScaleX.GetFrameValue(frame) : parent.Scale.X,
                                    pTrans.ScaleY.Exists ? pTrans.ScaleY.GetFrameValue(frame) : parent.Scale.Y,
                                    pTrans.ScaleZ.Exists ? pTrans.ScaleZ.GetFrameValue(frame) : parent.Scale.Z);
                            }
                            else
                            {
                                invScale /= parent.Scale;
                            }
                        }

                        scale = Matrix.CreateScale((invScale * new System.Numerics.Vector3(
                                                        transform2.ScaleX.Exists ? transform2.ScaleX.GetFrameValue(frame) : sklBone.Scale.X,
                                                        transform2.ScaleY.Exists ? transform2.ScaleY.GetFrameValue(frame) : sklBone.Scale.Y,
                                                        transform2.ScaleZ.Exists ? transform2.ScaleZ.GetFrameValue(frame) : sklBone.Scale.Z)).ToXNA());
                    }
                    else if (elem.Content is H3DAnimQuatTransform quatTransform)
                    {
                        if (!quatTransform.HasScale)
                        {
                            continue;
                        }

                        //Compensate parent bone scale (basically, don't inherit scales)
                        if (parent != null && (sklBone.Flags & H3DBoneFlags.IsSegmentScaleCompensate) != 0)
                        {
                            if (pElem != null)
                            {
                                invScale /= ((H3DAnimQuatTransform)pElem.Content).GetScaleValue(frame);
                            }
                            else
                            {
                                invScale /= parent.Scale;
                            }
                        }

                        scale = Matrix.CreateScale((invScale * quatTransform.GetScaleValue(frame)).ToXNA());
                    }

                    channel.Add(new AnimationKeyframe(TimeSpan.FromSeconds((float)frame / 30f), scale * rotation * translation));
                }

                animationNode.Channels[elem.Name] = channel;
            }

            return(animationNode);
        }
Exemple #13
0
        private static AnimationChannel BuildAnimtionChannel(Node animatedNode, NodeAnimationChannel nac)
        {
            AnimationChannel newChan = new AnimationChannel();

            Matrix animatedNodeTransform = Matrix.Transpose(ToXna(animatedNode.Transform));

            Vector3 xnaScale;

            Microsoft.Xna.Framework.Quaternion xnaRotation;
            Vector3 xnaPositon;

            animatedNodeTransform.Decompose(out xnaScale, out xnaRotation, out xnaPositon);

            Vector3D scale = new Vector3D(xnaScale.X, xnaScale.Y, xnaScale.Z);

            Assimp.Quaternion rotation;
            rotation.W = xnaRotation.W;
            rotation.X = xnaRotation.X;
            rotation.Y = xnaRotation.Y;
            rotation.Z = xnaRotation.Z;
            Vector3D position = new Vector3D(xnaPositon.X, xnaPositon.Y, xnaPositon.Z);

            int sKeyIndex = 0;
            int qKeyIndex = 0;
            int tKeyIndex = 0;

            double firstSKeyTime = nac.ScalingKeyCount > sKeyIndex ? nac.ScalingKeys[sKeyIndex].Time : Double.MaxValue;
            double firstQKeyTime = nac.RotationKeyCount > qKeyIndex ? nac.RotationKeys[qKeyIndex].Time : Double.MaxValue;
            double firstTKeyTime = nac.PositionKeyCount > tKeyIndex ? nac.PositionKeys[tKeyIndex].Time : Double.MaxValue;

            double currTime = Math.Min(Math.Min(firstSKeyTime, firstQKeyTime), firstTKeyTime);

            if (firstSKeyTime <= currTime)
            {
                scale = nac.ScalingKeys[sKeyIndex].Value;
            }

            if (firstQKeyTime <= currTime)
            {
                rotation = nac.RotationKeys[qKeyIndex].Value;
            }

            if (firstTKeyTime <= currTime)
            {
                position = nac.PositionKeys[tKeyIndex].Value;
            }

            while (currTime < double.MaxValue)
            {
                while (nac.ScalingKeyCount > sKeyIndex + 1 &&
                       nac.ScalingKeys[sKeyIndex + 1].Time <= currTime)
                {
                    sKeyIndex++;
                    scale = nac.ScalingKeys[sKeyIndex].Value;
                }

                while (nac.RotationKeyCount > qKeyIndex + 1 &&
                       nac.RotationKeys[qKeyIndex + 1].Time <= currTime)
                {
                    qKeyIndex++;
                    rotation = nac.RotationKeys[qKeyIndex].Value;
                }

                while (nac.PositionKeyCount > tKeyIndex + 1 &&
                       nac.PositionKeys[tKeyIndex + 1].Time <= currTime)
                {
                    tKeyIndex++;
                    position = nac.PositionKeys[tKeyIndex].Value;
                }

                xnaRotation.W = rotation.W;
                xnaRotation.X = rotation.X;
                xnaRotation.Y = rotation.Y;
                xnaRotation.Z = rotation.Z;

                Matrix transform =
                    Matrix.CreateScale(ToXna(scale)) *
                    Matrix.CreateFromQuaternion(xnaRotation) *
                    Matrix.CreateTranslation(ToXna(position));

                AnimationKeyframe newKeyframe = new AnimationKeyframe(TimeSpan.FromSeconds(currTime), transform);
                newChan.Add(newKeyframe);

                // Increment the time:

                double nextSKeyTime = nac.ScalingKeyCount > sKeyIndex + 1 ? nac.ScalingKeys[sKeyIndex + 1].Time : Double.MaxValue;
                double nextQKeyTime = nac.RotationKeyCount > qKeyIndex + 1 ? nac.RotationKeys[qKeyIndex + 1].Time : Double.MaxValue;
                double nextTKeyTime = nac.PositionKeyCount > tKeyIndex + 1 ? nac.PositionKeys[tKeyIndex + 1].Time : Double.MaxValue;

                currTime = Math.Min(Math.Min(nextSKeyTime, nextQKeyTime), nextTKeyTime);
            }

            return(newChan);
        }