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 static void SmoothLocalInterpolation(BezierKeyframe previous, float previousTime, ref BezierKeyframe current, BezierKeyframe next, float nextTime) { if (next.HasValue() && previous.HasValue()) { var inHandle = (current.value - previous.value) / 3f; var outHandle = (next.value - current.value) / 3f; var bothSegmentsDuration = nextTime - previousTime; var inRatio = (current.time - previousTime) / bothSegmentsDuration; var outRatio = (nextTime - current.time) / bothSegmentsDuration; var avg = inHandle * inRatio + outHandle * outRatio; if (inRatio > outRatio) { current.controlPointIn = current.value - avg; current.controlPointOut = current.value + avg * outRatio; } else { current.controlPointIn = current.value - avg * inRatio; current.controlPointOut = current.value + avg; } } else if (previous.IsNull()) { current.controlPointIn = current.value; current.controlPointOut = current.value + (next.value - current.value) / 3f; } else if (next.IsNull()) { current.controlPointIn = current.value - (current.value - previous.value) / 3f; current.controlPointOut = current.value; } }
public static float ComputeValue(BezierKeyframe current, BezierKeyframe next, float time) { if (next.IsNull()) { return(current.value); } var t = (time - current.time) / (next.time - current.time); switch (current.curveType) { case CurveTypeValues.Constant: return(current.value); case CurveTypeValues.Linear: case CurveTypeValues.FlatLinear: { return(current.value + (next.value - current.value) * t); } } var w0 = current.value; var w1 = current.controlPointOut; var w2 = next.controlPointIn; var w3 = next.value; // See https://pomax.github.io/bezierinfo/#how-to-implement-the-weighted-basis-function var mt = 1f - t; var mt2 = mt * mt; var mt3 = mt2 * mt; var t2 = t * t; var t3 = t2 * t; return(w0 * mt3 + 3f * w1 * mt2 * t + 3f * w2 * mt * t2 + w3 * t3); }
public int AddKey(BezierKeyframe keyframe) { if (keyframe.time > duration) { keys.Add(keyframe); return(_lastReferencedKey = keys.Count - 1); } var nearestKey = KeyframeBinarySearch(keyframe.time, true); var nearestKeyframe = keys[nearestKey]; if (Mathf.Abs(nearestKeyframe.time - keyframe.time) < _epsilon) { return(-1); } if (nearestKeyframe.time < keyframe.time) { var key = nearestKey + 1; keys.Insert(key, keyframe); _lastReferencedKey = key; return(key); } keys.Insert(nearestKey, keyframe); _lastReferencedKey = nearestKey; return(nearestKey); }
private static void SmoothLocalInterpolation(BezierKeyframe previous, float previousTime, ref BezierKeyframe current, BezierKeyframe next, float nextTime) { if (next.HasValue() && previous.HasValue()) { var inHandle = (current.value - previous.value) / 3f; var outHandle = (next.value - current.value) / 3f; var bothSegmentsDuration = nextTime - previousTime; var inRatio = (current.time - previousTime) / bothSegmentsDuration; var outRatio = (nextTime - current.time) / bothSegmentsDuration; /* // SMOOTH * // The larger the incoming curve, the weaker the effect on the other side * var weightedAvg = inHandle * outRatio + outHandle * inRatio; * if (inRatio > outRatio) * { * current.controlPointIn = current.value - weightedAvg * (inRatio / outRatio); * current.controlPointOut = current.value + weightedAvg; * } * else * { * current.controlPointIn = current.value - weightedAvg; * current.controlPointOut = current.value + weightedAvg * (outRatio / inRatio); * } */ // NO_OVERSHOOT // The larger the incoming curve, the stronger the effect on the other side var weightedAvg = inHandle * inRatio + outHandle * outRatio; if (inRatio > outRatio) { current.controlPointIn = current.value - weightedAvg; current.controlPointOut = current.value + weightedAvg * (outRatio / inRatio); } else { current.controlPointIn = current.value - weightedAvg * (inRatio / outRatio); current.controlPointOut = current.value + weightedAvg; } } else if (previous.IsNull()) { current.controlPointIn = current.value; current.controlPointOut = current.value + (next.value - current.value) / 3f; } else if (next.IsNull()) { current.controlPointIn = current.value - (current.value - previous.value) / 3f; current.controlPointOut = current.value; } }
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); } } }
private static void LinearInterpolation(BezierKeyframe previous, ref BezierKeyframe current, BezierKeyframe next) { if (previous.HasValue()) { current.controlPointIn = current.value - (current.value - previous.value) / 3f; } else { current.controlPointIn = current.value; } if (next.HasValue()) { current.controlPointOut = current.value + (next.value - current.value) / 3f; } else { current.controlPointOut = current.value; } }
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); } } }
public void SetKeySnapshot(float time, BezierKeyframe keyframe) { keyframe.time = time; if (length == 0) { AddKey(keyframe); return; } var index = KeyframeBinarySearch(time); if (index == -1) { AddKey(keyframe); } else { keys[index] = keyframe; } }
protected static float Weighting(BezierKeyframe k1, BezierKeyframe k2) { return(k2.time - k1.time); // if (_totalDistance == 0) return 1f; // return Vector2.Distance(new Vector2(1f - (k1.time / _totalTime), k1.value / _totalDistance), new Vector2(1f - (k2.time / _totalTime), k2.value / _totalDistance)); }
public void SetLastFrame(BezierKeyframe keyframe) { keys[keys.Count - 1] = keyframe; }
public int SetKeyframeByKey(int key, BezierKeyframe keyframe) { keys[key] = keyframe; return(key); }