Пример #1
0
        //----------------------------------------------
        // U P D A T E   M O D E L   A N I M A T I O N S
        //----------------------------------------------
        ///<summary> Gets the animation frame (based on elapsed time) for all nodes and loads them into the model node transforms. </summary>
        private void UpdateModelAnimations(GameTime gameTime)
        {
            if (animations.Count <= 0 || currentAnim >= animations.Count)
            {
                return;
            }

            AnimationTimeLogic(gameTime);                                      // process what to do based on animation time (frames, duration, complete | looping)

            int cnt = animations[currentAnim].animatedNodes.Count;             // loop thru animated nodes

            for (int n = 0; n < cnt; n++)
            {
                AnimNodes animNode = animations[currentAnim].animatedNodes[n];                        // get animation keyframe lists (each animNode)
                ModelNode node     = animNode.nodeRef;                                                // get bone associated with this animNode (could be mesh-node)
                node.local_mtx = animations[currentAnim].Interpolate(currentAnimFrameTime, animNode); // interpolate keyframes (animate local matrix) for this bone
            }
        }
Пример #2
0
            public List <AnimNodes> animatedNodes; // holds the animated nodes

            // I N T E R P O L A T E
            ///<summary> animation blending between key-frames </summary>
            public Matrix Interpolate(double animTime, AnimNodes nodeAnim)
            {
                var durationSecs = DurationInSeconds + DurationInSecondsAdded;

                while (animTime > durationSecs)        // If the requested play-time is past the end of the animation, loop it (ie: time = 20 but duration = 16 so time becomes 4)
                {
                    animTime -= durationSecs;
                }

                Quaternion q1 = nodeAnim.qrot[0], q2 = q1;            // init rot as entry 0 for both keys (init may be needed cuz conditional value assignment can upset compiler)
                Vector3    p1 = nodeAnim.position[0], p2 = p1;        // " pos
                Vector3    s1 = nodeAnim.scale[0], s2 = s1;           // " scale
                double     tq1 = nodeAnim.qrotTime[0], tq2 = tq1;     // " rot-time
                double     tp1 = nodeAnim.positionTime[0], tp2 = tp1; // " pos-time
                double     ts1 = nodeAnim.scaleTime[0], ts2 = ts1;    // " scale-time

                // GET ROTATION KEYFRAMES
                int end_t_index = nodeAnim.qrotTime.Count - 1;      // final time's index (starting with qrot cuz we do it first - we'll cahnge this variable for pos and scale)
                int end_index   = nodeAnim.qrot.Count - 1;          // final rot frame
                var end_time    = nodeAnim.qrotTime[end_t_index];   // get final rotation-time

                if (animTime > end_time)
                {                                    // if animTime is past final rotation-time: Set to interpolate between last and first frames (for animation-loop)
                    tq1  = end_time;                 // key 1 time is last keyframe and time 2 is time taken after to get to frame 0 (see below)
                    tq2 += durationSecs;             // total duration accounting for time to loop from last frame to frame 0 (with DurationInSecondsAdded)
                    q1   = nodeAnim.qrot[end_index]; // get final quaternion (count-1),       NOTE: q2 already set above (key frame 0)
                }
                else
                {
                    int frame2 = end_index, frame1;              //                  animTime   t =  frame2
                    for (; frame2 > -1; frame2--)                // loop from last index to 0 (until find correct place on timeline):
                    {
                        var t = nodeAnim.qrotTime[frame2];       // what's the time at this frame?
                        if (t < animTime)
                        {
                            break;                               // if the current_time > the frame time then we've found the spot we're looking for (break out)
                        }
                    }
                    if (frame2 < end_index)
                    {
                        frame2++;                                // at this point the frame2 is 1 less than what we're looking for so add 1
                    }
                    q2     = nodeAnim.qrot[frame2];
                    tq2    = nodeAnim.qrotTime[frame2];
                    frame1 = frame2 - 1;
                    if (frame1 < 0)
                    {
                        frame1 = end_index;                                // loop frame1 to last frame
                        tq1    = nodeAnim.qrotTime[frame1] - durationSecs; // Using: frame2time - frame1time, so we need time1 to be less _ thus: subtract durationSecs to fix it
                    }
                    else
                    {
                        tq1 = nodeAnim.qrotTime[frame1];                // get time1
                    }
                    q1 = nodeAnim.qrot[frame1];
                }
                // GET POSITION KEY FRAMES
                end_t_index = nodeAnim.positionTime.Count - 1;      // final time's index
                end_index   = nodeAnim.position.Count - 1;          // final pos frame
                end_time    = nodeAnim.positionTime[end_t_index];   // get final position-time
                if (animTime > end_time)                            // if animTime is past final pos-time: Set to interpolate between last and first frames (for animation-loop)
                {
                    tp1  = end_time;                                // key 1 time is last keyframe and time 2 is time taken after to get to frame 0 (see below)
                    tp2 += durationSecs;                            // total duration accounting for time to loop from last frame to frame 0 (with DurationInSecondsAdded)
                    p1   = nodeAnim.position[end_index];            // get final position (count-1),       NOTE: q2 already set above (key frame 0)
                }
                else
                {
                    int frame2 = end_index, frame1;
                    for (; frame2 > -1; frame2--)                   // loop from last index to 0 (until find correct place on timeline):
                    {
                        var t = nodeAnim.positionTime[frame2];      // what's the time at this frame?
                        if (t < animTime)
                        {
                            break;                                  // if the current_time > the frame time then we've found the spot we're looking for (break out)
                        }
                    }
                    if (frame2 < end_index)
                    {
                        frame2++;                                   // at this point the frame2 is 1 less than what we're looking for so add 1
                    }
                    p2     = nodeAnim.position[frame2];
                    tp2    = nodeAnim.positionTime[frame2];
                    frame1 = frame2 - 1;
                    if (frame1 < 0)
                    {
                        frame1 = end_index;                                    // loop frame1 to last frame
                        tp1    = nodeAnim.positionTime[frame1] - durationSecs; // Using: frame2time - frame1time, so we need time1 to be less _ thus: subtract durationSecs to fix it
                    }
                    else
                    {
                        tp1 = nodeAnim.positionTime[frame1];                // get time1
                    }
                    p1 = nodeAnim.position[frame1];
                }
                // GET SCALE KEYFRAMES
                end_t_index = nodeAnim.scaleTime.Count - 1;         // final time's index
                end_index   = nodeAnim.scale.Count - 1;             // final scale frame
                end_time    = nodeAnim.scaleTime[end_t_index];      // get final scale-time
                if (animTime > end_time)                            // if animTime is past final scale-time: Set to interpolate between last and first frames (for animation-loop)
                {
                    ts1  = end_time;                                // key 1 time is last keyframe and time 2 is time taken after to get to frame 0 (see below)
                    ts2 += durationSecs;                            // total duration accounting for time to loop from last frame to frame 0 (with DurationInSecondsAdded)
                    s1   = nodeAnim.scale[end_index];               // get final scale (count-1),       NOTE: q2 already set above (key frame 0)
                }
                else
                {
                    int frame2 = end_index, frame1;
                    for (; frame2 > -1; frame2--)                   // loop from last index to 0 (until find correct place on timeline):
                    {
                        var t = nodeAnim.scaleTime[frame2];         // what's the time at this frame?
                        if (animTime > t)
                        {
                            break;                                  // if the current_time > the frame time then we've found the spot we're looking for (break out)
                        }
                    }
                    if (frame2 < end_index)
                    {
                        frame2++;                                   // at this point the frame2 is 1 less than what we're looking for so add 1
                    }
                    s2     = nodeAnim.scale[frame2];
                    ts2    = nodeAnim.scaleTime[frame2];
                    frame1 = frame2 - 1;
                    if (frame1 < 0)
                    {
                        frame1 = end_index;                                 // loop frame1 to last frame
                        ts1    = nodeAnim.scaleTime[frame1] - durationSecs; // Using: frame2time - frame1time, so we need time1 to be less _ thus: subtract durationSecs to fix it
                    }
                    else
                    {
                        ts1 = nodeAnim.scaleTime[frame1];                 // get time1
                    }
                    s1 = nodeAnim.scale[frame1];
                }

                float tqi = 0, tpi = 0, tsi = 0;

                Quaternion q;

                tqi = (float)GetInterpolateTimePercent(tq1, tq2, animTime); // get the time% (0-1)
                q   = Quaternion.Slerp(q1, q2, tqi);                        // blend the rotation between keys using the time percent

                Vector3 p;

                tpi = (float)GetInterpolateTimePercent(tp1, tp2, animTime); // "
                p   = Vector3.Lerp(p1, p2, tpi);

                Vector3 s;

                tsi = (float)GetInterpolateTimePercent(ts1, ts2, animTime); // "
                s   = Vector3.Lerp(s1, s2, tsi);

                var ms = Matrix.CreateScale(s);
                var mr = Matrix.CreateFromQuaternion(q);
                var mt = Matrix.CreateTranslation(p);

                var m = ms * mr * mt; // S,R,T

                return(m);
            } // Interpolate