前言:每日记录自己学习unity的心得和体会,小弟才疏学浅,如有错误的地方,欢迎大佬们指正,感谢~
贝塞尔曲线原理
常用的贝塞尔曲线,就是二维图形应用程序的数学曲线。 曲线定义:起始点、终止点、控制点。通过调整控制点,贝塞尔曲线的形状会发生变化。
一阶直线
如何将下图中C CC点在设定时间内,从A AA点移动到B BB点?这里设定一个时间 t , t ∈ ( 0 , 1 ) t ,t \in(0,1)t,t∈(0,1),
二阶曲线
Vector3 AB = (1 - t) * OA + t * OB;
Vector3 BC = (1 - t) * OB + t * OC;
Vector3 ABC = (1 - t) * AB + t * BC;
三阶曲线
三阶和二价类似,不断累加。
Vector3 AB = (1 - t) * OA + t * OB;
Vector3 BC = (1 - t) * OB + t * OC;
Vector3 CD = (1 - t) * OC + t * OD;
Vector3 ABC = (1 - t) * AB + t * BC;
Vector3 BCD = (1 - t) * BC + t * CD;
result = (1 - t) * ABC + t * BCD;
后面四道高阶以此类推。日常常用的就是三阶,即四个点确定一条曲线。
贝塞尔的创建方法
public class BasselPath
{
List<GameObject> piont = new List<GameObject>();
GameObject mianPiont;
GameObject frontPiont;
GameObject backePiont;
public BasselPath()
{
mianPiont = new GameObject();
mianPiont.transform.position = Vector3.zero;
frontPiont = new GameObject();
frontPiont.transform.position = Vector3.zero + (Vector3.right * 5);
backePiont = new GameObject();
backePiont.transform.position = Vector3.zero + (Vector3.left * 5);
piont.Add(frontPiont);
piont.Add(mianPiont);
piont.Add(backePiont);
backePiont.transform.SetParent(mianPiont.transform);
frontPiont.transform.SetParent(mianPiont.transform);
mianPiont.AddComponent<DrawGizmosPoint>();
frontPiont.AddComponent<DrawGizmosPoint>();
backePiont.AddComponent<DrawGizmosPoint>();
}
public GameObject MianPiont { get => mianPiont; set => mianPiont = value; }
public GameObject FrontPiont { get => frontPiont; }
public GameObject BackePiont { get => backePiont; }
public List<GameObject> Piont { get => piont; }
}
/// <summary>
/// 绘制节点
/// </summary>
public class DrawGizmosPoint : MonoBehaviour
{
public float radius = 1;
private void OnDrawGizmos()
{
//绘制点
Gizmos.color = Color.blue;
Gizmos.DrawSphere(transform.position, radius * 0.5f);
}
}
/// <summary>
/// 绘制节点线
/// </summary>
public class DrawGizmosPointLine : MonoBehaviour
{
public float radius = 1;
public List<GameObject> SelfPoint = new List<GameObject>();
private void OnDrawGizmos()
{
List<Vector3> controlPointPos = SelfPoint.Select(point => point.transform.position).ToList();
//绘制曲线控制点连线
Gizmos.color = Color.red;
for (int i = 0; i < controlPointPos.Count - 1; i += 3)
{
Gizmos.DrawLine(controlPointPos[i], controlPointPos[i + 1]);
Gizmos.DrawLine(controlPointPos[i + 1], controlPointPos[i + 2]);
}
}
}
/// <summary>
/// 绘制曲线
/// </summary>
public class DrawGizmosLine : MonoBehaviour
{
public float radius;
public int densityCurve;
public List<GameObject> SelfPoint;
public List<Vector3> CurvePoints;
private void OnDrawGizmos()
{
List<Vector3> controlPointPos = SelfPoint.Select(point => point.transform.position).ToList();
if (controlPointPos != null)
{
CurvePoints = GetDrawingPoints(controlPointPos, densityCurve);
}
//绘制曲线
if (CurvePoints.Count >= 4)
{
Gizmos.color = Color.green;
//点密度
foreach (var item in CurvePoints)
{
Gizmos.DrawSphere(item, radius * 0.5f);
}
//曲线
for (int i = 0; i < CurvePoints.Count - 1; i++)
{
Gizmos.DrawLine(CurvePoints[i], CurvePoints[i + 1]);
}
}
}
/// <summary>
/// 获取绘制点
/// </summary>
/// <param name="controlPoints"></param>
/// <param name="segmentsPerCurve"></param>
/// <returns></returns>
public List<Vector3> GetDrawingPoints(List<Vector3> controlPoints, int segmentsPerCurve)
{
List<Vector3> points = new List<Vector3>();
// 下一段的起始点和上段终点是一个,所以是 i+=3
for (int i = 1; i < controlPoints.Count - 4; i += 3)
{
var p0 = controlPoints[i];
var p1 = controlPoints[i + 1];
var p2 = controlPoints[i + 2];
var p3 = controlPoints[i + 3];
float dis = Vector3.Distance(p0, p3);
int count = Mathf.CeilToInt(segmentsPerCurve * dis);
if (count < segmentsPerCurve)
{
count = segmentsPerCurve;
}
for (int j = 0; j <= count; j++)
{
var t = j / (float)count;
points.Add(CalculateBezierPoint(t, p0, p1, p2, p3));
}
}
return points;
}
// 三阶公式
Vector3 CalculateBezierPoint(float t, Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3)
{
Vector3 result;
Vector3 p0p1 = (1 - t) * p0 + t * p1;
Vector3 p1p2 = (1 - t) * p1 + t * p2;
Vector3 p2p3 = (1 - t) * p2 + t * p3;
Vector3 p0p1p2 = (1 - t) * p0p1 + t * p1p2;
Vector3 p1p2p3 = (1 - t) * p1p2 + t * p2p3;
result = (1 - t) * p0p1p2 + t * p1p2p3;
return result;
}
}