参考:https://blog.youkuaiyun.com/jxw167/article/details/77717012
https://blog.youkuaiyun.com/jxw167/article/details/77732605
https://blog.youkuaiyun.com/jxw167/article/details/77836509
https://blog.youkuaiyun.com/jxw167/article/details/77848742
https://blog.youkuaiyun.com/jxw167/article/details/77862110
画线
线的数据类型
using UnityEngine;
public class Line : MonoBehaviour {
public Vector3 p0, p1;
}
线在编辑器中显示:由于Handles是世界空间,所以,要把point从局部空间转换到世界空间;改变位置后,再从世界空间转换到局部空间,修改point的值;记录改变、提醒保存;可以revert。
该类放在editor目录下
using UnityEditor;
using UnityEngine;
[CustomEditor(typeof(Line))]
public class LineInspector : Editor
{
//unity自带的回调函数
private void OnSceneGUI()
{
Line line = target as Line;
Transform handleTransform = line.transform;
Quaternion handleRotation = Tools.pivotRotation == PivotRotation.Local ?
handleTransform.rotation : Quaternion.identity;
//将p0从局部空间转换到世界空间
Vector3 p0 = handleTransform.TransformPoint(line.p0);
Vector3 p1 = handleTransform.TransformPoint(line.p1);
Handles.color = Color.yellow;
Handles.DrawLine(p0, p1);
EditorGUI.BeginChangeCheck();
p0 = Handles.DoPositionHandle(p0, handleRotation);
//当点改变时,才进行点的移动
if (EditorGUI.EndChangeCheck())
{
//记录历史记录,我们就可以执行撤销操作了
Undo.RecordObject(line, "Move Line");
//再重新转换回局部空间
line.p0 = handleTransform.InverseTransformPoint(p0);
//unity知道线改了,会提醒保存
EditorUtility.SetDirty(line);
}
EditorGUI.BeginChangeCheck();
p1 = Handles.DoPositionHandle(p1, handleRotation);
if (EditorGUI.EndChangeCheck())
{
Undo.RecordObject(line, "Move Line");
line.p1 = handleTransform.InverseTransformPoint(p1);
EditorUtility.SetDirty(line);
}
}
}
Bezier曲线
Bezier曲线来自于线性插值,线性曲线可以写为B(t) = (1 - t) P0 + t P1。二次曲线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 - t) t P1 + t2 P2。所以我们也可以直接使用二次公式而不是三次调用Vector3.Lerp。
另外,我们的二次Beziér曲线的一阶导数是B’(t) = 2 (1 - t) (P1 - P0) + 2 t (P2 - P1)。
二阶或三阶Bezier曲线公式
using UnityEngine;
public static class Bezier
{
public static Vector3 GetSquarePoint(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;
}
//B(t) = (1 - t)3 P0 + 3 (1 - t)2 t P1 + 3 (1 - t) t2 P2 + t3 P3
public static Vector3 GetCubicPoint(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;
}
//B'(t) = 2 (1 - t) (P1 - P0) + 2 t (P2 - P1)。
public static Vector3 GetSquareFirstDerivative(Vector3 p0, Vector3 p1, Vector3 p2, float t)
{
return 2f * (1f - t) * (p1 - p0) +
2f * t * (p2 - p1);
}
public static Vector3 GetCubicFirstDerivative(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 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 GetPoint(Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float t)
{
t = Mathf.Clamp01(t);
float oneMinusT =