Esempio n. 1
0
        // template FrameTransformMatrix
        // {
        //     Matrix4x4 frameMatrix;
        // }
        /// <summary>
        /// Imports a transform matrix attached to a ContentNode
        /// </summary>
        /// <returns>The transform matrix attached to the current ContentNode</returns>
        private Matrix ImportFrameTransformMatrix()
        {
            Matrix m = tokens.SkipName().NextMatrix();

            // Reflect the matrix across the Z axis to swap from left hand to right hand
            // coordinate system
            ContentUtil.ReflectMatrix(ref m);
            // skip the "}" at the end of the node
            tokens.SkipToken();
            return(m);
        }
Esempio n. 2
0
            // "This template is instantiated on a per-mesh basis. Within a mesh, a sequence of n
            // instances of this template will appear, where n is the number of bones (X file frames)
            // that influence the vertices in the mesh. Each instance of the template basically defines
            // the influence of a particular bone on the mesh. There is a list of vertex indices, and a
            // corresponding list of weights.
            // template SkinWeights
            // {
            //     STRING transformNodeName;
            //     DWORD nWeights;
            //     array DWORD vertexIndices[nWeights];
            //     array float weights[nWeights];
            //     Matrix4x4 matrixOffset;
            // }
            // - The name of the bone whose influence is being defined is transformNodeName,
            // and nWeights is the number of vertices affected by this bone.
            // - The vertices influenced by this bone are contained in vertexIndices, and the weights for
            // each of the vertices influenced by this bone are contained in weights.
            // - The matrix matrixOffset transforms the mesh vertices to the space of the bone. When concatenated
            // to the bone's transform, this provides the world space coordinates of the mesh as affected by the bone."
            // (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/
            //  directx9_c/dx9_graphics_reference_x_file_format_templates.asp)
            //


            // Reads in a bone that contains skin weights.  It then adds one bone weight
            //  to every vertex that is influenced by ths bone, which contains the name of the bone and the
            //  weight.
            public void ImportSkinWeights()
            {
                isSkinned = true;
                string boneName = tokens.SkipName().NextString();
                // an influence is an index to a vertex that is affected by the current bone
                int          numInfluences = tokens.NextInt();
                List <int>   influences    = new List <int>();
                List <float> weights       = new List <float>();

                for (int i = 0; i < numInfluences; i++)
                {
                    influences.Add(tokens.NextInt());
                }
                for (int i = 0; i < numInfluences; i++)
                {
                    weights.Add(tokens.NextFloat());
                    if (weights[i] == 0)
                    {
                        influences[i] = -1;
                    }
                }
                influences.RemoveAll(delegate(int i) { return(i == -1); });
                weights.RemoveAll(delegate(float f) { return(f == 0); });

                // Add the matrix that transforms the vertices to the space of the bone.
                // we will need this for skinned animation.
                Matrix blendOffset = tokens.NextMatrix();

                ContentUtil.ReflectMatrix(ref blendOffset);
                skinTransformDictionary.Add(boneName, blendOffset);
                SkinTransformContent trans = new SkinTransformContent();

                trans.BoneName  = boneName;
                trans.Transform = blendOffset;
                skinTransforms.Add(trans);
                // end of skin weights
                tokens.SkipToken();

                // add a new name/weight pair to every vertex influenced by the bone
                for (int i = 0; i < influences.Count; i++)
                {
                    skinInfo[influences[i]].Add(new BoneWeight(boneName,
                                                               weights[i]));
                }
            }
        /// <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);
        }
Esempio n. 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);
        }