UnityBezierSolution
A bezier spline solution for Unity 3D with some utility functions (like travelling the spline with constant speed/time)
Install / Use
/learn @yasirkula/UnityBezierSolutionREADME
Unity Bezier Solution

Available on Asset Store: https://assetstore.unity.com/packages/tools/level-design/bezier-solution-113074
Forum Thread: https://forum.unity.com/threads/bezier-solution-open-source.440742/
Discord: https://discord.gg/UJJt549AaV
Video: https://www.youtube.com/watch?v=OpniwcFwSY8
ABOUT
This asset is a means to create bezier splines in editor and/or during runtime: splines can be created and edited visually in the editor, or by code during runtime. It is built upon Catlike Coding's spline tutorial: https://catlikecoding.com/unity/tutorials/curves-and-splines/
INSTALLATION
There are 5 ways to install this plugin:
- import BezierSolution.unitypackage via Assets-Import Package
- clone/download this repository and move the Plugins folder to your Unity project's Assets folder
- import it from Asset Store
- (via Package Manager) click the + button and install the package from the following git URL:
https://github.com/yasirkula/UnityBezierSolution.git
- (via OpenUPM) after installing openupm-cli, run the following command:
openupm add com.yasirkula.beziersolution
CREATING & EDITING A NEW SPLINE IN EDITOR
To create a new spline in the editor, click GameObject - Bezier Spline.
Now you can select the end points of the spline in the Scene view and translate/rotate/scale or delete/duplicate them as you wish (each end point has 2 control points, which can also be translated):

The user interface for the spline editor should be pretty self-explanatory with most variables having explanatory tooltips.

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.
To reverse the order of the end points in a spline, you can right click the BezierSpline component and click the Invert Spline button.
You can tweak the Scene view gizmos via Project Settings/yasirkula/Bezier Solution page (on older versions, this menu is located at Preferences window).

CREATING & EDITING A NEW SPLINE BY CODE
- Create a new bezier spline
Simply create a new GameObject, attach a BezierSpline component to it (BezierSpline uses BezierSolution namespace) and initialize the spline with a minimum of two end points:
BezierSpline spline = new GameObject().AddComponent<BezierSpline>();
spline.Initialize( 2 );
- Populate the spline
BezierPoint InsertNewPointAt( int index ): adds a new end point to the spline and returns it
BezierPoint DuplicatePointAt( int index ): duplicates an existing end point and returns it
void RemovePointAt( int index ): removes an end point from the spline
void SwapPointsAt( int index1, int index2 ): swaps indices of two end points
void ChangePointIndex( int previousIndex, int newIndex ): changes an end point's index
- Shape the spline
You can change the position, rotation, scale and normal values of the end points, as well as the positions of their control points to reshape the spline.
End points have the following properties to store their transformational data: position, localPosition, rotation, localRotation, eulerAngles, localEulerAngles, localScale, normal, autoCalculatedNormalAngleOffset and intermediateNormals.
Positions of control points can be tweaked using the following properties in BezierPoint: precedingControlPointPosition, precedingControlPointLocalPosition, followingControlPointPosition and followingControlPointLocalPosition. The local positions are relative to their corresponding end points.
End points also have read-only spline, index, previousPoint and nextPoint properties.
// Set first end point's (world) position to 2,3,5
spline[0].position = new Vector3( 2, 3, 5 );
// Set second end point's local position to 7,11,13
spline[1].localPosition = new Vector3( 7, 11, 13 );
// Set handle mode of first end point to Free to independently adjust each control point
spline[0].handleMode = BezierPoint.HandleMode.Free;
// Reposition the control points of the first end point
spline[0].precedingControlPointLocalPosition = new Vector3( 0, 0, 1 );
spline[0].followingControlPointPosition = spline[1].position;
- Auto construct the spline
If you don't want to position all the control points manually, but rather generate a nice-looking "continuous" spline that goes through the end points you have created, you can call either AutoConstructSpline() or AutoConstructSpline2(). These methods are implementations of some algorithms found on the internet (and credited in the source code). If you want these functions to be called automatically when spline's end points are modified, simply change the spline's autoConstructMode property.

- Convert spline to a linear path
If you want to create a linear path between the end points of the spline, you can call the ConstructLinearPath() function. Or, if you want this function to be called automatically when spline's end points are modified, simply set the spline's autoConstructMode property to SplineAutoConstructMode.Linear.

- Auto calculate the normals
If you want to calculate the spline's normal vectors automatically, you can call the AutoCalculateNormals( float normalAngle = 0f, int smoothness = 10, bool calculateIntermediateNormals = false ) function (or, to call this function automatically when spline's end points are modified, simply change the spline's autoCalculateNormals, autoCalculatedNormalsAngle and m_autoCalculatedIntermediateNormalsCount properties). All resulting normal vectors will be rotated around their Z axis by "normalAngle" degrees. Additionally, each end point's normal vector will be rotated by that end point's "autoCalculatedNormalAngleOffset" degrees. "smoothness" determines how many intermediate steps are taken between each consecutive end point to calculate those end points' normal vectors. More intermediate steps is better but also slower to calculate. When "calculateIntermediateNormals" is enabled, calculated intermediate normals (determined by "smoothness") are cached at each end point. This results in smoother linear interpolation for normals. Otherwise, the intermediate normals aren't stored anywhere and only the end points' normals are used to estimate normals along the spline.
If auto calculated normals don't look quite right despite modifying the "calculateIntermediateNormals" (Auto Calculated Intermediate Normals in the Inspector), "normalAngle" (Auto Calculated Normals Angle in the Inspector) and "autoCalculatedNormalAngleOffset" (Normal Angle in the Inspector) variables, you can either consider inserting new end points to the sections of the spline that normals don't behave correctly, or setting the normals manually.
- Get notified when spline is modified
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.
BezierSpline also has a version property which is automatically increased whenever the spline's properties change.
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.
UTILITY FUNCTIONS
The framework comes with some utility functions. These functions are not necessarily perfect but most of the time, they get the job done. Though, if you want, you can use this framework to just create splines and then apply your own logic to them.
Vector3 GetPoint( float normalizedT )
A spline is essentially a mathematical formula with a [0,1] clamped input (usually called t), which generates a point on the spline. As the name suggests, this function returns a point on the spline. As t goes from 0 to 1, the point moves from the first end point to the last end point (or goes back to first end point, if spline is looping).
Vector3 GetTangent( float normalizedT )
Tangent is calculated using the first derivative of the spline formula and gives the direction of the movement at a given point on the spline. Can be used to determine which direction an object on the spline should look at at a given point.
Vector3 GetNormal( float normalizedT )
Interpolates between the end points' normal vectors. If intermediate normals are calculated, they are interpolated to calculate the result. Otherwise, only the end points' normal vectors are interpolated and the resulting normal vectors may not be correct at some parts of the spline. Inserting new end point(s) to those sections of the spline could resolve t
