# Bezier曲线

Beziér曲线由点序列定义， 它从第一点开始，在最后一点结束，创建一个新的Bezier曲线组件并给它一个点数组， 还要给它一个Reset方法，它用三点进行初始化， 该方法也可用作特殊的Unity方法，该方法在创建或重置组件时由编辑器调用。代码如下所示：

using UnityEngine;

public class BezierCurve : MonoBehaviour {

public Vector3[] points;

public void Reset () {
points = new Vector3[] {
new Vector3(1f, 0f, 0f),
new Vector3(2f, 0f, 0f),
new Vector3(3f, 0f, 0f)
};
}
}

using UnityEditor;
using UnityEngine;

[CustomEditor(typeof(BezierCurve))]
public class BezierCurveInspector : Editor {

private BezierCurve curve;
private Transform handleTransform;
private Quaternion handleRotation;

private void OnSceneGUI () {
curve = target as BezierCurve;
handleTransform = curve.transform;
handleRotation = Tools.pivotRotation == PivotRotation.Local ?
handleTransform.rotation : Quaternion.identity;

Vector3 p0 = ShowPoint(0);
Vector3 p1 = ShowPoint(1);
Vector3 p2 = ShowPoint(2);

Handles.color = Color.white;
Handles.DrawLine(p0, p1);
Handles.DrawLine(p1, p2);
}

private Vector3 ShowPoint (int index) {
Vector3 point = handleTransform.TransformPoint(curve.points[index]);
EditorGUI.BeginChangeCheck();
point = Handles.DoPositionHandle(point, handleRotation);
if (EditorGUI.EndChangeCheck()) {
Undo.RecordObject(curve, "Move Point");
EditorUtility.SetDirty(curve);
curve.points[index] = handleTransform.InverseTransformPoint(point);
}
return point;
}
}

private const int lineSteps = 10;

private void OnSceneGUI () {
curve = target as BezierCurve;
handleTransform = curve.transform;
handleRotation = Tools.pivotRotation == PivotRotation.Local ?
handleTransform.rotation : Quaternion.identity;

Vector3 p0 = ShowPoint(0);
Vector3 p1 = ShowPoint(1);
Vector3 p2 = ShowPoint(2);

Handles.color = Color.gray;
Handles.DrawLine(p0, p1);
Handles.DrawLine(p1, p2);

Handles.color = Color.white;
Vector3 lineStart = curve.GetPoint(0f);
for (int i = 1; i <= lineSteps; i++) {
Vector3 lineEnd = curve.GetPoint(i / (float)lineSteps);
Handles.DrawLine(lineStart, lineEnd);
lineStart = lineEnd;
}
}

	public Vector3 GetPoint (float t) {
return transform.TransformPoint(Bezier.GetPoint(points[0], points[1], points[2], t));
}

using UnityEngine;

public static class Bezier {

public static Vector3 GetPoint (Vector3 p0, Vector3 p1, Vector3 p2, float t) {
return Vector3.Lerp(p0, p2, t);
}
}

	public static Vector3 GetPoint (Vector3 p0, Vector3 p1, Vector3 p2, float t) {
return Vector3.Lerp(Vector3.Lerp(p0, p1, t), Vector3.Lerp(p1, p2, t), t);
}

B(t) = (1 - t) ((1 - t) P0 + t P1) + t ((1 - t) P1 + t P2)更深一步。 这只是线性曲线，P0和P1被两条新的线性曲线取代。 它也可以被重写为更紧凑的形式B(t) = (1 - t)2 P0 + 2 (1 - tt P1 + t2 P2

	public static Vector3 GetPoint (Vector3 p0, Vector3 p1, Vector3 p2, float t) {
t = Mathf.Clamp01(t);
float oneMinusT = 1f - t;
return
oneMinusT * oneMinusT * p0 +
2f * oneMinusT * t * p1 +
t * t * p2;
}

	public static Vector3 GetFirstDerivative (Vector3 p0, Vector3 p1, Vector3 p2, float t) {
return
2f * (1f - t) * (p1 - p0) +
2f * t * (p2 - p1);
}

	public Vector3 GetVelocity (float t) {
return transform.TransformPoint(Bezier.GetFirstDerivative(points[0], points[1], points[2], t)) -
transform.position;
}

		Vector3 lineStart = curve.GetPoint(0f);
Handles.color = Color.green;
Handles.DrawLine(lineStart, lineStart + curve.GetVelocity(0f));
for (int i = 1; i <= lineSteps; i++) {
Vector3 lineEnd = curve.GetPoint(i / (float)lineSteps);
Handles.color = Color.white;
Handles.DrawLine(lineStart, lineEnd);
Handles.color = Color.green;
Handles.DrawLine(lineEnd, lineEnd + curve.GetVelocity(i / (float)lineSteps));
lineStart = lineEnd;
}

		Vector3 lineStart = curve.GetPoint(0f);
Handles.color = Color.green;
Handles.DrawLine(lineStart, lineStart + curve.GetDirection(0f));
for (int i = 1; i <= lineSteps; i++) {
Vector3 lineEnd = curve.GetPoint(i / (float)lineSteps);
Handles.color = Color.white;
Handles.DrawLine(lineStart, lineEnd);
Handles.color = Color.green;
Handles.DrawLine(lineEnd, lineEnd + curve.GetDirection(i / (float)lineSteps));
lineStart = lineEnd;
}

	public Vector3 GetDirection (float t) {
return GetVelocity(t).normalized;
}

	public static Vector3 GetPoint (Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float t) {
t = Mathf.Clamp01(t);
float oneMinusT = 1f - t;
return
oneMinusT * oneMinusT * oneMinusT * p0 +
3f * oneMinusT * oneMinusT * t * p1 +
3f * oneMinusT * t * t * p2 +
t * t * t * p3;
}

public static Vector3 GetFirstDerivative (Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float t) {
t = Mathf.Clamp01(t);
float oneMinusT = 1f - t;
return
3f * oneMinusT * oneMinusT * (p1 - p0) +
6f * oneMinusT * t * (p2 - p1) +
3f * t * t * (p3 - p2);
}

	public Vector3 GetPoint (float t) {
return transform.TransformPoint(Bezier.GetPoint(points[0], points[1], points[2], points[3], t));
}

public Vector3 GetVelocity (float t) {
return transform.TransformPoint(
Bezier.GetFirstDerivative(points[0], points[1], points[2], points[3], t)) - transform.position;
}

public void Reset () {
points = new Vector3[] {
new Vector3(1f, 0f, 0f),
new Vector3(2f, 0f, 0f),
new Vector3(3f, 0f, 0f),
new Vector3(4f, 0f, 0f)
};
}

		Vector3 p0 = ShowPoint(0);
Vector3 p1 = ShowPoint(1);
Vector3 p2 = ShowPoint(2);
Vector3 p3 = ShowPoint(3);

Handles.color = Color.gray;
Handles.DrawLine(p0, p1);
Handles.DrawLine(p2, p3);

private const float directionScale = 0.5f;

private void OnSceneGUI () {
curve = target as BezierCurve;
handleTransform = curve.transform;
handleRotation = Tools.pivotRotation == PivotRotation.Local ?
handleTransform.rotation : Quaternion.identity;

Vector3 p0 = ShowPoint(0);
Vector3 p1 = ShowPoint(1);
Vector3 p2 = ShowPoint(2);
Vector3 p3 = ShowPoint(3);

Handles.color = Color.gray;
Handles.DrawLine(p0, p1);
Handles.DrawLine(p2, p3);

ShowDirections();
Handles.DrawBezier(p0, p3, p1, p2, Color.white, null, 2f);
}

private void ShowDirections () {
Handles.color = Color.green;
Vector3 point = curve.GetPoint(0f);
Handles.DrawLine(point, point + curve.GetDirection(0f) * directionScale);
for (int i = 1; i <= lineSteps; i++) {
point = curve.GetPoint(i / (float)lineSteps);
Handles.DrawLine(point, point + curve.GetDirection(i / (float)lineSteps) * directionScale);
}
}