Bläddra i källkod

Even more experiments with curve edition APIs...

Vicente Penades 6 år sedan
förälder
incheckning
b32fa10e13

+ 7 - 7
src/SharpGLTF.Core/Animations/SamplerFactory.cs

@@ -27,7 +27,7 @@ namespace SharpGLTF.Animations
         /// 1: LINEAR.
         /// 1: LINEAR.
         /// 3: CUBIC.
         /// 3: CUBIC.
         /// </summary>
         /// </summary>
-        int Degree { get; }
+        int MaxDegree { get; }
 
 
         IReadOnlyDictionary<float, T> ToStepCurve();
         IReadOnlyDictionary<float, T> ToStepCurve();
         IReadOnlyDictionary<float, T> ToLinearCurve();
         IReadOnlyDictionary<float, T> ToLinearCurve();
@@ -293,7 +293,7 @@ namespace SharpGLTF.Animations
         private readonly IEnumerable<(float, Vector3)> _Sequence;
         private readonly IEnumerable<(float, Vector3)> _Sequence;
         private readonly Boolean _Linear;
         private readonly Boolean _Linear;
 
 
-        public int Degree => _Linear ? 1 : 0;
+        public int MaxDegree => _Linear ? 1 : 0;
 
 
         public Vector3 GetPoint(float offset)
         public Vector3 GetPoint(float offset)
         {
         {
@@ -336,7 +336,7 @@ namespace SharpGLTF.Animations
         private readonly IEnumerable<(float, Quaternion)> _Sequence;
         private readonly IEnumerable<(float, Quaternion)> _Sequence;
         private readonly Boolean _Linear;
         private readonly Boolean _Linear;
 
 
-        public int Degree => _Linear ? 1 : 0;
+        public int MaxDegree => _Linear ? 1 : 0;
 
 
         public Quaternion GetPoint(float offset)
         public Quaternion GetPoint(float offset)
         {
         {
@@ -379,7 +379,7 @@ namespace SharpGLTF.Animations
         private readonly IEnumerable<(float, float[])> _Sequence;
         private readonly IEnumerable<(float, float[])> _Sequence;
         private readonly Boolean _Linear;
         private readonly Boolean _Linear;
 
 
-        public int Degree => _Linear ? 1 : 0;
+        public int MaxDegree => _Linear ? 1 : 0;
 
 
         public float[] GetPoint(float offset)
         public float[] GetPoint(float offset)
         {
         {
@@ -427,7 +427,7 @@ namespace SharpGLTF.Animations
 
 
         private readonly IEnumerable<(float, (Vector3, Vector3, Vector3))> _Sequence;
         private readonly IEnumerable<(float, (Vector3, Vector3, Vector3))> _Sequence;
 
 
-        public int Degree => 3;
+        public int MaxDegree => 3;
 
 
         public Vector3 GetPoint(float offset)
         public Vector3 GetPoint(float offset)
         {
         {
@@ -471,7 +471,7 @@ namespace SharpGLTF.Animations
 
 
         private readonly IEnumerable<(float, (Quaternion, Quaternion, Quaternion))> _Sequence;
         private readonly IEnumerable<(float, (Quaternion, Quaternion, Quaternion))> _Sequence;
 
 
-        public int Degree => 3;
+        public int MaxDegree => 3;
 
 
         public Quaternion GetPoint(float offset)
         public Quaternion GetPoint(float offset)
         {
         {
@@ -515,7 +515,7 @@ namespace SharpGLTF.Animations
 
 
         private readonly IEnumerable<(float, (float[], float[], float[]))> _Sequence;
         private readonly IEnumerable<(float, (float[], float[], float[]))> _Sequence;
 
 
-        public int Degree => 3;
+        public int MaxDegree => 3;
 
 
         public float[] GetPoint(float offset)
         public float[] GetPoint(float offset)
         {
         {

+ 12 - 0
src/SharpGLTF.Toolkit/Animations/AnimatableProperty.cs

@@ -78,7 +78,19 @@ namespace SharpGLTF.Animations
 
 
         public CurveBuilder<T> UseTrackBuilder(string track)
         public CurveBuilder<T> UseTrackBuilder(string track)
         {
         {
+            Guard.NotNullOrEmpty(track, nameof(track));
+
+            if (_Tracks == null || !_Tracks.TryGetValue(track, out ICurveSampler<T> sampler))
+            {
+                sampler = CurveFactory.CreateCurveBuilder<T>() as ICurveSampler<T>;
+                SetTrack(track, sampler);
+            }
+
+            if (sampler is CurveBuilder<T> builder) return builder;
+
             throw new NotImplementedException();
             throw new NotImplementedException();
+
+            // TODO: CurveFactory.CreateCurveBuilder(sampler);
         }
         }
 
 
         #endregion
         #endregion

+ 248 - 54
src/SharpGLTF.Toolkit/Animations/Curves.cs

@@ -6,12 +6,32 @@ using System.Linq;
 
 
 namespace SharpGLTF.Animations
 namespace SharpGLTF.Animations
 {
 {
-    //------------------------------------------------------
-    // this code is in hibernation mode - DO NOT USE
-    //------------------------------------------------------
+    struct _CurveNode<T>
+    {
+        public _CurveNode(T value, bool isLinear)
+        {
+            IncomingTangent = default;
+            Point = value;
+            OutgoingTangent = default;
+            Degree = isLinear ? 1 : 0;
+        }
+
+        public _CurveNode(T incoming, T value, T outgoing)
+        {
+            IncomingTangent = incoming;
+            Point = value;
+            OutgoingTangent = outgoing;
+            Degree = 3;
+        }
+
+        public T IncomingTangent;
+        public T Point;
+        public T OutgoingTangent;
+        public int Degree;
+    }
 
 
     // the idea is that depending on the calls we do to this interface, it upgrades the data under the hood.
     // the idea is that depending on the calls we do to this interface, it upgrades the data under the hood.
-    public abstract class CurveBuilder<T>
+    public abstract class CurveBuilder<T> : IConvertibleCurve<T>
     {
     {
         #region data
         #region data
 
 
@@ -19,18 +39,26 @@ namespace SharpGLTF.Animations
 
 
         #endregion
         #endregion
 
 
+        #region properties
+
         public IReadOnlyCollection<float> Keys => _Keys.Keys;
         public IReadOnlyCollection<float> Keys => _Keys.Keys;
 
 
+        public int MaxDegree => _Keys.Values.Max(item => item.Degree);
+
+        #endregion
+
+        #region API
+
         public void RemoveKey(float offset) { _Keys.Remove(offset); }
         public void RemoveKey(float offset) { _Keys.Remove(offset); }
 
 
         public void SetKey(float offset, T value, bool isLinear = true)
         public void SetKey(float offset, T value, bool isLinear = true)
         {
         {
-            throw new NotImplementedException();
+            _Keys[offset] = new _CurveNode<T>(value, isLinear);
         }
         }
 
 
-        public void SetKey(float offset, T value, T incomingTangent, int outgoingTangent)
+        public void SetKey(float offset, T value, T incomingTangent, T outgoingTangent)
         {
         {
-            throw new NotImplementedException();
+            _Keys[offset] = new _CurveNode<T>(incomingTangent, value, outgoingTangent);
         }
         }
 
 
         public CurveBuilder<T> WithKey(float offset, T value, bool isLinear = true)
         public CurveBuilder<T> WithKey(float offset, T value, bool isLinear = true)
@@ -39,18 +67,207 @@ namespace SharpGLTF.Animations
             return this;
             return this;
         }
         }
 
 
-        public CurveBuilder<T> WithKey(float offset, T value, T incomingTangent, int outgoingTangent)
+        public CurveBuilder<T> WithKey(float offset, T value, T incomingTangent, T outgoingTangent)
         {
         {
             SetKey(offset, value, incomingTangent, outgoingTangent);
             SetKey(offset, value, incomingTangent, outgoingTangent);
             return this;
             return this;
         }
         }
+
+        private protected (_CurveNode<T>, _CurveNode<T>, float) FindSample(float offset)
+        {
+            if (_Keys.Count == 0) return (default(_CurveNode<T>), default(_CurveNode<T>), 0);
+
+            var offsets = SamplerFactory.FindPairContainingOffset(_Keys.Keys, offset);
+
+            return (_Keys[offsets.Item1], _Keys[offsets.Item2], offsets.Item3);
+        }
+
+        public abstract T GetPoint(float offset);
+
+        protected abstract T GetTangent(T fromValue, T toValue);
+
+        IReadOnlyDictionary<float, T> IConvertibleCurve<T>.ToStepCurve()
+        {
+            if (MaxDegree != 0) throw new NotSupportedException();
+
+            return _Keys.ToDictionary(item => item.Key, item => item.Value.Point);
+        }
+
+        IReadOnlyDictionary<float, T> IConvertibleCurve<T>.ToLinearCurve()
+        {
+            var d = new Dictionary<float, T>();
+
+            var orderedKeys = _Keys.Keys.ToList();
+
+            for (int i = 0; i < orderedKeys.Count - 1; ++i)
+            {
+                var a = orderedKeys[i + 0];
+                var b = orderedKeys[i + 1];
+
+                var sa = _Keys[a];
+                var sb = _Keys[b];
+
+                switch (sa.Degree)
+                {
+                    case 0: // simulate a step with an extra key
+                        d[a] = sa.Point;
+                        d[b - float.Epsilon] = sa.Point;
+                        d[b] = sb.Point;
+                        break;
+
+                    case 1:
+                        d[a] = sa.Point;
+                        d[b] = sb.Point;
+                        break;
+
+                    case 3:
+                        var t = a;
+                        while (t < b)
+                        {
+                            d[t] = this.GetPoint(t);
+                            t += 1.0f / 30.0f;
+                        }
+
+                        break;
+
+                    default: throw new NotImplementedException();
+                }
+            }
+
+            return d;
+        }
+
+        IReadOnlyDictionary<float, (T, T, T)> IConvertibleCurve<T>.ToSplineCurve()
+        {
+            var d = new Dictionary<float, (T, T, T)>();
+
+            var orderedKeys = _Keys.Keys.ToList();
+
+            for (int i = 0; i < orderedKeys.Count - 1; ++i)
+            {
+                var a = orderedKeys[i + 0];
+                var b = orderedKeys[i + 1];
+
+                var sa = _Keys[a];
+                var sb = _Keys[b];
+
+                if (!d.TryGetValue(a, out (T, T, T) da)) da = default;
+                if (!d.TryGetValue(b, out (T, T, T) db)) db = default;
+
+                da.Item2 = sa.Point;
+                db.Item2 = sb.Point;
+
+                var delta = GetTangent(da.Item2, da.Item2);
+
+                switch (sa.Degree)
+                {
+                    case 0: // simulate a step with an extra key
+                        da.Item3 = default;
+                        d[b - float.Epsilon] = (default, sa.Point, delta);
+                        db.Item1 = delta;
+                        break;
+
+                    case 1: // tangents are the delta between points
+                        da.Item3 = db.Item1 = delta;
+                        break;
+
+                    case 3: // actual tangents
+                        da.Item3 = sa.OutgoingTangent;
+                        db.Item1 = sb.IncomingTangent;
+                        break;
+
+                    default: throw new NotImplementedException();
+                }
+
+                d[a] = da;
+                d[b] = db;
+            }
+
+            return d;
+        }
+
+        #endregion
+    }
+
+    static class CurveFactory
+    {
+        // TODO: we could support conversions between linear and cubic (with hermite regression)
+
+        public static CurveBuilder<T> CreateCurveBuilder<T>()
+        {
+            if (typeof(T) == typeof(Vector3)) return new Vector3CurveBuilder() as CurveBuilder<T>;
+            if (typeof(T) == typeof(Quaternion)) return new QuaternionCurveBuilder() as CurveBuilder<T>;
+            if (typeof(T) == typeof(float[])) throw new NotImplementedException();
+
+            throw new ArgumentException(nameof(T), "Generic argument not supported");
+        }
+    }
+
+    sealed class Vector3CurveBuilder : CurveBuilder<Vector3>, ICurveSampler<Vector3>
+    {
+        protected override Vector3 GetTangent(Vector3 fromValue, Vector3 toValue)
+        {
+            return toValue - fromValue;
+        }
+
+        public override Vector3 GetPoint(float offset)
+        {
+            var sample = FindSample(offset);
+
+            if (sample.Item1.Degree == 0) return sample.Item1.Point;
+
+            if (sample.Item1.Degree == 1)
+            {
+                return Vector3.Lerp(sample.Item1.Point, sample.Item2.Point, sample.Item3);
+            }
+
+            System.Diagnostics.Debug.Assert(sample.Item1.Degree == 3, "invalid interpolation mode");
+
+            var pointStart = sample.Item1.Point;
+            var tangentOut = sample.Item1.OutgoingTangent;
+            var pointEnd = sample.Item2.Point;
+            var tangentIn = sample.Item2.IncomingTangent;
+
+            var basis = SamplerFactory.CreateHermitePointWeights(sample.Item3);
+
+            return (pointStart * basis.Item1) + (pointEnd * basis.Item2) + (tangentOut * basis.Item3) + (tangentIn * basis.Item4);
+        }
     }
     }
 
 
-    public sealed class Vector3CurveBuilder : CurveBuilder<Vector3>
+    sealed class QuaternionCurveBuilder : CurveBuilder<Quaternion>, ICurveSampler<Quaternion>
     {
     {
+        protected override Quaternion GetTangent(Quaternion fromValue, Quaternion toValue)
+        {
+            return SamplerFactory.CreateTangent(fromValue, toValue, 1);
+        }
 
 
+        public override Quaternion GetPoint(float offset)
+        {
+            var sample = FindSample(offset);
+
+            if (sample.Item1.Degree == 0) return sample.Item1.Point;
+
+            if (sample.Item1.Degree == 1) return Quaternion.Slerp(sample.Item1.Point, sample.Item2.Point, sample.Item3);
+
+            System.Diagnostics.Debug.Assert(sample.Item1.Degree == 3, "invalid interpolation mode");
+
+            var pointStart = sample.Item1.Point;
+            var tangentOut = sample.Item1.OutgoingTangent;
+            var pointEnd = sample.Item2.Point;
+            var tangentIn = sample.Item2.IncomingTangent;
+
+            var basis = SamplerFactory.CreateHermitePointWeights(sample.Item3);
+
+            var q = (pointStart * basis.Item1) + (pointEnd * basis.Item2) + (tangentOut * basis.Item3) + (tangentIn * basis.Item4);
+
+            return Quaternion.Normalize(q);
+        }
     }
     }
 
 
+    //--------------------------------
+    // unused code
+    //--------------------------------
+
     [System.Diagnostics.DebuggerDisplay("[{_Offset}] = {Sample}")]
     [System.Diagnostics.DebuggerDisplay("[{_Offset}] = {Sample}")]
     struct CurvePoint<T>
     struct CurvePoint<T>
         where T : struct
         where T : struct
@@ -140,29 +357,6 @@ namespace SharpGLTF.Animations
         #endregion
         #endregion
     }
     }
 
 
-    static class CurveFactory
-    {
-        // TODO: we could support conversions between linear and cubic (with hermite regression)
-
-        public static Curve<T> CreateSplineCurve<T>()
-            where T : struct
-        {
-            if (typeof(T) == typeof(Single)) return new ScalarSplineCurve() as Curve<T>;
-            if (typeof(T) == typeof(Vector3)) return new Vector3SplineCurve() as Curve<T>;
-            if (typeof(T) == typeof(Quaternion)) return new QuaternionSplineCurve() as Curve<T>;
-
-            throw new ArgumentException(nameof(T), "Generic argument not supported");
-        }
-    }
-
-    struct _CurveNode<T>
-    {
-        public T IncomingTangent;
-        public T Point;
-        public T OutgoingTangent;
-        public int OutgoingMode;
-    }
-
     /// <summary>
     /// <summary>
     /// Represents a collection of consecutive nodes that can be sampled into a continuous curve.
     /// Represents a collection of consecutive nodes that can be sampled into a continuous curve.
     /// </summary>
     /// </summary>
@@ -197,7 +391,7 @@ namespace SharpGLTF.Animations
         /// <summary>
         /// <summary>
         /// Gets a value indicating if the keys of this curve are at least Step, Linear, or Spline.
         /// Gets a value indicating if the keys of this curve are at least Step, Linear, or Spline.
         /// </summary>
         /// </summary>
-        public int Degree => _Keys.Values.Select(item => item.OutgoingMode).Max();
+        public int MaxDegree => _Keys.Values.Select(item => item.Degree).Max();
 
 
         #endregion
         #endregion
 
 
@@ -257,7 +451,7 @@ namespace SharpGLTF.Animations
 
 
         public IReadOnlyDictionary<float, T> ToStepCurve()
         public IReadOnlyDictionary<float, T> ToStepCurve()
         {
         {
-            Guard.IsTrue(Degree == 0, nameof(Degree));
+            Guard.IsTrue(MaxDegree == 0, nameof(MaxDegree));
 
 
             // todo: if Degree is not zero we might export sampled data at 60FPS
             // todo: if Degree is not zero we might export sampled data at 60FPS
 
 
@@ -277,12 +471,12 @@ namespace SharpGLTF.Animations
             {
             {
                 d[v1.Key] = v1.Value.Point;
                 d[v1.Key] = v1.Value.Point;
 
 
-                if (v0.Value.OutgoingMode == 0)
+                if (v0.Value.Degree == 0)
                 {
                 {
                     d[v1.Key - float.Epsilon] = v0.Value.Point;
                     d[v1.Key - float.Epsilon] = v0.Value.Point;
                 }
                 }
 
 
-                if (v0.Value.OutgoingMode == 2)
+                if (v0.Value.Degree == 2)
                 {
                 {
                     var ll = v1.Key - v0.Key;
                     var ll = v1.Key - v0.Key;
 
 
@@ -330,14 +524,14 @@ namespace SharpGLTF.Animations
         {
         {
             var sample = FindSample(offset);
             var sample = FindSample(offset);
 
 
-            if (sample.Item1.OutgoingMode == 0) return sample.Item1.Point;
+            if (sample.Item1.Degree == 0) return sample.Item1.Point;
 
 
-            if (sample.Item1.OutgoingMode == 1)
+            if (sample.Item1.Degree == 1)
             {
             {
                 return (sample.Item1.Point * (1 - sample.Item3)) + (sample.Item2.Point * sample.Item3);
                 return (sample.Item1.Point * (1 - sample.Item3)) + (sample.Item2.Point * sample.Item3);
             }
             }
 
 
-            System.Diagnostics.Debug.Assert(sample.Item1.OutgoingMode == 3, "invalid interpolation mode");
+            System.Diagnostics.Debug.Assert(sample.Item1.Degree == 3, "invalid interpolation mode");
 
 
             var pointStart = sample.Item1.Point;
             var pointStart = sample.Item1.Point;
             var tangentOut = sample.Item1.OutgoingTangent;
             var tangentOut = sample.Item1.OutgoingTangent;
@@ -353,11 +547,11 @@ namespace SharpGLTF.Animations
         {
         {
             var sample = FindSample(offset);
             var sample = FindSample(offset);
 
 
-            if (sample.Item1.OutgoingMode == 0) return 0;
+            if (sample.Item1.Degree == 0) return 0;
 
 
-            if (sample.Item1.OutgoingMode == 1) return sample.Item2.Point - sample.Item1.Point;
+            if (sample.Item1.Degree == 1) return sample.Item2.Point - sample.Item1.Point;
 
 
-            System.Diagnostics.Debug.Assert(sample.Item1.OutgoingMode == 3, "invalid interpolation mode");
+            System.Diagnostics.Debug.Assert(sample.Item1.Degree == 3, "invalid interpolation mode");
 
 
             var pointStart = sample.Item1.Point;
             var pointStart = sample.Item1.Point;
             var tangentOut = sample.Item1.OutgoingTangent;
             var tangentOut = sample.Item1.OutgoingTangent;
@@ -409,14 +603,14 @@ namespace SharpGLTF.Animations
         {
         {
             var sample = FindSample(offset);
             var sample = FindSample(offset);
 
 
-            if (sample.Item1.OutgoingMode == 0) return sample.Item1.Point;
+            if (sample.Item1.Degree == 0) return sample.Item1.Point;
 
 
-            if (sample.Item1.OutgoingMode == 1)
+            if (sample.Item1.Degree == 1)
             {
             {
                 return Vector3.Lerp(sample.Item1.Point, sample.Item2.Point, sample.Item3);
                 return Vector3.Lerp(sample.Item1.Point, sample.Item2.Point, sample.Item3);
             }
             }
 
 
-            System.Diagnostics.Debug.Assert(sample.Item1.OutgoingMode == 3, "invalid interpolation mode");
+            System.Diagnostics.Debug.Assert(sample.Item1.Degree == 3, "invalid interpolation mode");
 
 
             var pointStart = sample.Item1.Point;
             var pointStart = sample.Item1.Point;
             var tangentOut = sample.Item1.OutgoingTangent;
             var tangentOut = sample.Item1.OutgoingTangent;
@@ -432,11 +626,11 @@ namespace SharpGLTF.Animations
         {
         {
             var sample = FindSample(offset);
             var sample = FindSample(offset);
 
 
-            if (sample.Item1.OutgoingMode == 0) return Vector3.Zero;
+            if (sample.Item1.Degree == 0) return Vector3.Zero;
 
 
-            if (sample.Item1.OutgoingMode == 1) return sample.Item2.Point - sample.Item1.Point;
+            if (sample.Item1.Degree == 1) return sample.Item2.Point - sample.Item1.Point;
 
 
-            System.Diagnostics.Debug.Assert(sample.Item1.OutgoingMode == 3, "invalid interpolation mode");
+            System.Diagnostics.Debug.Assert(sample.Item1.Degree == 3, "invalid interpolation mode");
 
 
             var pointStart = sample.Item1.Point;
             var pointStart = sample.Item1.Point;
             var tangentOut = sample.Item1.OutgoingTangent;
             var tangentOut = sample.Item1.OutgoingTangent;
@@ -488,11 +682,11 @@ namespace SharpGLTF.Animations
         {
         {
             var sample = FindSample(offset);
             var sample = FindSample(offset);
 
 
-            if (sample.Item1.OutgoingMode == 0) return sample.Item1.Point;
+            if (sample.Item1.Degree == 0) return sample.Item1.Point;
 
 
-            if (sample.Item1.OutgoingMode == 1) return Quaternion.Slerp(sample.Item1.Point, sample.Item2.Point, sample.Item3);
+            if (sample.Item1.Degree == 1) return Quaternion.Slerp(sample.Item1.Point, sample.Item2.Point, sample.Item3);
 
 
-            System.Diagnostics.Debug.Assert(sample.Item1.OutgoingMode == 3, "invalid interpolation mode");
+            System.Diagnostics.Debug.Assert(sample.Item1.Degree == 3, "invalid interpolation mode");
 
 
             var pointStart = sample.Item1.Point;
             var pointStart = sample.Item1.Point;
             var tangentOut = sample.Item1.OutgoingTangent;
             var tangentOut = sample.Item1.OutgoingTangent;
@@ -510,11 +704,11 @@ namespace SharpGLTF.Animations
         {
         {
             var sample = FindSample(offset);
             var sample = FindSample(offset);
 
 
-            if (sample.Item1.OutgoingMode == 0) return Quaternion.Identity;
+            if (sample.Item1.Degree == 0) return Quaternion.Identity;
 
 
-            if (sample.Item1.OutgoingMode == 1) throw new NotImplementedException();
+            if (sample.Item1.Degree == 1) throw new NotImplementedException();
 
 
-            System.Diagnostics.Debug.Assert(sample.Item1.OutgoingMode == 3, "invalid interpolation mode");
+            System.Diagnostics.Debug.Assert(sample.Item1.Degree == 3, "invalid interpolation mode");
 
 
             var pointStart = sample.Item1.Point;
             var pointStart = sample.Item1.Point;
             var tangentOut = sample.Item1.OutgoingTangent;
             var tangentOut = sample.Item1.OutgoingTangent;

+ 3 - 3
src/SharpGLTF.Toolkit/Schema2/AnimationExtensions.cs

@@ -21,7 +21,7 @@ namespace SharpGLTF.Schema2
             {
             {
                 var animation = node.LogicalParent.UseAnimation(animationName);
                 var animation = node.LogicalParent.UseAnimation(animationName);
 
 
-                var degree = curve.Degree;
+                var degree = curve.MaxDegree;
                 if (degree == 0) animation.CreateScaleChannel(node, curve.ToStepCurve(), false);
                 if (degree == 0) animation.CreateScaleChannel(node, curve.ToStepCurve(), false);
                 if (degree == 1) animation.CreateScaleChannel(node, curve.ToLinearCurve(), true);
                 if (degree == 1) animation.CreateScaleChannel(node, curve.ToLinearCurve(), true);
                 if (degree == 3) animation.CreateScaleChannel(node, curve.ToSplineCurve());
                 if (degree == 3) animation.CreateScaleChannel(node, curve.ToSplineCurve());
@@ -36,7 +36,7 @@ namespace SharpGLTF.Schema2
             {
             {
                 var animation = node.LogicalParent.UseAnimation(animationName);
                 var animation = node.LogicalParent.UseAnimation(animationName);
 
 
-                var degree = curve.Degree;
+                var degree = curve.MaxDegree;
                 if (degree == 0) animation.CreateTranslationChannel(node, curve.ToStepCurve(), false);
                 if (degree == 0) animation.CreateTranslationChannel(node, curve.ToStepCurve(), false);
                 if (degree == 1) animation.CreateTranslationChannel(node, curve.ToLinearCurve(), true);
                 if (degree == 1) animation.CreateTranslationChannel(node, curve.ToLinearCurve(), true);
                 if (degree == 3) animation.CreateTranslationChannel(node, curve.ToSplineCurve());
                 if (degree == 3) animation.CreateTranslationChannel(node, curve.ToSplineCurve());
@@ -51,7 +51,7 @@ namespace SharpGLTF.Schema2
             {
             {
                 var animation = node.LogicalParent.UseAnimation(animationName);
                 var animation = node.LogicalParent.UseAnimation(animationName);
 
 
-                var degree = curve.Degree;
+                var degree = curve.MaxDegree;
                 if (degree == 0) animation.CreateRotationChannel(node, curve.ToStepCurve(), false);
                 if (degree == 0) animation.CreateRotationChannel(node, curve.ToStepCurve(), false);
                 if (degree == 1) animation.CreateRotationChannel(node, curve.ToLinearCurve(), true);
                 if (degree == 1) animation.CreateRotationChannel(node, curve.ToLinearCurve(), true);
                 if (degree == 3) animation.CreateRotationChannel(node, curve.ToSplineCurve());
                 if (degree == 3) animation.CreateRotationChannel(node, curve.ToSplineCurve());

+ 3 - 3
tests/SharpGLTF.Tests/Scenes/SceneBuilderTests.cs

@@ -46,9 +46,9 @@ namespace SharpGLTF.Scenes
 
 
             var pivot = new NodeBuilder();
             var pivot = new NodeBuilder();
 
 
-            // pivot.UseTranslation("track1")
-                // .WithKey(0, Vector3.Zero)
-                // .WithKey(1, Vector3.One);
+            pivot.UseTranslation("track1")
+                .WithKey(0, Vector3.Zero)
+                .WithKey(1, Vector3.One);
 
 
             var scene = new SceneBuilder();            
             var scene = new SceneBuilder();