コード例 #1
0
            public void InvalidateTime()
            {
                reachedEnd = false;

                currentKeyFrame = keyFrames.GetEnumerator();

                var animationInitialValues = new AnimationInitialValues <float>();

                // Skip two elements (right before third)
                currentKeyFrame.MoveNext();
                animationInitialValues.Value1 = currentKeyFrame.Current;
                currentKeyFrame.MoveNext();
                animationInitialValues.Value2 = currentKeyFrame.Current;

                currentTime = animationInitialValues.Value1.Time;

                InitializeAnimation(ref data, ref animationInitialValues);
            }
        protected unsafe override void ProcessChannel(ref Channel channel, CompressedTimeSpan newTime, IntPtr location)
        {
            SetTime(ref channel, newTime);

            var currentTime  = channel.CurrentTime;
            var currentIndex = channel.CurrentIndex;

            var keyFrames      = channel.Curve.KeyFrames;
            var keyFramesItems = keyFrames.Items;
            var keyFramesCount = keyFrames.Count;

            // Extract data
            int timeStart = keyFrames[currentIndex + 0].Time.Ticks;
            int timeEnd   = keyFrames[currentIndex + 1].Time.Ticks;

            // Compute interpolation factor
            float t = ((float)currentTime.Ticks - (float)timeStart) / ((float)timeEnd - (float)timeStart);

            if (channel.InterpolationType == AnimationCurveInterpolationType.Cubic)
            {
                Interpolator.Quaternion.Cubic(
                    ref keyFramesItems[currentIndex > 0 ? currentIndex - 1 : 0].Value,
                    ref keyFramesItems[currentIndex].Value,
                    ref keyFramesItems[currentIndex + 1].Value,
                    ref keyFramesItems[currentIndex + 2 >= keyFramesCount ? currentIndex + 1 : currentIndex + 2].Value,
                    t,
                    out *(Quaternion *)(location + channel.Offset));
            }
            else if (channel.InterpolationType == AnimationCurveInterpolationType.Linear)
            {
                Interpolator.Quaternion.SphericalLinear(
                    ref keyFramesItems[currentIndex].Value,
                    ref keyFramesItems[currentIndex + 1].Value,
                    t,
                    out *(Quaternion *)(location + channel.Offset));
            }
            else
            {
                throw new NotImplementedException();
            }
        }
コード例 #3
0
        protected static void SetTime(ref Channel channel, CompressedTimeSpan newTime)
        {
            var currentTime = channel.CurrentTime;

            if (newTime == currentTime)
            {
                return;
            }

            var currentIndex = channel.CurrentIndex;
            var keyFrames    = channel.Curve.KeyFrames;

            var keyFramesItems = keyFrames.Items;
            var keyFramesCount = keyFrames.Count;

            if (newTime > currentTime)
            {
                while (currentIndex + 1 < keyFramesCount - 1 && newTime >= keyFramesItems[currentIndex + 1].Time)
                {
                    ++currentIndex;
                }
            }
            else if (newTime <= keyFramesItems[0].Time)
            {
                // Special case: fast rewind to beginning of animation
                currentIndex = 0;
            }
            else // newTime < currentTime
            {
                while (currentIndex - 1 >= 0 && newTime < keyFramesItems[currentIndex].Time)
                {
                    --currentIndex;
                }
            }

            channel.CurrentIndex = currentIndex;
            channel.CurrentTime  = newTime;
        }
コード例 #4
0
 protected unsafe override void ProcessChannel(ref Channel channel, CompressedTimeSpan currentTime, IntPtr location, float factor)
 {
     if (channel.InterpolationType == AnimationCurveInterpolationType.Cubic)
     {
         *(float *)(location + channel.Offset) = Interpolator.Cubic(
             channel.ValuePrev.Value,
             channel.ValueStart.Value,
             channel.ValueEnd.Value,
             channel.ValueNext.Value,
             factor);
     }
     else if (channel.InterpolationType == AnimationCurveInterpolationType.Linear)
     {
         *(float *)(location + channel.Offset) = Interpolator.Linear(
             channel.ValueStart.Value,
             channel.ValueEnd.Value,
             factor);
     }
     else
     {
         throw new NotImplementedException();
     }
 }
コード例 #5
0
        /// <summary>
        /// Evaluates the error within specified segment.
        /// </summary>
        /// <param name="originalCurve">The original curve.</param>
        /// <param name="evaluator">The evaluator.</param>
        /// <param name="stepSize">Size of the step.</param>
        /// <param name="keyFrame">The key frame.</param>
        /// <param name="nextKeyFrame">The next key frame.</param>
        /// <returns></returns>
        private KeyValuePair <CompressedTimeSpan, float> EvaluateError(Func <CompressedTimeSpan, float> originalCurve, Evaluator evaluator, CompressedTimeSpan stepSize, KeyFrameData <float> keyFrame, KeyFrameData <float> nextKeyFrame)
        {
            var startTime = keyFrame.Time;
            var endTime   = nextKeyFrame.Time;

            var biggestDifference     = 0.0f;
            var biggestDifferenceTime = startTime;

            // Rounds up start time (i.e. startTime is multiple of stepSize)
            startTime = new CompressedTimeSpan((startTime.Ticks / stepSize.Ticks + 1) * stepSize.Ticks);

            for (var time = startTime; time < endTime; time += stepSize)
            {
                var difference = Math.Abs(originalCurve(time) - evaluator.Evaluate(time));

                if (difference > biggestDifference)
                {
                    biggestDifference     = difference;
                    biggestDifferenceTime = time;
                }
            }
            return(new KeyValuePair <CompressedTimeSpan, float>(biggestDifferenceTime, biggestDifference));
        }
コード例 #6
0
        protected void ProcessChannel(ref Channel channel, CompressedTimeSpan currentTime, IntPtr location)
        {
            var startTime = channel.ValueStart.Time;

            // Sampling before start (should not really happen because we add a keyframe at TimeSpan.Zero, but let's keep it in case it changes later.
            if (currentTime <= startTime)
            {
                Utilities.UnsafeWrite(location + channel.Offset, ref channel.ValueStart.Value);
                return;
            }

            var endTime = channel.ValueEnd.Time;

            // Sampling after end
            if (currentTime >= endTime)
            {
                Utilities.UnsafeWrite(location + channel.Offset, ref channel.ValueEnd.Value);
                return;
            }

            float factor = (float)(currentTime.Ticks - startTime.Ticks) / (float)(endTime.Ticks - startTime.Ticks);

            ProcessChannel(ref channel, currentTime, location, factor);
        }
コード例 #7
0
 /// <summary>
 /// Writes a new value at the end of the curve (used for building curves).
 /// It should be done in increasing order as it will simply add a new key at the end of <see cref="AnimationCurve{T}.KeyFrames"/>.
 /// </summary>
 /// <param name="newTime">The new time.</param>
 /// <param name="location">The location.</param>
 public abstract void AddValue(CompressedTimeSpan newTime, IntPtr location);
コード例 #8
0
 public abstract void Evaluate(CompressedTimeSpan newTime, object[] results);
コード例 #9
0
 public abstract void Evaluate(CompressedTimeSpan newTime, IntPtr location);
コード例 #10
0
 public override void Evaluate(CompressedTimeSpan newTime, object[] results)
 {
     throw new NotImplementedException();
 }
コード例 #11
0
 protected abstract void ProcessChannel(ref Channel channel, CompressedTimeSpan currentTime, IntPtr location, float factor);
コード例 #12
0
 protected abstract void ProcessChannel(ref Channel channel, CompressedTimeSpan newTime, IntPtr location);
コード例 #13
0
        public void Fitting(Func <CompressedTimeSpan, float> originalCurve, CompressedTimeSpan stepSize, float maxErrorThreshold)
        {
            // Some info: http://wscg.zcu.cz/wscg2008/Papers_2008/full/A23-full.pdf
            // Compression of Temporal Video Data by Catmull-Rom Spline and Quadratic Bézier Curve Fitting
            // And: http://bitsquid.blogspot.jp/2009/11/bitsquid-low-level-animation-system.html

            // Only one or zero keys: no need to do anything.
            if (KeyFrames.Count <= 1)
            {
                return;
            }

            var keyFrames = new LinkedList <KeyFrameData <float> >(this.KeyFrames);
            var evaluator = new Evaluator(keyFrames);

            // Compute initial errors (using Least Square Equation)
            var errors = new LinkedList <ErrorNode>();
            //var errors = new List<float>();
            var errorQueue = new PriorityQueue <LinkedListNode <ErrorNode> >(new ErrorComparer());

            foreach (var keyFrame in keyFrames.EnumerateNodes())
            {
                if (keyFrame.Next == null)
                {
                    break;
                }
                var error     = EvaluateError(originalCurve, evaluator, stepSize, keyFrame.Value, keyFrame.Next.Value);
                var errorNode = errors.AddLast(new ErrorNode(keyFrame, error.Key, error.Value));
                errorQueue.Enqueue(errorNode);
            }
            //for (int keyFrame = 0; keyFrame < KeyFrames.Count - 1; ++keyFrame)
            //{
            //    //errors.Add(EvaluateError(originalCurve, evaluator, stepSize, keyFrame));
            //    var errorNode = errors.AddLast(new ErrorNode(EvaluateError(originalCurve, evaluator, stepSize, keyFrame)));
            //    errorQueue.Enqueue(errorNode);
            //}

            while (true)
            {
                // Already reached enough subdivisions
                var highestError = errorQueue.Dequeue();
                if (highestError.Value.Error <= maxErrorThreshold)
                {
                    break;
                }

                //// Find segment to optimize
                //var biggestErrorIndex = 0;
                //for (int keyFrame = 1; keyFrame < KeyFrames.Count - 1; ++keyFrame)
                //{
                //    if (errors[keyFrame] > errors[biggestErrorIndex])
                //        biggestErrorIndex = keyFrame;
                //}

                //// Already reached enough subdivisions
                //if (errors[biggestErrorIndex] <= maxErrorThreshold)
                //    break;

                // Create new key (use middle point, but better heuristic might improve situation -- like point with biggest error)
                //var middleTime = (start.Value.Time + end.Value.Time) / 2;
                var middleTime = highestError.Value.BiggestDeltaTime;
                //KeyFrames.Insert(biggestErrorIndex + 1, new KeyFrameData<float> { Time = middleTime, Value = originalCurve(middleTime) });
                var newKeyFrame = keyFrames.AddAfter(highestError.Value.KeyFrame, new KeyFrameData <float> {
                    Time = middleTime, Value = originalCurve(middleTime)
                });
                //errors.Insert(biggestErrorIndex + 1, 0.0f);
                var newError = errors.AddAfter(highestError, new ErrorNode(newKeyFrame, CompressedTimeSpan.Zero, 0.0f));

                var highestErrorLastUpdate = newError;
                if (highestErrorLastUpdate.Next != null)
                {
                    highestErrorLastUpdate = highestErrorLastUpdate.Next;
                }

                // Invalidate evaluator (data changed)
                evaluator.InvalidateTime();

                // Update errors
                for (var error = highestError.Previous ?? highestError; error != null; error = error.Next)
                {
                    if (error != highestError && error != newError)
                    {
                        errorQueue.Remove(error);
                    }

                    var errorInfo = EvaluateError(originalCurve, evaluator, stepSize, error.Value.KeyFrame.Value, error.Value.KeyFrame.Next.Value);
                    error.Value.BiggestDeltaTime = errorInfo.Key;
                    error.Value.Error            = errorInfo.Value;

                    errorQueue.Enqueue(error);

                    if (error == highestErrorLastUpdate)
                    {
                        break;
                    }
                }
            }

            KeyFrames = new List <KeyFrameData <float> >(keyFrames);
        }
コード例 #14
0
 public ErrorNode(LinkedListNode <KeyFrameData <float> > keyFrame, CompressedTimeSpan biggestDeltaTime, float error)
 {
     KeyFrame         = keyFrame;
     BiggestDeltaTime = biggestDeltaTime;
     Error            = error;
 }