Skip to content

Commit fea9edb

Browse files
author
Unity Technologies
committed
com.unity.splines@2.4.0
## [2.4.0] - 2023-07-26 ### Added - Exposed public APIs for `SplineUtility.ReverseFlow`, `SplineUtility.JoinSplinesOnKnots`, and `SplineUtility.SplitSplineOnKnot`. ### Changed - For Editor versions of 2023.2 or newer, added clipboard operations for Splines to the Scene view context menu. - Changed `Splines/Cycle Active Spline` shortcut to Shift-S to remove a conflict with Unity default shortcuts. - [SPLB-163] Improved performance of spline handles by caching spline data. - [SPLB-167] Changed the evaluation of up vectors to use a cache instead of re-evaluate the values on every single request. - In Editor versions of 2023.2 or newer, moved the following actions from the Element Inspector to the Scene view context menu: Link, Unlink, Split, Join, and Reverse Spline Flow. ### Bug Fixes - [SPLB-176] Fixed a regression where the up vector would not evaluate correctly for some curves. - Fixed the setter for SplineAnimate.Normalized time to handle ping-pong direction correctly when set. - Fixed a bug where setting the time value to 0 after reaching the end of the spline animation was not resetting the object position. - [SPLB-169] Fixed a bug where `CurveUtility.GetNearestPoint` would return incorrect values for the interpolation.
1 parent a014116 commit fea9edb

26 files changed

+1245
-534
lines changed

CHANGELOG.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,30 @@ All notable changes to this package will be documented in this file.
55
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
66
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
77

8+
## [Unreleased]
9+
10+
11+
## [2.4.0] - 2023-07-26
12+
13+
### Added
14+
15+
- Exposed public APIs for `SplineUtility.ReverseFlow`, `SplineUtility.JoinSplinesOnKnots`, and `SplineUtility.SplitSplineOnKnot`.
16+
17+
### Changed
18+
19+
- For Editor versions of 2023.2 or newer, added clipboard operations for Splines to the Scene view context menu.
20+
- Changed `Splines/Cycle Active Spline` shortcut to Shift-S to remove a conflict with Unity default shortcuts.
21+
- [SPLB-163] Improved performance of spline handles by caching spline data.
22+
- [SPLB-167] Changed the evaluation of up vectors to use a cache instead of re-evaluate the values on every single request.
23+
- In Editor versions of 2023.2 or newer, moved the following actions from the Element Inspector to the Scene view context menu: Link, Unlink, Split, Join, and Reverse Spline Flow.
24+
25+
### Bug Fixes
26+
27+
- [SPLB-176] Fixed a regression where the up vector would not evaluate correctly for some curves.
28+
- Fixed the setter for SplineAnimate.Normalized time to handle ping-pong direction correctly when set.
29+
- Fixed a bug where setting the time value to 0 after reaching the end of the spline animation was not resetting the object position.
30+
- [SPLB-169] Fixed a bug where `CurveUtility.GetNearestPoint` would return incorrect values for the interpolation.
31+
832
## [2.3.0] - 2023-05-31
933

1034
### Added

Editor/Controls/CurveHandles.cs

Lines changed: 19 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,10 @@ namespace UnityEditor.Splines
77
{
88
static class CurveHandles
99
{
10-
const int k_CurveDrawResolution = 72;
1110
const float k_CurveLineWidth = 4f;
1211
const float k_PreviewCurveOpacity = 0.5f;
1312

14-
static readonly Vector3[] s_CurveDrawingBuffer = new Vector3[k_CurveDrawResolution + 1];
13+
static readonly Vector3[] s_CurveDrawingBuffer = new Vector3[SplineCacheUtility.CurveDrawResolution + 1];
1514
static readonly Vector3[] s_FlowTriangleVertices = new Vector3[3];
1615

1716
/// <summary>
@@ -48,9 +47,9 @@ internal static void Draw(BezierCurve curve, bool activeSpline)
4847
/// <param name="activeSpline">Whether the curve is part of the active spline.</param>
4948
internal static void DrawWithHighlight(
5049
int controlID,
51-
BezierCurve curve,
5250
ISpline spline,
5351
int curveIndex,
52+
float4x4 localToWorld,
5453
SelectableKnot knotA,
5554
SelectableKnot knotB,
5655
bool activeSpline)
@@ -62,13 +61,14 @@ internal static void DrawWithHighlight(
6261
case EventType.MouseMove:
6362
if (!SplineHandles.ViewToolActive() && activeSpline)
6463
{
64+
var curve = spline.GetCurve(curveIndex).Transform(localToWorld);
6565
var dist = DistanceToCurve(curve);
6666
HandleUtility.AddControl(controlID, Mathf.Max(0, dist - SplineHandleUtility.pickingDistance));
6767
//Trigger repaint on MouseMove to update highlight visuals from SplineHandles
6868
if (evt.type == EventType.MouseMove || controlID == HandleUtility.nearestControl)
6969
{
7070
SplineHandleUtility.GetNearestPointOnCurve(curve, out _, out var t);
71-
var curveMidT = GetCurveMiddleInterpolation(curve, spline, curveIndex);
71+
var curveMidT = EditorSplineUtility.GetCurveMiddleInterpolation(curve, spline, curveIndex);
7272
var hoveredKnot = t <= curveMidT ? knotA : knotB;
7373

7474
if (!(SplineHandleUtility.lastHoveredElement is SelectableKnot knot) || !knot.Equals(hoveredKnot))
@@ -81,6 +81,7 @@ internal static void DrawWithHighlight(
8181
break;
8282

8383
case EventType.MouseDown:
84+
var curveMD = spline.GetCurve(curveIndex).Transform(localToWorld);
8485
if (!SplineHandles.ViewToolActive() && HandleUtility.nearestControl == controlID)
8586
{
8687
//Clicking a knot selects it
@@ -90,7 +91,7 @@ internal static void DrawWithHighlight(
9091
GUIUtility.hotControl = controlID;
9192
evt.Use();
9293

93-
SplineHandleUtility.GetNearestPointOnCurve(curve, out _, out var t);
94+
SplineHandleUtility.GetNearestPointOnCurve(curveMD, out _, out var t);
9495
SplineSelectionUtility.HandleSelection(t <= .5f ? knotA : knotB, false);
9596
}
9697
break;
@@ -105,96 +106,35 @@ internal static void DrawWithHighlight(
105106
}
106107
}
107108

108-
/// <summary>
109-
/// Draws curve and flow for a BezierCurve without the highlight.
110-
/// </summary>
111-
/// <param name="controlID">The controlID of the curve to create highlights for.</param>
112-
/// <param name="curve">The <see cref="BezierCurve"/> to create highlights for.</param>
113-
/// <param name="spline">The <see cref="ISpline"/> (if any) that the curve belongs to.</param>
114-
/// <param name="curveIndex">The curve's index if it belongs to a spline - otherwise -1.</param>
115-
/// <param name="knotA">The knot at the start of the curve.</param>
116-
/// <param name="knotB">The knot at the end of the curve.</param>
117-
/// <param name="activeSpline">Whether the curve is part of the active spline.</param>
118-
internal static void DrawWithoutHighlight(
119-
int controlID,
120-
BezierCurve curve,
121-
ISpline spline,
122-
int curveIndex,
123-
SelectableKnot knotA,
124-
SelectableKnot knotB,
125-
bool activeSpline)
126-
{
127-
var evt = Event.current;
128-
switch (evt.GetTypeForControl(controlID))
129-
{
130-
case EventType.Repaint:
131-
Draw(controlID, curve, false, activeSpline);
132-
if (SplineHandleSettings.FlowDirectionEnabled && activeSpline)
133-
DrawFlow(curve, spline, curveIndex, math.rotate(knotA.Rotation, math.up()), math.rotate(knotB.Rotation, math.up()));
134-
break;
135-
}
136-
}
137-
138109
/// <summary>
139110
/// Draws flow on a BezierCurve to indicate the direction.
140111
/// </summary>
141112
/// <param name="curve">The <see cref="BezierCurve"/> to create highlights for.</param>
142113
/// <param name="spline">The <see cref="ISpline"/> (if any) that the curve belongs to.</param>
143114
/// <param name="curveIndex">The curve's index if it belongs to a spline - otherwise -1.</param>
144-
/// <param name="upAtStart">The up vector at the start of the curve.</param>
145-
/// <param name="upAtEnd">The up vector at the end of the curve.</param>
146-
internal static void DrawFlow(BezierCurve curve, ISpline spline, int curveIndex, Vector3 upAtStart, Vector3 upAtEnd)
115+
internal static void DrawFlow(BezierCurve curve, ISpline spline, int curveIndex)
147116
{
148117
if(Event.current.type != EventType.Repaint)
149118
return;
150119

151-
var curveMidT = GetCurveMiddleInterpolation(curve, spline, curveIndex);
152-
var arrow = GetFlowArrowData(curve, curveMidT, upAtStart, upAtEnd);
153-
s_FlowTriangleVertices[0] = arrow.pointA;
154-
s_FlowTriangleVertices[1] = arrow.pointB;
155-
s_FlowTriangleVertices[2] = arrow.pointC;
120+
var arrow = SplineCacheUtility.GetCurveArrow(spline, curveIndex, curve);
121+
s_FlowTriangleVertices[0] = arrow.positions[0];
122+
s_FlowTriangleVertices[1] = arrow.positions[1];
123+
s_FlowTriangleVertices[2] = arrow.positions[2];
156124

157-
using (new Handles.DrawingScope(SplineHandleUtility.lineColor, arrow.transform))
125+
using (new Handles.DrawingScope(SplineHandleUtility.lineColor, arrow.trs))
158126
{
159127
using (new ZTestScope(CompareFunction.Less))
160128
Handles.DrawAAConvexPolygon(s_FlowTriangleVertices);
161129
}
162130

163-
using (new Handles.DrawingScope(SplineHandleUtility.lineBehindColor, arrow.transform))
131+
using (new Handles.DrawingScope(SplineHandleUtility.lineBehindColor, arrow.trs))
164132
{
165133
using (new ZTestScope(CompareFunction.Greater))
166134
Handles.DrawAAConvexPolygon(s_FlowTriangleVertices);
167135
}
168136
}
169137

170-
public static (Vector3 pointA, Vector3 pointB, Vector3 pointC, Matrix4x4 transform) GetFlowArrowData(BezierCurve curve, float t, Vector3 upAtStart, Vector3 upAtEnd, float sizeMultiplier = 1f)
171-
{
172-
var position = (Vector3)CurveUtility.EvaluatePosition(curve, t);
173-
var tangent = ((Vector3)CurveUtility.EvaluateTangent(curve, t)).normalized;
174-
var up = CurveUtility.EvaluateUpVector(curve, t, upAtStart, upAtEnd);
175-
var rotation = Quaternion.LookRotation(tangent, up);
176-
177-
var arrowMaxSpline = .05f * CurveUtility.ApproximateLength(curve);
178-
var size = HandleUtility.GetHandleSize(position) * .5f * sizeMultiplier;
179-
180-
tangent = new Vector3(0, 0, .1f) * size;
181-
var right = new Vector3(0.075f, 0, 0) * size;
182-
var magnitude = tangent.magnitude;
183-
184-
if(magnitude > arrowMaxSpline)
185-
{
186-
var ratio = arrowMaxSpline / magnitude;
187-
tangent *= ratio;
188-
right *= ratio;
189-
}
190-
191-
var a = tangent;
192-
var b = -tangent + right;
193-
var c = -tangent - right;
194-
195-
return (pointA: a, pointB: b, pointC: c, transform: Matrix4x4.TRS(position, rotation, Vector3.one));
196-
}
197-
198138
static void Draw(int controlID, BezierCurve curve, bool preview, bool activeSpline)
199139
{
200140
var evt = Event.current;
@@ -237,11 +177,7 @@ static void Draw(int controlID, BezierCurve curve, bool preview, bool activeSpli
237177

238178
static void FillCurveDrawingBuffer(BezierCurve curve)
239179
{
240-
const float segmentPercentage = 1f / k_CurveDrawResolution;
241-
for (int i = 0; i <= k_CurveDrawResolution; ++i)
242-
{
243-
s_CurveDrawingBuffer[i] = CurveUtility.EvaluatePosition(curve, i * segmentPercentage);
244-
}
180+
SplineCacheUtility.GetCurvePositions(curve, s_CurveDrawingBuffer);
245181
}
246182

247183
internal static float DistanceToCurve(BezierCurve curve)
@@ -263,25 +199,6 @@ static float DistanceToCurve()
263199
return dist;
264200
}
265201

266-
/// <summary>
267-
/// Returns the interpolation value that corresponds to the middle (distance wise) of the curve.
268-
/// If spline and curveIndex are provided, the function leverages the spline's LUTs, otherwise the LUT is built on the fly.
269-
/// </summary>
270-
/// <param name="curve">The curve to evaluate.</param>
271-
/// <param name="spline">The ISpline that curve belongs to. Not used if curve is not part of any spline.</param>
272-
/// <param name="curveIndex">The index of the curve if it's part of the spine.</param>
273-
/// <typeparam name="T">A type implementing ISpline.</typeparam>
274-
internal static float GetCurveMiddleInterpolation<T>(BezierCurve curve, T spline, int curveIndex) where T: ISpline
275-
{
276-
var curveMidT = 0f;
277-
if (curveIndex >= 0)
278-
curveMidT = spline.GetCurveInterpolation(curveIndex, spline.GetCurveLength(curveIndex) * 0.5f);
279-
else
280-
curveMidT = CurveUtility.GetDistanceToInterpolation(curve, CurveUtility.ApproximateLength(curve) * 0.5f);
281-
282-
return curveMidT;
283-
}
284-
285202
internal static void DoCurveHighlightCap(SelectableKnot knot)
286203
{
287204
if(Event.current.type != EventType.Repaint)
@@ -295,14 +212,14 @@ internal static void DoCurveHighlightCap(SelectableKnot knot)
295212
if(knot.KnotIndex > 0 || spline.Closed)
296213
{
297214
var curve = spline.GetCurve(spline.PreviousIndex(knot.KnotIndex)).Transform(localToWorld);
298-
var curveMiddleT = GetCurveMiddleInterpolation(curve, spline, spline.PreviousIndex(knot.KnotIndex));
215+
var curveMiddleT = EditorSplineUtility.GetCurveMiddleInterpolation(curve, spline, spline.PreviousIndex(knot.KnotIndex));
299216
DrawCurveHighlight(curve, 1f, curveMiddleT);
300217
}
301218

302219
if(knot.KnotIndex < spline.Count - 1 || spline.Closed)
303220
{
304221
var curve = spline.GetCurve(knot.KnotIndex).Transform(localToWorld);
305-
var curveMiddleT = GetCurveMiddleInterpolation(curve, spline, knot.KnotIndex);
222+
var curveMiddleT = EditorSplineUtility.GetCurveMiddleInterpolation(curve, spline, knot.KnotIndex);
306223
DrawCurveHighlight(curve, 0f, curveMiddleT);
307224
}
308225
}
@@ -327,11 +244,11 @@ static void DrawCurveHighlight(BezierCurve curve, float startT, float endT)
327244

328245
static void DrawAAPolyLineForCurveHighlight(Color color, float startT, float endT, float colorAlpha, bool growing)
329246
{
330-
for (int i = 1; i <= k_CurveDrawResolution; ++i)
247+
for (int i = 1; i <= SplineCacheUtility.CurveDrawResolution; ++i)
331248
{
332249
Handles.DrawAAPolyLine(SplineHandleUtility.denseLineAATex, k_CurveLineWidth, new[] { s_CurveDrawingBuffer[i - 1], s_CurveDrawingBuffer[i] });
333250

334-
var current = ((float)i / (float)k_CurveDrawResolution);
251+
var current = ((float)i / (float)SplineCacheUtility.CurveDrawResolution);
335252
if (growing)
336253
{
337254
if (current > endT)
@@ -355,7 +272,6 @@ static void DrawAAPolyLineForCurveHighlight(Color color, float startT, float end
355272
/// Creates the set of control points that make up a curve.
356273
/// </summary>
357274
/// <param name="curve">The <see cref="BezierCurve"/> to create control points for.</param>
358-
359275
public static void DrawControlNet(BezierCurve curve)
360276
{
361277
Handles.color = Color.green;
@@ -373,4 +289,4 @@ public static void DrawControlNet(BezierCurve curve)
373289
Handles.DrawDottedLine(curve.P2, curve.P3, 2f);
374290
}
375291
}
376-
}
292+
}

Editor/Controls/KnotHandles.cs

Lines changed: 11 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -26,22 +26,12 @@ internal static void Do(int controlId, SelectableKnot knot, bool selected = fals
2626
//Hovered might not be available if a TRS tool is in use
2727
hovered &= SplineHandleUtility.IsHoverAvailableForSplineElement();
2828

29-
#if UNITY_2022_2_OR_NEWER
30-
var knotColor = Handles.elementColor;
31-
var rotationDiscColor = Handles.elementPreselectionColor;
29+
var knotColor = SplineHandleUtility.elementColor;
30+
var rotationDiscColor = SplineHandleUtility.elementPreselectionColor;
3231
if (hovered)
33-
knotColor = Handles.elementPreselectionColor;
32+
knotColor = SplineHandleUtility.elementPreselectionColor;
3433
else if (selected)
35-
knotColor = Handles.elementSelectionColor;
36-
#else
37-
var knotColor = SplineHandleUtility.knotColor;
38-
var highlightColor = SplineHandleUtility.knotColor;
39-
var rotationDiscColor = Handles.preselectionColor;
40-
if (hovered)
41-
knotColor = Handles.preselectionColor;
42-
else if (selected)
43-
knotColor = Handles.selectedColor;
44-
#endif
34+
knotColor = SplineHandleUtility.elementSelectionColor;
4535

4636
Draw(knot.Position, knot.Rotation, knotColor, selected, hovered, rotationDiscColor, k_KnotRotDiscWidthHover);
4737
DrawKnotIndices(knot);
@@ -127,35 +117,19 @@ internal static void Draw(int controlId, SelectableKnot knot)
127117
//Hovered might not be available if a TRS tool is in use
128118
hovered &= SplineHandleUtility.IsHoverAvailableForSplineElement();
129119

130-
#if UNITY_2022_2_OR_NEWER
131-
var knotColor = Handles.elementColor;
132-
var highlightColor = Handles.elementPreselectionColor;
133-
var rotationDiscColor = Handles.elementPreselectionColor;
134-
if (hovered)
135-
{
136-
knotColor = Handles.elementPreselectionColor;
137-
highlightColor = Handles.elementPreselectionColor;
138-
}
139-
else if (selected)
140-
{
141-
knotColor = Handles.elementSelectionColor;
142-
highlightColor = Handles.elementSelectionColor;
143-
}
144-
#else
145-
var knotColor = SplineHandleUtility.knotColor;
146-
var highlightColor = SplineHandleUtility.knotColor;
147-
var rotationDiscColor = Handles.preselectionColor;
120+
var knotColor = SplineHandleUtility.elementColor;
121+
var highlightColor = SplineHandleUtility.elementPreselectionColor;
122+
var rotationDiscColor = SplineHandleUtility.elementPreselectionColor;
148123
if (hovered)
149124
{
150-
knotColor = Handles.preselectionColor;
151-
highlightColor = Handles.preselectionColor;
125+
knotColor = SplineHandleUtility.elementPreselectionColor;
126+
highlightColor = SplineHandleUtility.elementPreselectionColor;
152127
}
153128
else if (selected)
154129
{
155-
knotColor = Handles.selectedColor;
156-
highlightColor = Handles.selectedColor;
130+
knotColor = SplineHandleUtility.elementSelectionColor;
131+
highlightColor = SplineHandleUtility.elementSelectionColor;
157132
}
158-
#endif
159133

160134
if (SplineHandleUtility.canDrawOnCurves && (hovered || selected))
161135
{

Editor/Controls/SplineElementRectSelector.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -225,4 +225,4 @@ static Rect GetRectFromPoints(Vector2 a, Vector2 b)
225225
return new Rect(min, max - min);
226226
}
227227
}
228-
}
228+
}

0 commit comments

Comments
 (0)