Refactor Bezier splines drawing and editing to property evaluate value and match curve evaluation

#3051
This commit is contained in:
Wojtek Figat
2024-12-02 19:10:28 +01:00
parent 0a4a431f74
commit 57628c3d5f
12 changed files with 129 additions and 93 deletions

View File

@@ -4,7 +4,7 @@
"Major": 1, "Major": 1,
"Minor": 9, "Minor": 9,
"Revision": 0, "Revision": 0,
"Build": 6605 "Build": 6606
}, },
"Company": "Flax", "Company": "Flax",
"Copyright": "Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.", "Copyright": "Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.",

View File

@@ -231,11 +231,10 @@ namespace FlaxEditor.GUI
else if (_isMovingTangent) else if (_isMovingTangent)
{ {
var viewRect = _editor._mainPanel.GetClientArea(); var viewRect = _editor._mainPanel.GetClientArea();
var direction = _movingTangent.IsIn ? -1.0f : 1.0f;
var k = _editor.GetKeyframe(_movingTangent.Index); var k = _editor.GetKeyframe(_movingTangent.Index);
var kv = _editor.GetKeyframeValue(k); var kv = _editor.GetKeyframeValue(k);
var value = _editor.Accessor.GetCurveValue(ref kv, _movingTangent.Component); var value = _editor.Accessor.GetCurveValue(ref kv, _movingTangent.Component);
_movingTangent.TangentValue = direction * (PointToKeyframes(location, ref viewRect).Y - value); _movingTangent.TangentValue = PointToKeyframes(location, ref viewRect).Y - value;
_editor.UpdateTangents(); _editor.UpdateTangents();
Cursor = CursorType.SizeNS; Cursor = CursorType.SizeNS;
_movedKeyframes = true; _movedKeyframes = true;

View File

@@ -682,9 +682,9 @@ namespace FlaxEditor.GUI
var minPosPoint = _contents.PointToParent(ref minPos); var minPosPoint = _contents.PointToParent(ref minPos);
var scroll = new Float2(_mainPanel.HScrollBar?.TargetValue ?? 0, _mainPanel.VScrollBar?.TargetValue ?? 0); var scroll = new Float2(_mainPanel.HScrollBar?.TargetValue ?? 0, _mainPanel.VScrollBar?.TargetValue ?? 0);
scroll = ApplyUseModeMask(EnablePanning, minPosPoint, scroll); scroll = ApplyUseModeMask(EnablePanning, minPosPoint, scroll);
if (_mainPanel.HScrollBar != null && _mainPanel.HScrollBar.Enabled) if (_mainPanel.HScrollBar != null)
_mainPanel.HScrollBar.TargetValue = scroll.X; _mainPanel.HScrollBar.TargetValue = scroll.X;
if (_mainPanel.VScrollBar != null && _mainPanel.VScrollBar.Enabled) if (_mainPanel.VScrollBar != null)
_mainPanel.VScrollBar.TargetValue = scroll.Y; _mainPanel.VScrollBar.TargetValue = scroll.Y;
UpdateKeyframes(); UpdateKeyframes();
@@ -1649,6 +1649,7 @@ namespace FlaxEditor.GUI
var o = _keyframes[p.Index - 1]; var o = _keyframes[p.Index - 1];
var oValue = Accessor.GetCurveValue(ref o.Value, p.Component); var oValue = Accessor.GetCurveValue(ref o.Value, p.Component);
var slope = (value - oValue) / (k.Time - o.Time); var slope = (value - oValue) / (k.Time - o.Time);
slope = -slope;
Accessor.SetCurveValue(slope, ref k.TangentIn, p.Component); Accessor.SetCurveValue(slope, ref k.TangentIn, p.Component);
} }
@@ -2199,12 +2200,12 @@ namespace FlaxEditor.GUI
var tangent = t.TangentValue; var tangent = t.TangentValue;
var direction = t.IsIn ? -1.0f : 1.0f; var direction = t.IsIn ? -1.0f : 1.0f;
var offset = 30.0f * direction; var offset = 30.0f;
var location = GetKeyframePoint(ref k, selectedComponent); var location = GetKeyframePoint(ref k, selectedComponent);
t.Size = KeyframesSize / ViewScale; t.Size = KeyframesSize / ViewScale;
t.Location = new Float2 t.Location = new Float2
( (
location.X * UnitsPerSecond - t.Width * 0.5f + offset, location.X * UnitsPerSecond - t.Width * 0.5f + offset * direction,
location.Y * -UnitsPerSecond - t.Height * 0.5f + curveContentAreaBounds.Height - offset * tangent location.Y * -UnitsPerSecond - t.Height * 0.5f + curveContentAreaBounds.Height - offset * tangent
); );
@@ -2280,14 +2281,13 @@ namespace FlaxEditor.GUI
var startTangent = Accessor.GetCurveValue(ref startK.TangentOut, component); var startTangent = Accessor.GetCurveValue(ref startK.TangentOut, component);
var endTangent = Accessor.GetCurveValue(ref endK.TangentIn, component); var endTangent = Accessor.GetCurveValue(ref endK.TangentIn, component);
var offset = (end.X - start.X) * 0.5f; var tangentScale = (endK.Time - startK.Time) / 3.0f;
var p1 = PointFromKeyframes(start, ref viewRect); var p1 = PointFromKeyframes(start, ref viewRect);
var p2 = PointFromKeyframes(start + new Float2(offset, startTangent * offset), ref viewRect); var p2 = PointFromKeyframes(start + new Float2(0, startTangent * tangentScale), ref viewRect);
var p3 = PointFromKeyframes(end - new Float2(offset, endTangent * offset), ref viewRect); var p3 = PointFromKeyframes(end + new Float2(0, endTangent * tangentScale), ref viewRect);
var p4 = PointFromKeyframes(end, ref viewRect); var p4 = PointFromKeyframes(end, ref viewRect);
Render2D.DrawBezier(p1, p2, p3, p4, color); Render2D.DrawSpline(p1, p2, p3, p4, color);
} }
} }
} }

View File

@@ -230,7 +230,7 @@ namespace FlaxEditor.GUI.Timeline.GUI
continue; continue;
// Draw all ticks // Draw all ticks
int l = Mathf.Clamp(smallestTick + level, 0, _tickSteps.Length - 1); int l = Mathf.Clamp(smallestTick + level, 0, _tickSteps.Length - 2);
var lStep = _tickSteps[l]; var lStep = _tickSteps[l];
var lNextStep = _tickSteps[l + 1]; var lNextStep = _tickSteps[l + 1];
int startTick = Mathf.FloorToInt(min / lStep); int startTick = Mathf.FloorToInt(min / lStep);

View File

@@ -66,27 +66,23 @@ namespace AnimationUtils
} }
template<class T> template<class T>
FORCE_INLINE static void GetTangent(const T& a, const T& b, float length, T& result) FORCE_INLINE static void GetTangent(const T& value, const T& tangent, float tangentScale, T& result)
{ {
const float oneThird = 1.0f / 3.0f; result = value + tangent * tangentScale;
result = a + b * (length * oneThird);
} }
template<> template<>
FORCE_INLINE void GetTangent<Quaternion>(const Quaternion& a, const Quaternion& b, float length, Quaternion& result) FORCE_INLINE void GetTangent<Quaternion>(const Quaternion& value, const Quaternion& tangent, float tangentScale, Quaternion& result)
{ {
const float oneThird = 1.0f / 3.0f; Quaternion::Slerp(value, tangent, 1.0f / 3.0f, result);
Quaternion::Slerp(a, b, oneThird, result);
} }
template<> template<>
FORCE_INLINE void GetTangent<Transform>(const Transform& a, const Transform& b, float length, Transform& result) FORCE_INLINE void GetTangent<Transform>(const Transform& value, const Transform& tangent, float tangentScale, Transform& result)
{ {
const float oneThird = 1.0f / 3.0f; GetTangent(value.Translation, tangent.Translation, tangentScale, result.Translation);
const float oneThirdLength = length * oneThird; GetTangent(value.Orientation, tangent.Orientation, tangentScale, result.Orientation);
result.Translation = a.Translation + b.Translation * oneThirdLength; GetTangent(value.Scale, tangent.Scale, tangentScale, result.Scale);
Quaternion::Slerp(a.Orientation, b.Orientation, oneThird, result.Orientation);
result.Scale = a.Scale + (b.Scale - a.Scale) * oneThirdLength;
} }
template<class T> template<class T>

View File

@@ -24,9 +24,9 @@ namespace FlaxEngine
/// </summary> /// </summary>
/// <param name="value">The value.</param> /// <param name="value">The value.</param>
/// <param name="tangent">The tangent.</param> /// <param name="tangent">The tangent.</param>
/// <param name="lengthThird">The length divided by 3.</param> /// <param name="tangentScale">The tangent scale factor.</param>
/// <param name="result">The result.</param> /// <param name="result">The result.</param>
void GetTangent(ref U value, ref U tangent, float lengthThird, out U result); void GetTangent(ref U value, ref U tangent, float tangentScale, out U result);
/// <summary> /// <summary>
/// Calculates the linear interpolation at the specified alpha. /// Calculates the linear interpolation at the specified alpha.
@@ -67,7 +67,7 @@ namespace FlaxEngine
IKeyframeAccess<Color32>, IKeyframeAccess<Color32>,
IKeyframeAccess<Color> IKeyframeAccess<Color>
{ {
public void GetTangent(ref bool value, ref bool tangent, float lengthThird, out bool result) public void GetTangent(ref bool value, ref bool tangent, float tangentScale, out bool result)
{ {
result = value; result = value;
} }
@@ -82,9 +82,9 @@ namespace FlaxEngine
result = p0; result = p0;
} }
public void GetTangent(ref int value, ref int tangent, float lengthThird, out int result) public void GetTangent(ref int value, ref int tangent, float tangentScale, out int result)
{ {
result = value + (int)(tangent * lengthThird); result = value + (int)(tangent * tangentScale);
} }
public void Linear(ref int a, ref int b, float alpha, out int result) public void Linear(ref int a, ref int b, float alpha, out int result)
@@ -102,9 +102,9 @@ namespace FlaxEngine
result = Mathf.Lerp(p012, p123, alpha); result = Mathf.Lerp(p012, p123, alpha);
} }
public void GetTangent(ref double value, ref double tangent, float lengthThird, out double result) public void GetTangent(ref double value, ref double tangent, float tangentScale, out double result)
{ {
result = value + tangent * lengthThird; result = value + tangent * tangentScale;
} }
public void Linear(ref double a, ref double b, float alpha, out double result) public void Linear(ref double a, ref double b, float alpha, out double result)
@@ -122,9 +122,9 @@ namespace FlaxEngine
result = Mathf.Lerp(p012, p123, alpha); result = Mathf.Lerp(p012, p123, alpha);
} }
public void GetTangent(ref float value, ref float tangent, float lengthThird, out float result) public void GetTangent(ref float value, ref float tangent, float tangentScale, out float result)
{ {
result = value + tangent * lengthThird; result = value + tangent * tangentScale;
} }
public void Linear(ref float a, ref float b, float alpha, out float result) public void Linear(ref float a, ref float b, float alpha, out float result)
@@ -142,9 +142,9 @@ namespace FlaxEngine
result = Mathf.Lerp(p012, p123, alpha); result = Mathf.Lerp(p012, p123, alpha);
} }
public void GetTangent(ref Vector2 value, ref Vector2 tangent, float lengthThird, out Vector2 result) public void GetTangent(ref Vector2 value, ref Vector2 tangent, float tangentScale, out Vector2 result)
{ {
result = value + tangent * lengthThird; result = value + tangent * tangentScale;
} }
public void Linear(ref Vector2 a, ref Vector2 b, float alpha, out Vector2 result) public void Linear(ref Vector2 a, ref Vector2 b, float alpha, out Vector2 result)
@@ -162,9 +162,9 @@ namespace FlaxEngine
Vector2.Lerp(ref p012, ref p123, alpha, out result); Vector2.Lerp(ref p012, ref p123, alpha, out result);
} }
public void GetTangent(ref Vector3 value, ref Vector3 tangent, float lengthThird, out Vector3 result) public void GetTangent(ref Vector3 value, ref Vector3 tangent, float tangentScale, out Vector3 result)
{ {
result = value + tangent * lengthThird; result = value + tangent * tangentScale;
} }
public void Linear(ref Vector3 a, ref Vector3 b, float alpha, out Vector3 result) public void Linear(ref Vector3 a, ref Vector3 b, float alpha, out Vector3 result)
@@ -182,9 +182,9 @@ namespace FlaxEngine
Vector3.Lerp(ref p012, ref p123, alpha, out result); Vector3.Lerp(ref p012, ref p123, alpha, out result);
} }
public void GetTangent(ref Vector4 value, ref Vector4 tangent, float lengthThird, out Vector4 result) public void GetTangent(ref Vector4 value, ref Vector4 tangent, float tangentScale, out Vector4 result)
{ {
result = value + tangent * lengthThird; result = value + tangent * tangentScale;
} }
public void Linear(ref Vector4 a, ref Vector4 b, float alpha, out Vector4 result) public void Linear(ref Vector4 a, ref Vector4 b, float alpha, out Vector4 result)
@@ -202,9 +202,9 @@ namespace FlaxEngine
Vector4.Lerp(ref p012, ref p123, alpha, out result); Vector4.Lerp(ref p012, ref p123, alpha, out result);
} }
public void GetTangent(ref Float2 value, ref Float2 tangent, float lengthThird, out Float2 result) public void GetTangent(ref Float2 value, ref Float2 tangent, float tangentScale, out Float2 result)
{ {
result = value + tangent * lengthThird; result = value + tangent * tangentScale;
} }
public void Linear(ref Float2 a, ref Float2 b, float alpha, out Float2 result) public void Linear(ref Float2 a, ref Float2 b, float alpha, out Float2 result)
@@ -222,9 +222,9 @@ namespace FlaxEngine
Float2.Lerp(ref p012, ref p123, alpha, out result); Float2.Lerp(ref p012, ref p123, alpha, out result);
} }
public void GetTangent(ref Float3 value, ref Float3 tangent, float lengthThird, out Float3 result) public void GetTangent(ref Float3 value, ref Float3 tangent, float tangentScale, out Float3 result)
{ {
result = value + tangent * lengthThird; result = value + tangent * tangentScale;
} }
public void Linear(ref Float3 a, ref Float3 b, float alpha, out Float3 result) public void Linear(ref Float3 a, ref Float3 b, float alpha, out Float3 result)
@@ -242,9 +242,9 @@ namespace FlaxEngine
Float3.Lerp(ref p012, ref p123, alpha, out result); Float3.Lerp(ref p012, ref p123, alpha, out result);
} }
public void GetTangent(ref Float4 value, ref Float4 tangent, float lengthThird, out Float4 result) public void GetTangent(ref Float4 value, ref Float4 tangent, float tangentScale, out Float4 result)
{ {
result = value + tangent * lengthThird; result = value + tangent * tangentScale;
} }
public void Linear(ref Float4 a, ref Float4 b, float alpha, out Float4 result) public void Linear(ref Float4 a, ref Float4 b, float alpha, out Float4 result)
@@ -262,9 +262,9 @@ namespace FlaxEngine
Float4.Lerp(ref p012, ref p123, alpha, out result); Float4.Lerp(ref p012, ref p123, alpha, out result);
} }
public void GetTangent(ref Double2 value, ref Double2 tangent, float lengthThird, out Double2 result) public void GetTangent(ref Double2 value, ref Double2 tangent, float tangentScale, out Double2 result)
{ {
result = value + tangent * lengthThird; result = value + tangent * tangentScale;
} }
public void Linear(ref Double2 a, ref Double2 b, float alpha, out Double2 result) public void Linear(ref Double2 a, ref Double2 b, float alpha, out Double2 result)
@@ -282,9 +282,9 @@ namespace FlaxEngine
Double2.Lerp(ref p012, ref p123, alpha, out result); Double2.Lerp(ref p012, ref p123, alpha, out result);
} }
public void GetTangent(ref Double3 value, ref Double3 tangent, float lengthThird, out Double3 result) public void GetTangent(ref Double3 value, ref Double3 tangent, float tangentScale, out Double3 result)
{ {
result = value + tangent * lengthThird; result = value + tangent * tangentScale;
} }
public void Linear(ref Double3 a, ref Double3 b, float alpha, out Double3 result) public void Linear(ref Double3 a, ref Double3 b, float alpha, out Double3 result)
@@ -302,9 +302,9 @@ namespace FlaxEngine
Double3.Lerp(ref p012, ref p123, alpha, out result); Double3.Lerp(ref p012, ref p123, alpha, out result);
} }
public void GetTangent(ref Double4 value, ref Double4 tangent, float lengthThird, out Double4 result) public void GetTangent(ref Double4 value, ref Double4 tangent, float tangentScale, out Double4 result)
{ {
result = value + tangent * lengthThird; result = value + tangent * tangentScale;
} }
public void Linear(ref Double4 a, ref Double4 b, float alpha, out Double4 result) public void Linear(ref Double4 a, ref Double4 b, float alpha, out Double4 result)
@@ -322,7 +322,7 @@ namespace FlaxEngine
Double4.Lerp(ref p012, ref p123, alpha, out result); Double4.Lerp(ref p012, ref p123, alpha, out result);
} }
public void GetTangent(ref Quaternion value, ref Quaternion tangent, float lengthThird, out Quaternion result) public void GetTangent(ref Quaternion value, ref Quaternion tangent, float tangentScale, out Quaternion result)
{ {
Quaternion.Slerp(ref value, ref tangent, 1.0f / 3.0f, out result); Quaternion.Slerp(ref value, ref tangent, 1.0f / 3.0f, out result);
} }
@@ -342,9 +342,9 @@ namespace FlaxEngine
Quaternion.Slerp(ref p012, ref p123, alpha, out result); Quaternion.Slerp(ref p012, ref p123, alpha, out result);
} }
public void GetTangent(ref Color32 value, ref Color32 tangent, float lengthThird, out Color32 result) public void GetTangent(ref Color32 value, ref Color32 tangent, float tangentScale, out Color32 result)
{ {
result = value + tangent * lengthThird; result = value + tangent * tangentScale;
} }
public void Linear(ref Color32 a, ref Color32 b, float alpha, out Color32 result) public void Linear(ref Color32 a, ref Color32 b, float alpha, out Color32 result)
@@ -362,9 +362,9 @@ namespace FlaxEngine
Color32.Lerp(ref p012, ref p123, alpha, out result); Color32.Lerp(ref p012, ref p123, alpha, out result);
} }
public void GetTangent(ref Color value, ref Color tangent, float lengthThird, out Color result) public void GetTangent(ref Color value, ref Color tangent, float tangentScale, out Color result)
{ {
result = value + tangent * lengthThird; result = value + tangent * tangentScale;
} }
public void Linear(ref Color a, ref Color b, float alpha, out Color result) public void Linear(ref Color a, ref Color b, float alpha, out Color result)
@@ -860,9 +860,9 @@ namespace FlaxEngine
// Evaluate the key at the curve // Evaluate the key at the curve
result.Time = leftKey.Time + length * t; result.Time = leftKey.Time + length * t;
float lengthThird = length / 3.0f; float tangentScale = length / 3.0f;
_accessor.GetTangent(ref leftKey.Value, ref leftKey.TangentOut, lengthThird, out var leftTangent); _accessor.GetTangent(ref leftKey.Value, ref leftKey.TangentOut, tangentScale, out var leftTangent);
_accessor.GetTangent(ref rightKey.Value, ref rightKey.TangentIn, lengthThird, out var rightTangent); _accessor.GetTangent(ref rightKey.Value, ref rightKey.TangentIn, tangentScale, out var rightTangent);
_accessor.Bezier(ref leftKey.Value, ref leftTangent, ref rightTangent, ref rightKey.Value, t, out result.Value); _accessor.Bezier(ref leftKey.Value, ref leftTangent, ref rightTangent, ref rightKey.Value, t, out result.Value);
result.TangentIn = leftKey.TangentOut; result.TangentIn = leftKey.TangentOut;
result.TangentOut = rightKey.TangentIn; result.TangentOut = rightKey.TangentIn;
@@ -895,9 +895,9 @@ namespace FlaxEngine
float t = Mathf.NearEqual(length, 0.0f) ? 0.0f : (time - leftKey.Time) / length; float t = Mathf.NearEqual(length, 0.0f) ? 0.0f : (time - leftKey.Time) / length;
// Evaluate the value at the curve // Evaluate the value at the curve
float lengthThird = length / 3.0f; float tangentScale = length / 3.0f;
_accessor.GetTangent(ref leftKey.Value, ref leftKey.TangentOut, lengthThird, out var leftTangent); _accessor.GetTangent(ref leftKey.Value, ref leftKey.TangentOut, tangentScale, out var leftTangent);
_accessor.GetTangent(ref rightKey.Value, ref rightKey.TangentIn, lengthThird, out var rightTangent); _accessor.GetTangent(ref rightKey.Value, ref rightKey.TangentIn, tangentScale, out var rightTangent);
_accessor.Bezier(ref leftKey.Value, ref leftTangent, ref rightTangent, ref rightKey.Value, t, out result); _accessor.Bezier(ref leftKey.Value, ref leftTangent, ref rightTangent, ref rightKey.Value, t, out result);
} }

View File

@@ -247,16 +247,18 @@ public:
static void Interpolate(const BezierCurveKeyframe& a, const BezierCurveKeyframe& b, float alpha, float length, T& result) static void Interpolate(const BezierCurveKeyframe& a, const BezierCurveKeyframe& b, float alpha, float length, T& result)
{ {
T leftTangent, rightTangent; T leftTangent, rightTangent;
AnimationUtils::GetTangent(a.Value, a.TangentOut, length, leftTangent); const float tangentScale = length / 3.0f;
AnimationUtils::GetTangent(b.Value, b.TangentIn, length, rightTangent); AnimationUtils::GetTangent(a.Value, a.TangentOut, tangentScale, leftTangent);
AnimationUtils::GetTangent(b.Value, b.TangentIn, tangentScale, rightTangent);
AnimationUtils::Bezier(a.Value, leftTangent, rightTangent, b.Value, alpha, result); AnimationUtils::Bezier(a.Value, leftTangent, rightTangent, b.Value, alpha, result);
} }
static void InterpolateFirstDerivative(const BezierCurveKeyframe& a, const BezierCurveKeyframe& b, float alpha, float length, T& result) static void InterpolateFirstDerivative(const BezierCurveKeyframe& a, const BezierCurveKeyframe& b, float alpha, float length, T& result)
{ {
T leftTangent, rightTangent; T leftTangent, rightTangent;
AnimationUtils::GetTangent(a.Value, a.TangentOut, length, leftTangent); const float tangentScale = length / 3.0f;
AnimationUtils::GetTangent(b.Value, b.TangentIn, length, rightTangent); AnimationUtils::GetTangent(a.Value, a.TangentOut, tangentScale, leftTangent);
AnimationUtils::GetTangent(b.Value, b.TangentIn, tangentScale, rightTangent);
AnimationUtils::BezierFirstDerivative(a.Value, leftTangent, rightTangent, b.Value, alpha, result); AnimationUtils::BezierFirstDerivative(a.Value, leftTangent, rightTangent, b.Value, alpha, result);
} }
@@ -264,8 +266,9 @@ public:
{ {
result.Time = a.Time + length * alpha; result.Time = a.Time + length * alpha;
T leftTangent, rightTangent; T leftTangent, rightTangent;
AnimationUtils::GetTangent(a.Value, a.TangentOut, length, leftTangent); const float tangentScale = length / 3.0f;
AnimationUtils::GetTangent(b.Value, b.TangentIn, length, rightTangent); AnimationUtils::GetTangent(a.Value, a.TangentOut, tangentScale, leftTangent);
AnimationUtils::GetTangent(b.Value, b.TangentIn, tangentScale, rightTangent);
AnimationUtils::Bezier(a.Value, leftTangent, rightTangent, b.Value, alpha, result.Value); AnimationUtils::Bezier(a.Value, leftTangent, rightTangent, b.Value, alpha, result.Value);
result.TangentIn = a.TangentOut; result.TangentIn = a.TangentOut;
result.TangentOut = b.TangentIn; result.TangentOut = b.TangentIn;

View File

@@ -158,10 +158,10 @@ float Spline::GetSplineLength() const
const auto& b = Curve[i]; const auto& b = Curve[i];
Vector3 prevPoint = a.Value.Translation * scale; Vector3 prevPoint = a.Value.Translation * scale;
const float length = Math::Abs(b.Time - a.Time); const float tangentScale = Math::Abs(b.Time - a.Time) / 3.0f;
Vector3 leftTangent, rightTangent; Vector3 leftTangent, rightTangent;
AnimationUtils::GetTangent(a.Value.Translation, a.TangentOut.Translation, length, leftTangent); AnimationUtils::GetTangent(a.Value.Translation, a.TangentOut.Translation, tangentScale, leftTangent);
AnimationUtils::GetTangent(b.Value.Translation, b.TangentIn.Translation, length, rightTangent); AnimationUtils::GetTangent(b.Value.Translation, b.TangentIn.Translation, tangentScale, rightTangent);
for (int32 slice = 1; slice < slices; slice++) for (int32 slice = 1; slice < slices; slice++)
{ {
@@ -189,10 +189,10 @@ float Spline::GetSplineSegmentLength(int32 index) const
const Vector3 scale = _transform.Scale; const Vector3 scale = _transform.Scale;
Vector3 prevPoint = a.Value.Translation * scale; Vector3 prevPoint = a.Value.Translation * scale;
{ {
const float length = Math::Abs(b.Time - a.Time); const float tangentScale = Math::Abs(b.Time - a.Time) / 3.0f;
Vector3 leftTangent, rightTangent; Vector3 leftTangent, rightTangent;
AnimationUtils::GetTangent(a.Value.Translation, a.TangentOut.Translation, length, leftTangent); AnimationUtils::GetTangent(a.Value.Translation, a.TangentOut.Translation, tangentScale, leftTangent);
AnimationUtils::GetTangent(b.Value.Translation, b.TangentIn.Translation, length, rightTangent); AnimationUtils::GetTangent(b.Value.Translation, b.TangentIn.Translation, tangentScale, rightTangent);
for (int32 slice = 1; slice < slices; slice++) for (int32 slice = 1; slice < slices; slice++)
{ {

View File

@@ -184,9 +184,9 @@ void SplineModel::OnSplineUpdated()
auto& instance = _instances[segment]; auto& instance = _instances[segment];
const auto& start = keyframes[segment]; const auto& start = keyframes[segment];
const auto& end = keyframes[segment + 1]; const auto& end = keyframes[segment + 1];
const float length = end.Time - start.Time; const float tangentScale = (end.Time - start.Time) / 3.0f;
AnimationUtils::GetTangent(start.Value, start.TangentOut, length, leftTangent); AnimationUtils::GetTangent(start.Value, start.TangentOut, tangentScale, leftTangent);
AnimationUtils::GetTangent(end.Value, end.TangentIn, length, rightTangent); AnimationUtils::GetTangent(end.Value, end.TangentIn, tangentScale, rightTangent);
// Find maximum scale over the segment spline and collect the segment positions for bounds // Find maximum scale over the segment spline and collect the segment positions for bounds
segmentPoints.Clear(); segmentPoints.Clear();
@@ -256,9 +256,9 @@ void SplineModel::UpdateDeformationBuffer()
auto& instance = _instances[segment]; auto& instance = _instances[segment];
const auto& start = keyframes[segment]; const auto& start = keyframes[segment];
const auto& end = keyframes[segment + 1]; const auto& end = keyframes[segment + 1];
const float length = end.Time - start.Time; const float tangentScale = (end.Time - start.Time) / 3.0f;
AnimationUtils::GetTangent(start.Value, start.TangentOut, length, leftTangent); AnimationUtils::GetTangent(start.Value, start.TangentOut, tangentScale, leftTangent);
AnimationUtils::GetTangent(end.Value, end.TangentIn, length, rightTangent); AnimationUtils::GetTangent(end.Value, end.TangentIn, tangentScale, rightTangent);
for (int32 chunk = 0; chunk < chunksPerSegment; chunk++) for (int32 chunk = 0; chunk < chunksPerSegment; chunk++)
{ {
const float alpha = (chunk == chunksPerSegment - 1) ? 1.0f : ((float)chunk * chunksPerSegmentInv); const float alpha = (chunk == chunksPerSegment - 1) ? 1.0f : ((float)chunk * chunksPerSegmentInv);
@@ -291,10 +291,10 @@ void SplineModel::UpdateDeformationBuffer()
{ {
const auto& start = keyframes[segments - 1]; const auto& start = keyframes[segments - 1];
const auto& end = keyframes[segments]; const auto& end = keyframes[segments];
const float length = end.Time - start.Time; const float tangentScale = (end.Time - start.Time) / 3.0f;
const float alpha = 1.0f - ZeroTolerance; // Offset to prevent zero derivative at the end of the curve const float alpha = 1.0f - ZeroTolerance; // Offset to prevent zero derivative at the end of the curve
AnimationUtils::GetTangent(start.Value, start.TangentOut, length, leftTangent); AnimationUtils::GetTangent(start.Value, start.TangentOut, tangentScale, leftTangent);
AnimationUtils::GetTangent(end.Value, end.TangentIn, length, rightTangent); AnimationUtils::GetTangent(end.Value, end.TangentIn, tangentScale, rightTangent);
AnimationUtils::Bezier(start.Value, leftTangent, rightTangent, end.Value, alpha, transform); AnimationUtils::Bezier(start.Value, leftTangent, rightTangent, end.Value, alpha, transform);
Vector3 direction; Vector3 direction;
AnimationUtils::BezierFirstDerivative(start.Value.Translation, leftTangent.Translation, rightTangent.Translation, end.Value.Translation, alpha, direction); AnimationUtils::BezierFirstDerivative(start.Value.Translation, leftTangent.Translation, rightTangent.Translation, end.Value.Translation, alpha, direction);

View File

@@ -214,9 +214,9 @@ void SplineCollider::GetGeometry(CollisionShape& collision)
auto offsetIndices = segment * collisionIndices.Count(); auto offsetIndices = segment * collisionIndices.Count();
const auto& start = keyframes[segment]; const auto& start = keyframes[segment];
const auto& end = keyframes[segment + 1]; const auto& end = keyframes[segment + 1];
const float length = end.Time - start.Time; const float tangentScale = (end.Time - start.Time) / 3.0f;
AnimationUtils::GetTangent(start.Value, start.TangentOut, length, leftTangent); AnimationUtils::GetTangent(start.Value, start.TangentOut, tangentScale, leftTangent);
AnimationUtils::GetTangent(end.Value, end.TangentIn, length, rightTangent); AnimationUtils::GetTangent(end.Value, end.TangentIn, tangentScale, rightTangent);
// Vertex buffer is deformed along the spline // Vertex buffer is deformed along the spline
auto srcVertices = collisionVertices.Get(); auto srcVertices = collisionVertices.Get();

View File

@@ -1882,19 +1882,46 @@ void Render2D::DrawBezier(const Float2& p1, const Float2& p2, const Float2& p3,
const Float2 d3 = p4 - p3; const Float2 d3 = p4 - p3;
const float len = d1.Length() + d2.Length() + d3.Length(); const float len = d1.Length() + d2.Length() + d3.Length();
const int32 segmentCount = Math::Clamp(Math::CeilToInt(len * 0.05f), 1, 100); const int32 segmentCount = Math::Clamp(Math::CeilToInt(len * 0.05f), 1, 100);
const float segmentCountInv = 1.0f / segmentCount; const float segmentCountInv = 1.0f / (float)segmentCount;
// Draw segmented curve // Draw segmented curve
Float2 p;
AnimationUtils::Bezier(p1, p2, p3, p4, 0, p);
Lines2.Clear(); Lines2.Clear();
Lines2.Add(p); Lines2.Add(p1);
for (int32 i = 1; i <= segmentCount; i++) for (int32 i = 1; i < segmentCount; i++)
{ {
const float t = i * segmentCountInv; const float t = (float)i * segmentCountInv;
Float2 p;
AnimationUtils::Bezier(p1, p2, p3, p4, t, p); AnimationUtils::Bezier(p1, p2, p3, p4, t, p);
Lines2.Add(p); Lines2.Add(p);
} }
Lines2.Add(p4);
DrawLines(Lines2.Get(), Lines2.Count(), color, color, thickness);
}
void Render2D::DrawSpline(const Float2& p1, const Float2& p2, const Float2& p3, const Float2& p4, const Color& color, float thickness)
{
RENDER2D_CHECK_RENDERING_STATE;
// Find amount of segments to use
const Float2 d1 = p2 - p1;
const Float2 d2 = p3 - p2;
const Float2 d3 = p4 - p3;
const float len = d1.Length() + d2.Length() + d3.Length();
const int32 segmentCount = Math::Clamp(Math::CeilToInt(len * 0.05f), 1, 100);
const float segmentCountInv = 1.0f / (float)segmentCount;
// Draw segmented curve
Lines2.Clear();
Lines2.Add(p1);
for (int32 i = 1; i < segmentCount; i++)
{
const float t = (float)i * segmentCountInv;
Float2 p;
p.X = Math::Lerp(p1.X, p4.X, t);
AnimationUtils::Bezier(p1.Y, p2.Y, p3.Y, p4.Y, t, p.Y);
Lines2.Add(p);
}
Lines2.Add(p4);
DrawLines(Lines2.Get(), Lines2.Count(), color, color, thickness); DrawLines(Lines2.Get(), Lines2.Count(), color, color, thickness);
} }

View File

@@ -389,6 +389,17 @@ public:
/// <param name="thickness">The line thickness.</param> /// <param name="thickness">The line thickness.</param>
API_FUNCTION() static void DrawBezier(const Float2& p1, const Float2& p2, const Float2& p3, const Float2& p4, const Color& color, float thickness = 1.0f); API_FUNCTION() static void DrawBezier(const Float2& p1, const Float2& p2, const Float2& p3, const Float2& p4, const Color& color, float thickness = 1.0f);
/// <summary>
/// Draws a spline curve (Bezier but X axis represents uniform time).
/// </summary>
/// <param name="p1">The start point.</param>
/// <param name="p2">The first control point.</param>
/// <param name="p3">The second control point.</param>
/// <param name="p4">The end point.</param>
/// <param name="color">The line color</param>
/// <param name="thickness">The line thickness.</param>
API_FUNCTION() static void DrawSpline(const Float2& p1, const Float2& p2, const Float2& p3, const Float2& p4, const Color& color, float thickness = 1.0f);
/// <summary> /// <summary>
/// Draws the GUI material. /// Draws the GUI material.
/// </summary> /// </summary>