public static void EnsureQuaternionContinuityAndRecalculateSlope(BezierAnimationCurve x, BezierAnimationCurve y, BezierAnimationCurve z, BezierAnimationCurve w, Quaternion last) { var keyCount = x.length; if (keyCount < 2) { return; } for (var i = 0; i < keyCount; i++) { var cur = GetValue(x, y, z, w, i); if (Quaternion.Dot(cur, last) < 0.0f) { cur = new Quaternion(-cur.x, -cur.y, -cur.z, -cur.w); } last = cur; SetValue(x, y, z, w, i, cur); } // for (int i = 0; i < keyCount; i++) // { // RecalculateSplineSlopeT(x, i); // RecalculateSplineSlopeT(y, i); // RecalculateSplineSlopeT(z, i); // RecalculateSplineSlopeT(w, i); // } }
public IEnumerable EvaluateLinear(TestContext context) { var curve = new BezierAnimationCurve { loop = false }; curve.SetKeyframe(0, 10, CurveTypeValues.Linear); curve.SetKeyframe(1, 20, CurveTypeValues.Linear); curve.SetKeyframe(2, 30, CurveTypeValues.Linear); if (!context.Assert(curve.Evaluate(0.0f), 10f, "Linear/0")) { yield break; } if (!context.Assert(curve.Evaluate(0.5f), 15f, "Linear/1")) { yield break; } if (!context.Assert(curve.Evaluate(1.0f), 20f, "Linear/2")) { yield break; } if (!context.Assert(curve.Evaluate(1.5f), 25f, "Linear/3")) { yield break; } if (!context.Assert(curve.Evaluate(2.0f), 30f, "Linear/4")) { yield break; } }
private static void SetValue(BezierAnimationCurve x, BezierAnimationCurve y, BezierAnimationCurve z, BezierAnimationCurve w, int key, Quaternion q) { SetValue(x, key, q.x); SetValue(y, key, q.y); SetValue(z, key, q.z); SetValue(w, key, q.w); }
private static void SetValue(BezierAnimationCurve curve, int key, float value) { var keyframe = curve.GetKeyframeByKey(key); keyframe.value = value; curve.SetKeyframeByKey(key, keyframe); }
public IEnumerable KeyframeBinarySearch(TestContext context) { var curve = new BezierAnimationCurve(); curve.SetKeyframe(0, 10, CurveTypeValues.Linear); curve.SetKeyframe(1, 20, CurveTypeValues.Linear); curve.SetKeyframe(2, 30, CurveTypeValues.Linear); if (!context.Assert(curve.KeyframeBinarySearch(0.0f), 0, "0.0f")) { yield break; } if (!context.Assert(curve.KeyframeBinarySearch(0.5f, true), 1, "0.5f")) { yield break; } if (!context.Assert(curve.KeyframeBinarySearch(1.0f), 1, "1.0f")) { yield break; } if (!context.Assert(curve.KeyframeBinarySearch(1.5f, true), 2, "1.5f")) { yield break; } if (!context.Assert(curve.KeyframeBinarySearch(2.0f), 2, "2.0f")) { yield break; } }
private static void DeserializeCurveFromClassLegacy(BezierAnimationCurve curve, JSONNode curveJSON) { var keysJSON = curveJSON["keys"].AsArray; if (keysJSON.Count == 0) { return; } var last = -1f; foreach (JSONNode keyframeJSON in keysJSON) { var time = DeserializeFloat(keyframeJSON["time"]).Snap(); if (time == last) { continue; } last = time; var value = DeserializeFloat(keyframeJSON["value"]); var keyframe = new BezierKeyframe( time, value, CurveTypeValues.SmoothLocal ); curve.AddKey(keyframe); } }
private void BindCurve(BezierAnimationCurve lead, Color color, string label) { var lines = CreateCurvesLines(_linesContainer, color, label); _lines.Add(lines); lines.AddCurve(color, lead); lines.SetVerticesDirty(); }
public IEnumerable AddAndRemoveFrames(TestContext context) { var curve = new BezierAnimationCurve(); { var key = curve.SetKeyframe(0, 123, CurveTypeValues.Linear); if (!context.Assert(key, 0, "First key is zero")) { yield break; } if (!context.Assert(curve.keys.Select(k => k.time), new[] { 0f }, "Expected one frame")) { yield break; } context.Assert(curve.GetKeyframeByKey(curve.KeyframeBinarySearch(0)).value, 123, "Set and get at time 0"); } { var key = curve.SetKeyframe(0.499999f, 456, CurveTypeValues.Linear); if (!context.Assert(key, 1, "Second key is one")) { yield break; } if (!context.Assert(curve.keys.Select(k => k.time), new[] { 0f, 0.5f }, "Expected two frames")) { yield break; } context.Assert(curve.GetKeyframeByKey(curve.KeyframeBinarySearch(0.000001f)).value, 123, "Set and get at time 0.000001"); context.Assert(curve.GetKeyframeByKey(curve.KeyframeBinarySearch(0.499999f)).value, 456, "Set and get at time 0.499999"); } { var key = curve.SetKeyframe(0.250f, 789, CurveTypeValues.Linear); if (!context.Assert(key, 1, "Third key is one")) { yield break; } if (!context.Assert(curve.keys.Select(k => k.time), new[] { 0f, 0.250f, 0.5f }, "Expected three frames")) { yield break; } context.Assert(curve.GetKeyframeByKey(curve.KeyframeBinarySearch(0.000001f)).value, 123, "Set and get at time 0.000001"); context.Assert(curve.GetKeyframeByKey(curve.KeyframeBinarySearch(0.250f)).value, 789, "Set and get at time 0.250f"); context.Assert(curve.GetKeyframeByKey(curve.KeyframeBinarySearch(0.499999f)).value, 456, "Set and get at time 0.499999"); } { curve.RemoveKey(1); if (!context.Assert(curve.keys.Select(k => k.time), new[] { 0f, 0.5f }, "Expected two frames after remove")) { yield break; } } yield break; }
public IEnumerable EvaluateSmoothGlobalNonLooping(TestContext context) { var curve = new BezierAnimationCurve { loop = false }; curve.SetKeyframe(0, 100, CurveTypeValues.SmoothGlobal); curve.SetKeyframe(1, 200, CurveTypeValues.SmoothGlobal); curve.SetKeyframe(2, 300, CurveTypeValues.SmoothGlobal); curve.SetKeyframe(3, 200, CurveTypeValues.SmoothGlobal); curve.SetKeyframe(4, 100, CurveTypeValues.SmoothGlobal); curve.ComputeCurves(); if (!context.Assert(curve.Evaluate(0.0f), 100f, "0.0")) { yield break; } if (!context.Assert(curve.Evaluate(0.5f).Snap(0.001f), 144.643f, "0.5")) { yield break; } if (!context.Assert(curve.Evaluate(1.0f), 200f, "1.0")) { yield break; } if (!context.Assert(curve.Evaluate(1.5f).Snap(0.001f), 266.071f, "1.5")) { yield break; } if (!context.Assert(curve.Evaluate(2.0f), 300f, "2.0")) { yield break; } if (!context.Assert(curve.Evaluate(2.5f).Snap(0.001f), 266.071f, "2.5")) { yield break; } if (!context.Assert(curve.Evaluate(3.0f), 200f, "3.0")) { yield break; } if (!context.Assert(curve.Evaluate(3.5f).Snap(0.001f), 144.643f, "3.5")) { yield break; } if (!context.Assert(curve.Evaluate(4.0f), 100f, "4.0")) { yield break; } }
protected void Validate(BezierAnimationCurve curve, float animationLength) { if (animationLength <= 0) { SuperController.LogError($"Target {name} has an invalid animation length of {animationLength}"); return; } if (curve.length < 2) { SuperController.LogError($"Target {name} has {curve.length} frames"); return; } if (curve.GetFirstFrame().time != 0) { SuperController.LogError($"Target {name} has no start frame. Frames: {string.Join(", ", curve.keys.Select(k => k.time.ToString(CultureInfo.InvariantCulture)).ToArray())}"); return; } if (curve.duration > animationLength + 0.0001f) { SuperController.LogError($"Target {name} has duration of {curve.duration:0.0000} but the animation should be {animationLength:0.0000}. Auto-repairing extraneous keys."); foreach (var c in GetCurves()) { while (c.GetKeyframeByKey(c.length - 1).time > animationLength && c.length > 2) { c.RemoveKey(c.length - 1); } } dirty = true; } if (curve.duration != animationLength) { if (Mathf.Abs(curve.duration - animationLength) > 0.0009f) { SuperController.LogError($"Target {name} ends with frame {curve.duration:0.0000} instead of expected {animationLength:0.0000}. Auto-repairing last frame."); } foreach (var c in GetCurves()) { var keyframe = c.GetLastFrame(); if (keyframe.time == animationLength) { continue; } keyframe.time = animationLength; c.SetLastFrame(keyframe); } dirty = true; } }
private void DeserializeCurve(BezierAnimationCurve curve, JSONNode curveJSON, ref bool dirty) { if (curveJSON is JSONArray) { DeserializeCurveFromArray(curve, (JSONArray)curveJSON, ref dirty); } if (curveJSON is JSONClass) { DeserializeCurveFromClassLegacy(curve, curveJSON); dirty = true; } else { DeserializeCurveFromStringLegacy(curve, curveJSON); dirty = true; } }
private static void DeserializeCurveFromArray(BezierAnimationCurve curve, JSONArray curveJSON, ref bool dirty) { if (curveJSON.Count == 0) { return; } var last = -1f; foreach (JSONClass keyframeJSON in curveJSON) { try { var time = float.Parse(keyframeJSON["t"], CultureInfo.InvariantCulture).Snap(); if (time == last) { continue; } last = time; var value = DeserializeFloat(keyframeJSON["v"]); var keyframe = new BezierKeyframe { time = time, value = value, curveType = int.Parse(keyframeJSON["c"]), controlPointIn = DeserializeFloat(keyframeJSON["i"]), controlPointOut = DeserializeFloat(keyframeJSON["o"]) }; // Backward compatibility, tangents are not supported since bezier conversion. if (keyframeJSON.HasKey("ti")) { dirty = true; if (keyframe.curveType == CurveTypeValues.LeaveAsIs) { keyframe.curveType = CurveTypeValues.SmoothLocal; } } curve.AddKey(keyframe); } catch (IndexOutOfRangeException exc) { throw new InvalidOperationException($"Failed to read curve: {keyframeJSON}", exc); } } }
public IEnumerable RepairBrokenCurve(TestContext context) { var curve = new BezierAnimationCurve(); curve.SetKeyframe(1, 2, CurveTypeValues.Linear); curve.SetKeyframe(2, 3, CurveTypeValues.Linear); curve.SetKeyframe(3, 4, CurveTypeValues.Linear); if (!context.Assert(curve.keys.Select(k => k.time), new[] { 1f, 2f, 3f }, "Expected broken curve")) { yield break; } curve.AddEdgeFramesIfMissing(5f, CurveTypeValues.Linear); if (!context.Assert(curve.keys.Select(k => k.time), new[] { 0f, 1f, 2f, 3f, 5f }, "Expected repaired curve")) { yield break; } }
private static void DeserializeCurveFromStringLegacy(BezierAnimationCurve curve, JSONNode curveJSON) { var strFrames = curveJSON.Value.Split(';').Where(x => x != "").ToList(); if (strFrames.Count == 0) { return; } var last = -1f; foreach (var strFrame in strFrames) { var parts = strFrame.Split(','); try { var time = float.Parse(parts[0], CultureInfo.InvariantCulture).Snap(); if (time == last) { continue; } last = time; var value = DeserializeFloat(parts[1]); var keyframe = new BezierKeyframe { time = time, value = value, curveType = int.Parse(parts[2]) }; // Backward compatibility, tangents are not supported since bezier conversion. if (keyframe.curveType == CurveTypeValues.LeaveAsIs) { keyframe.curveType = CurveTypeValues.SmoothLocal; } curve.AddKey(keyframe); } catch (IndexOutOfRangeException exc) { throw new InvalidOperationException($"Failed to read curve: {strFrame}", exc); } } }
private static JSONNode SerializeCurve(BezierAnimationCurve curve) { var curveJSON = new JSONArray(); for (var key = 0; key < curve.length; key++) { var keyframe = curve.GetKeyframeByKey(key); var curveEntry = new JSONClass { ["t"] = keyframe.time.ToString(CultureInfo.InvariantCulture), ["v"] = keyframe.value.ToString(CultureInfo.InvariantCulture), ["c"] = keyframe.curveType.ToString(CultureInfo.InvariantCulture), ["i"] = keyframe.controlPointIn.ToString(CultureInfo.InvariantCulture), ["o"] = keyframe.controlPointOut.ToString(CultureInfo.InvariantCulture) }; curveJSON.Add(curveEntry); } return(curveJSON); }
// const float kDefaultWeight = 1.0f / 3.0f; // const float kCurveTimeEpsilon = 0.00001f; private static Quaternion GetValue(BezierAnimationCurve x, BezierAnimationCurve y, BezierAnimationCurve z, BezierAnimationCurve w, int key) { return(new Quaternion(x.GetKeyframeByKey(key).value, y.GetKeyframeByKey(key).value, z.GetKeyframeByKey(key).value, w.GetKeyframeByKey(key).value)); }
public void AddCurve(Color color, BezierAnimationCurve curve) { _curves.Add(new KeyValuePair <Color, BezierAnimationCurve>(color, curve)); }