Skip to content

Instantly share code, notes, and snippets.

@kschieck
Created June 10, 2015 14:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kschieck/0aa205abad413c0e5654 to your computer and use it in GitHub Desktop.
Save kschieck/0aa205abad413c0e5654 to your computer and use it in GitHub Desktop.
Unity3d class used to make objects follow a curve
using UnityEngine; // for Vector3
/// <summary>
/// A utility for finding points along a bezier curve
/// ref: http://en.wikipedia.org/wiki/B%C3%A9zier_curve
/// </summary>
public class Bezier
{
/// <summary>
/// Get point a certain distance after point at t
/// </summary>
/// <param name="iterations">degree of accuracy</param>
/// <param name="t">Time associated with the start point (before distance is added)</param>
/// <param name="t_out">(out)Time associated with the end point (after distance is added)</param>
/// <param name="Distance">How far to travel after point at t</param>
/// <param name="Angle">Angle associated with end point</param>
/// <param name="Points">Bezier control points</param>
/// <returns>Point on Bezier curve</returns>
public static Vector3 GetPoint(int iterations, float t, out float t_out, float Distance, out Quaternion Angle, params Vector3[] Points)
{
Vector3 start_pos = GetPoint(t, out Angle, Points);
float delta_t = Time.deltaTime;
Vector3 end_pos = GetPoint(t + delta_t, out Angle, Points);
for (int i = 0; i < iterations; i++)
{
delta_t *= Distance / (end_pos - start_pos).magnitude;
end_pos = GetPoint(t + delta_t, out Angle, Points);
}
t_out = t + delta_t;
return end_pos;
}
/// <summary>
/// Get a point along a Berzier Curve of any degree
/// </summary>
/// <param name="t">Percentage along the curve [0-1]</param>
/// <param name="Angle">3D derivative of the curve at the point</param>
/// <param name="Points">Start point, Control point(s), End point</param>
/// <returns>Vector3 location along the curve</returns>
public static Vector3 GetPoint(float t, out Quaternion Angle, params Vector3[] Points)
{
int n = Points.Length-1;
//Calculate all t^i (i in 1 to n)
float t_ = (1 - t);
float[] t_Exp = new float[n+1];
t_Exp[0] = 1;
for (int i = 1; i <= n; i++)
{
t_Exp[i] = t_Exp[i - 1] * t_;
}
//Calculate the point
Vector3 Point = new Vector3(0f, 0f, 0f);
Vector3 AnglePoint = new Vector3(0f, 0f, 0f);
float tCoefficient = 1f;
for (int i = 0; i <= n; i++)
{
//Incorporate next line into position
Point += NchooseK(n, i) * t_Exp[n - i] * tCoefficient * Points[i];
//Incorporate next line into angle
if (i == n) continue;
AnglePoint += NchooseK(n-1, i) * t_Exp[n-1-i] * tCoefficient * (Points[i+1] - Points[i]);
//Fix tCoefficient for next loop (t^i)
tCoefficient *= t;
}
Angle = Quaternion.LookRotation(AnglePoint, Vector3.up);
return Point;
}
/// <summary>
/// Calculate the choose function with integers
/// </summary>
/// <param name="n">Number of elements to choose from</param>
/// <param name="k">Number of elements to choose</param>
/// <returns>Integer result for the mathmatical function n choose k</returns>
private static int NchooseK(int n, int k)
{
int i = Mathf.Max(n-k, k);
int rv = 1;
for (int j = i+1; j<= n; j++) { rv *= j; }
for (int j = n-i; j>0; j--) { rv /= j; }
return rv;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment