//### Bezier Logic //This is an utilety class for all major calculations related to vectorized bezier curve. // //License information: [ASSET STORE TERMS OF SERVICE AND EULA](https://unity3d.com/legal/as_terms) // //Developed by [MathArtCode](https://www.assetstore.unity3d.com/en/#!/search/page=1/sortby=popularity/query=publisher:8738) team, 2015 using System; using System.Linq; using Assets.Scripts.BezierCurvedParticlesFlow.Interfaces; using UnityEngine; namespace Assets.Scripts.BezierCurvedParticlesFlow.Utilities { [Serializable] public sealed class BezierLogic : IBezierLogic { [SerializeField] private Vector3[] _points; //All points are handeled inside a single array //- positioning (end points) have indexes 0, 3, 6, ... //- angles (control points) have indexes 1,2, 4,5, ... private Vector3[] Points { get { if (_points == null) { Reset(); } return _points; } } // Provides ammount of all points (end points + control pouints in AI terminolagy) public int ControlPointCount { get { return Points.Length; } } // Provides ammount of all curved segments of Bezier curve private int CurveCount { get { return (Points.Length - 1)/3; } } // Returns a coordinate point relative to curve 'time' where 0 is bezier curve beginning and 1 is end of the bezier curve (length vise) public Vector3 GetPoint(float t) { int i; if (t >= 1f) { t = 1f; i = _points.Length - 4; } else { t = Mathf.Clamp01(t)*CurveCount; i = (int) t; t -= i; i *= 3; } return GetPoint(_points[i], _points[i + 1], _points[i + 2], _points[i + 3], t); } // Returns a velocity point relative to curve 'time' where 0 is bezier curve beginning and 1 is end of the bezier curve (length vise) public Vector3 GetVelocity(float t) { int i; if (t >= 1f) { t = 1f; i = _points.Length - 4; } else { t = Mathf.Clamp01(t)*CurveCount; i = (int) t; t -= i; i *= 3; } return GetFirstDerivative(_points[i], _points[i + 1], _points[i + 2], _points[i + 3], t); } // Returns a normalized velocity point relative to curve 'time' where 0 is bezier curve beginning and 1 is end of the bezier curve (length vise) public Vector3 GetDirection(float t) { return GetVelocity(t).normalized; } //### Mathematical core of Bezier Logic private static Vector3 GetPoint(Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float t) { t = Mathf.Clamp01(t); var oneMinusT = 1f - t; return oneMinusT*oneMinusT*oneMinusT*p0 + 3f*oneMinusT*oneMinusT*t*p1 + 3f*oneMinusT*t*t*p2 + t*t*t*p3; } private static Vector3 GetFirstDerivative(Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float t) { t = Mathf.Clamp01(t); var oneMinusT = 1f - t; return 3f*oneMinusT*oneMinusT*(p1 - p0) + 6f*oneMinusT*t*(p2 - p1) + 3f*t*t*(p3 - p2); } //Resets component to its default 2 points (forming a straight line) public void Reset() { _points = new[] { new Vector3(0f, 0f, 0f), new Vector3(2f, 0f, 0f), new Vector3(3f, 0f, 0f), new Vector3(4f, 0f, 0f) }; } //Returns a point by its index //- positioning (end points) have indexes 0, 3, 6, ... //- angles (control points) have indexes 1,2, 4,5, ... public Vector3 GetControlPoint(int index) { return Points[index]; } //Sets a point value by its index //- positioning (end points) have indexes 0, 3, 6 ... //- angles (control points) have indexes 1,2, 4,5, ... public void SetControlPoint(int index, Vector3 point) { if (index%3 == 0) { var delta = point - Points[index]; if (index > 0) { _points[index - 1] += delta; } if (index + 1 < _points.Length) { _points[index + 1] += delta; } } Points[index] = point; } // Adds a position point + 2 angle points public void AddPoint() { var length = Points.Length; var point = _points[length - 1]; var velocity = GetDirection(1f); Array.Resize(ref _points, length + 3); length = Points.Length; point += velocity; _points[length - 3] = point; point += velocity; _points[length - 2] = point; point += velocity; _points[length - 1] = point; } // Removes a position point + 2 angle points. gets an end point index as an argument //- positioning (end points) have indexes 0, 3, 6... public void RemovePoint(int selectedIndex) { var points = Points.ToList(); if (selectedIndex == _points.Length - 1) { points.RemoveRange(selectedIndex - 2, 3); } else { points.RemoveRange(selectedIndex - 1, 3); } _points = points.ToArray(); } } }