Use double for animation curves
authorMikko Rasa <tdb@tdb.fi>
Sun, 23 Jun 2019 19:38:23 +0000 (22:38 +0300)
committerMikko Rasa <tdb@tdb.fi>
Sun, 23 Jun 2019 19:38:23 +0000 (22:38 +0300)
Since the t value is raised to the third power, floats with their 24-bit
mantissa started to run out of precision around 30 seconds.  Doubles
should be good for several hours.  If that somehow turns out to not be
enough I'll invent some way to chain animations.

source/animation.cpp
source/animation.h

index 0e4bd3e6ff26c26a4e4b7204c487fa6715148be7..37f583d5ec53b43324e67f7fcd1237a25bbefa80 100644 (file)
@@ -234,6 +234,7 @@ void Animation::create_curve(CurveTarget target, int component, const T &extract
                typename Interpolate::SplineValue<float, N>::Type value;
                if(extract(*i->keyframe, value))
                {
+                       typename Knot::Value dvalue = value;
                        float x = i->time/Time::sec;
                        if(i->control)
                        {
@@ -246,14 +247,14 @@ void Animation::create_curve(CurveTarget target, int component, const T &extract
                                if(n_control==1)
                                {
                                        typename Knot::Value cv = knots.back().y;
-                                       knots.back().y = (knots[knots.size()-2].y+cv*2.0f)/3.0f;
-                                       knots.push_back(Knot(x, (value+cv*2.0f)/3.0f));
+                                       knots.back().y = (knots[knots.size()-2].y+cv*2.0)/3.0;
+                                       knots.push_back(Knot(x, (dvalue+cv*2.0)/3.0));
                                }
                                else if(n_control==0 && !knots.empty())
                                {
                                        typename Knot::Value prev = knots.back().y;
-                                       knots.push_back(Knot(knots.back().x, (prev*2.0f+value)/3.0f));
-                                       knots.push_back(Knot(x, (prev+value*2.0f)/3.0f));
+                                       knots.push_back(Knot(knots.back().x, (prev*2.0+dvalue)/3.0));
+                                       knots.push_back(Knot(x, (prev+dvalue*2.0)/3.0));
                                }
                                n_control = 0;
                        }
@@ -318,7 +319,7 @@ Animation::Curve::Curve(CurveTarget t, int c):
 template<unsigned N>
 Animation::ValueCurve<N>::ValueCurve(CurveTarget t, int c, const vector<Knot> &k):
        Curve(t, c),
-       spline(Interpolate::BezierSpline<float, 3, N>(k))
+       spline(Interpolate::BezierSpline<double, 3, N>(k))
 { }
 
 template<unsigned N>
@@ -372,7 +373,7 @@ template<unsigned N>
 void Animation::ValueCurve<N>::apply(float x, KeyFrame::AnimatedUniform &uni) const
 {
        uni.size = N;
-       typename Interpolate::Spline<float, 3, N>::Value value = spline(x);
+       typename Interpolate::Spline<double, 3, N>::Value value = spline(x);
        for(unsigned i=0; i<N; ++i)
                uni.values[i] = Interpolate::SplineValue<float, N>::get(value, i);
 }
index d053ee9004835154acd8f22f3a91ab5655148c67..6845d23ee3e1652c9f7e49a86e5145f3faa6aa52 100644 (file)
@@ -83,10 +83,10 @@ private:
        class ValueCurve: public Curve
        {
        public:
-               typedef typename Interpolate::SplineKnot<float, N> Knot;
+               typedef typename Interpolate::SplineKnot<double, N> Knot;
 
        private:
-               Interpolate::Spline<float, 3, N> spline;
+               Interpolate::Spline<double, 3, N> spline;
 
        public:
                ValueCurve(CurveTarget, int, const std::vector<Knot> &);