Skip to content

Commit 8504d6a

Browse files
committed
- Added 'Quick Edit Mode" to BezierSpline: in this mode, new points can quickly be added/inserted to the spline and the existing points can be dragged around/snapped to the scene geometry
- Added BezierSpline.GeneratePointCache function to calculate evenly spaced points along the spline. Instead of calling the function with default parameters, use the 'pointCache' property instead which is cached and is updated automatically when spline is modified. If a spline is rarely modified at runtime, then point cache can be used to get points, tangents, normals, etc. along the spline in a cheaper and uniform way - Added an optional second pass to FindNearestPointTo functions for greatly increased accuracy - Added 'Invert Spline' button to BezierSpline's context menu which inverts the order of the end points - Added 'version' property to BezierSpline which is automatically increased whenever the spline's properties change - Added per-setting Reset buttons to the plugin's settings - Removed GUILayer and FlareLayer components from demo scene
1 parent d083ef6 commit 8504d6a

14 files changed

+1161
-484
lines changed

.github/README.md

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ The user interface for the spline editor should be pretty self-explanatory with
3838

3939
![inspector](Images/BezierSpline.png)
4040

41+
When **Quick Edit Mode** is enabled, new points can quickly be added/inserted to the spline and the existing points can be dragged around/snapped to the scene geometry.
42+
43+
To reverse the order of the end points in a spline, you can right click the BezierSpline component and click the *Invert Spline* button.
44+
4145
You can tweak the Scene view gizmos via *Project Settings/yasirkula/Bezier Solution* page (on older versions, this menu is located at *Preferences* window).
4246

4347
![gizmo-settings](Images/GizmoSettings.png)
@@ -112,6 +116,8 @@ If auto calculated normals don't look quite right despite modifying the "normalA
112116

113117
You can register to the spline's **onSplineChanged** event to get notified when some of its properties have changed. This event has the following signature: `delegate void SplineChangeDelegate( BezierSpline spline, DirtyFlags dirtyFlags )`. **DirtyFlags** is an enum flag, meaning that it can have one or more of these values: **SplineShapeChanged**, **NormalsChanged** and/or **ExtraDataChanged**. *SplineShapeChanged* flag means that either the spline's Transform values have changed or some of its end points' Transform values have changed (changing control points may also trigger this flag). *NormalsChanged* flag means that normals of some of the end points have changed and *ExtraDataChanged* flag means that extraDatas of some of the end points have changed.
114118

119+
BezierSpline also has a **version** property which is automatically increased whenever the spline's properties change.
120+
115121
**NOTE:** onSplineChanged event is usually invoked in *LateUpdate*. Before it is invoked, *autoConstructMode* and *autoCalculateNormals* properties' values are checked and the relevant auto construction/calculation functions are executed if necessary.
116122

117123
## UTILITY FUNCTIONS
@@ -148,11 +154,11 @@ Calculates the approximate length of a segment of the spline. To calculate the l
148154

149155
Returns the two end points that are closest to *normalizedT*. The *Segment* struct also holds a *localT* value in range \[0,1\], which can be used to interpolate between the properties of these two end points. You can also call the `GetPoint()`, `GetTangent()`, `GetNormal()` and `GetExtraData()` functions of this struct and the returned values will be calculated as if the spline consisted of only these two end points.
150156

151-
- `Vector3 FindNearestPointTo( Vector3 worldPos, out float normalizedT, float accuracy = 100f )`
157+
- `Vector3 FindNearestPointTo( Vector3 worldPos, out float normalizedT, float accuracy = 100f, int secondPassIterations = 7, float secondPassExtents = 0.025f )`
152158

153-
Finds the nearest point on the spline to any given point in 3D space. The normalizedT parameter is optional and it returns the parameter *t* corresponding to the resulting point. To find the nearest point, the spline is divided into "accuracy" points and the nearest point is selected. Thus, the result will not be 100% accurate but will be good enough for casual use-cases.
159+
Finds the nearest point on the spline to any given point in 3D space. The normalizedT parameter is optional and it returns the parameter *t* corresponding to the resulting point. To find the nearest point, the spline is divided into "accuracy" points and the nearest point is selected. Then, a binary search is performed in "secondPassIterations" steps in range `[normalizedT-secondPassExtents, normalizedT+secondPassExtents]` to fine-tune the result.
154160

155-
- `Vector3 FindNearestPointToLine( Vector3 lineStart, Vector3 lineEnd, out Vector3 pointOnLine, out float normalizedT, float accuracy = 100f )`
161+
- `Vector3 FindNearestPointToLine( Vector3 lineStart, Vector3 lineEnd, out Vector3 pointOnLine, out float normalizedT, float accuracy = 100f, int secondPassIterations = 7, float secondPassExtents = 0.025f )`
156162

157163
Finds the nearest point on the spline to the given line in 3D space. The pointOnLine and normalizedT parameters are optional.
158164

@@ -162,17 +168,23 @@ Moves a point (normalizedT) on the spline deltaMovement units ahead and returns
162168

163169
- `EvenlySpacedPointsHolder CalculateEvenlySpacedPoints( float resolution = 10f, float accuracy = 3f )`
164170

165-
Finds uniformly distributed points on the spline and returns a lookup table. The lookup table isn't refreshed automatically, so it may be invalidated when the spline is modified. This function's resolution parameter determines approximately how many points will be calculated per each segment of the spline and accuracy determines how accurate the uniform spacing will be. The default values should work well in most cases.
171+
Finds uniformly distributed points along the spline and returns a lookup table. The lookup table isn't refreshed automatically, so it may be invalidated when the spline is modified. This function's *resolution* parameter determines approximately how many points will be calculated per each segment of the spline and accuracy determines how accurate the uniform spacing will be. The default values should work well in most cases.
166172

167173
**Food For Thought**: BezierSpline has an **evenlySpacedPoints** property which is a shorthand for `CalculateEvenlySpacedPoints()`. Its value is cached and won't be recalculated unless the spline is modified.
168174

169-
**EvenlySpacedPointsHolder** struct has *spline*, *splineLength* and *uniformNormalizedTs* variables. In addition, it has the following convenience functions:
175+
*EvenlySpacedPointsHolder* class has *spline*, *splineLength* and *uniformNormalizedTs* variables. In addition, it has the following convenience functions:
176+
177+
- **GetNormalizedTAtPercentage:** converts a percentage to normalizedT value, i.e. if you enter 0.5f as parameter, it will return the normalizedT value of the spline that corresponds to its actual middle point.
178+
- **GetNormalizedTAtDistance:** finds the normalizedT value that is specified units away from the spline's starting point.
179+
- **GetPercentageAtNormalizedT:** inverse of *GetNormalizedTAtPercentage*.
180+
181+
- `PointCache GeneratePointCache( EvenlySpacedPointsHolder lookupTable, ExtraDataLerpFunction extraDataLerpFunction, PointCacheFlags cachedData = PointCacheFlags.All, int resolution = 100 )`
170182

171-
**GetNormalizedTAtPercentage:** converts a percentage to normalizedT value, i.e. if you enter 0.5f as parameter, it will return the normalizedT value of the spline that corresponds to its actual middle point.
183+
Returns a cache of data for uniformly distributed points along the spline. The cache isn't refreshed automatically, so it may be invalidated when the spline is modified. This function's *resolution* parameter determines how many uniformly distributed points the cache will have. To determine which data should be cached, *cachedData* parameter is used. *PointCacheFlags* is an enum flag, meaning that it can have one or more of these values: **Positions**, **Normals**, **Tangents**, **Bitangents** and/or **ExtraDatas**. *lookupTable* is an optional parameter and, by default, spline's *evenlySpacedPoints* is used. *extraDataLerpFunction* is also an optional parameter and is used only when PointCacheFlags.ExtraDatas is included in cachedData.
172184

173-
**GetNormalizedTAtDistance:** finds the normalizedT value that is specified units away from the spline's starting point.
185+
**Food For Thought**: BezierSpline has a **pointCache** property which is a shorthand for `GeneratePointCache()`. Its value is cached and won't be recalculated unless the spline is modified.
174186

175-
**GetPercentageAtNormalizedT:** inverse of *GetNormalizedTAtPercentage*.
187+
*PointCache* class has *positions*, *normals*, *tangents*, *bitangents*, *extraDatas* and *loop* variables (loop determines whether or not the spline had its *loop* property set to true while calculating the cache). In addition, it has the following functions: *GetPoint*, *GetNormal*, *GetTangent*, *GetBitangent* and *GetExtraData* (if the required data for a function wasn't included in PointCacheFlags, then the function will throw an exception). If a spline is rarely modified at runtime, then point cache can be used to get points, tangents, normals, etc. along the spline in a cheaper and uniform way.
176188

177189
## OTHER COMPONENTS
178190

Plugins/BezierSolution/BezierPoint.cs

Lines changed: 10 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -3,72 +3,8 @@
33
namespace BezierSolution
44
{
55
[AddComponentMenu( "Bezier Solution/Bezier Point" )]
6-
public class BezierPoint : MonoBehaviour
6+
public partial class BezierPoint : MonoBehaviour
77
{
8-
[System.Serializable]
9-
public struct ExtraData
10-
{
11-
public float c1, c2, c3, c4;
12-
13-
public ExtraData( float c1 = 0f, float c2 = 0f, float c3 = 0f, float c4 = 0f )
14-
{
15-
this.c1 = c1;
16-
this.c2 = c2;
17-
this.c3 = c3;
18-
this.c4 = c4;
19-
}
20-
21-
public static ExtraData Lerp( ExtraData a, ExtraData b, float t )
22-
{
23-
t = Mathf.Clamp01( t );
24-
return new ExtraData(
25-
a.c1 + ( b.c1 - a.c1 ) * t,
26-
a.c2 + ( b.c2 - a.c2 ) * t,
27-
a.c3 + ( b.c3 - a.c3 ) * t,
28-
a.c4 + ( b.c4 - a.c4 ) * t );
29-
}
30-
31-
public static ExtraData LerpUnclamped( ExtraData a, ExtraData b, float t )
32-
{
33-
return new ExtraData(
34-
a.c1 + ( b.c1 - a.c1 ) * t,
35-
a.c2 + ( b.c2 - a.c2 ) * t,
36-
a.c3 + ( b.c3 - a.c3 ) * t,
37-
a.c4 + ( b.c4 - a.c4 ) * t );
38-
}
39-
40-
public static implicit operator ExtraData( Vector2 v ) { return new ExtraData( v.x, v.y ); }
41-
public static implicit operator ExtraData( Vector3 v ) { return new ExtraData( v.x, v.y, v.z ); }
42-
public static implicit operator ExtraData( Vector4 v ) { return new ExtraData( v.x, v.y, v.z, v.w ); }
43-
public static implicit operator ExtraData( Quaternion q ) { return new ExtraData( q.x, q.y, q.z, q.w ); }
44-
public static implicit operator ExtraData( Rect r ) { return new ExtraData( r.xMin, r.yMin, r.width, r.height ); }
45-
#if UNITY_2017_2_OR_NEWER
46-
public static implicit operator ExtraData( Vector2Int v ) { return new ExtraData( v.x, v.y ); }
47-
public static implicit operator ExtraData( Vector3Int v ) { return new ExtraData( v.x, v.y, v.z ); }
48-
public static implicit operator ExtraData( RectInt r ) { return new ExtraData( r.xMin, r.yMin, r.width, r.height ); }
49-
#endif
50-
51-
public static implicit operator Vector2( ExtraData v ) { return new Vector2( v.c1, v.c2 ); }
52-
public static implicit operator Vector3( ExtraData v ) { return new Vector3( v.c1, v.c2, v.c3 ); }
53-
public static implicit operator Vector4( ExtraData v ) { return new Vector4( v.c1, v.c2, v.c3, v.c4 ); }
54-
public static implicit operator Quaternion( ExtraData v ) { return new Quaternion( v.c1, v.c2, v.c3, v.c4 ); }
55-
public static implicit operator Rect( ExtraData v ) { return new Rect( v.c1, v.c2, v.c3, v.c4 ); }
56-
#if UNITY_2017_2_OR_NEWER
57-
public static implicit operator Vector2Int( ExtraData v ) { return new Vector2Int( Mathf.RoundToInt( v.c1 ), Mathf.RoundToInt( v.c2 ) ); }
58-
public static implicit operator Vector3Int( ExtraData v ) { return new Vector3Int( Mathf.RoundToInt( v.c1 ), Mathf.RoundToInt( v.c2 ), Mathf.RoundToInt( v.c3 ) ); }
59-
public static implicit operator RectInt( ExtraData v ) { return new RectInt( Mathf.RoundToInt( v.c1 ), Mathf.RoundToInt( v.c2 ), Mathf.RoundToInt( v.c3 ), Mathf.RoundToInt( v.c4 ) ); }
60-
#endif
61-
62-
public static bool operator ==( ExtraData d1, ExtraData d2 ) { return d1.c1 == d2.c1 && d1.c2 == d2.c2 && d1.c3 == d2.c3 && d1.c4 == d2.c4; }
63-
public static bool operator !=( ExtraData d1, ExtraData d2 ) { return d1.c1 != d2.c1 || d1.c2 != d2.c2 || d1.c3 != d2.c3 || d1.c4 != d2.c4; }
64-
65-
public override bool Equals( object obj ) { return obj is ExtraData && this == (ExtraData) obj; }
66-
public override int GetHashCode() { return unchecked((int) ( ( ( ( 17 * 23 + c1 ) * 23 + c2 ) * 23 + c3 ) * 23 + c4 )); }
67-
public override string ToString() { return ( (Vector4) this ).ToString(); }
68-
}
69-
70-
public enum HandleMode { Free, Aligned, Mirrored };
71-
728
public Vector3 localPosition
739
{
7410
get { return transform.localPosition; }
@@ -435,5 +371,14 @@ public void Reset()
435371

436372
transform.hasChanged = true;
437373
}
374+
375+
#if UNITY_EDITOR
376+
[ContextMenu( "Invert Spline" )]
377+
private void InvertSplineContextMenu()
378+
{
379+
if( spline )
380+
spline.InvertSpline( "Invert spline" );
381+
}
382+
#endif
438383
}
439384
}

0 commit comments

Comments
 (0)