给定一组点,用平滑曲线按顺序连接点:
考虑过 贝塞尔曲线 ,但是贝塞尔曲线只经过首尾两个点,其余点是控制点,不经过曲线
于是找到了接下来的 Catmull-Rom样条曲线:
参考资料:Centripetal Catmull–Rom spline
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//https://en.wikipedia.org/wiki/Centripetal_Catmull%E2%80%93Rom_spline
public class SmoothCurveHandler : MonoBehaviour
{
[SerializeField] LineRenderer lineRender;
[SerializeField] List<Transform> posList;
const int countBetween2Point = 20;
Vector3[] curvePoints;
void Start()
{
curvePoints = new Vector3[countBetween2Point * (posList.Count - 1) + 1];
lineRender.positionCount = curvePoints.Length;
}
void Update()
{
CalculateCurve();
lineRender.SetPositions(curvePoints);
}
//-----------------------
Vector3 firstPos, curPos, nextPos, lastPos;
void CalculateCurve()
{
//依次计算相邻两点间曲线
//由四个点确定一条曲线(当前相邻两点p1,p2,以及前后各一点p0,p3)
for (int i = 0; i < posList.Count - 1; i++)
{
//特殊位置增加虚拟点
//如果p1点是第一个点,不存在p0点,由p1,p2确定一条直线,在向量(p2p1)方向确定虚拟点p0
if (i == 0)
firstPos = posList[i].position * 2 - posList[i + 1].position;
else
firstPos = posList[i - 1].position;
//中间点
curPos = posList[i].position;
nextPos = posList[i + 1].position;
//特殊位置增加虚拟点,同上
if (i == posList.Count - 2)
lastPos = posList[i + 1].position * 2 - posList[i].position;
else
lastPos = posList[i + 2].position;
CatmulRom(firstPos, curPos, nextPos, lastPos, ref curvePoints, countBetween2Point * i);
}
//加入最后一个点位
curvePoints[curvePoints.Length - 1] = posList[posList.Count - 1].position;
}
//平滑过渡两点间曲线(p1,p2为端点,p0,p3是控制点)
void CatmulRom(Vector2 p0, Vector2 p1, Vector2 p2, Vector2 p3, ref Vector3[] points, int startIndex)
{
//计算Catmull-Rom样条曲线
float t0 = 0;
float t1 = GetT(t0, p0, p1);
float t2 = GetT(t1, p1, p2);
float t3 = GetT(t2, p2, p3);
float t;
for (int i = 0; i < countBetween2Point; i++)
{
t = t1 + (t2 - t1) / countBetween2Point * i;
Vector2 A1 = (t1 - t) / (t1 - t0) * p0 + (t - t0) / (t1 - t0) * p1;
Vector2 A2 = (t2 - t) / (t2 - t1) * p1 + (t - t1) / (t2 - t1) * p2;
Vector2 A3 = (t3 - t) / (t3 - t2) * p2 + (t - t2) / (t3 - t2) * p3;
Vector2 B1 = (t2 - t) / (t2 - t0) * A1 + (t - t0) / (t2 - t0) * A2;
Vector2 B2 = (t3 - t) / (t3 - t1) * A2 + (t - t1) / (t3 - t1) * A3;
Vector2 C = (t2 - t) / (t2 - t1) * B1 + (t - t1) / (t2 - t1) * B2;
points[startIndex + i] = C;
}
}
float GetT(float t, Vector2 p0, Vector2 p1)
{
return t + Mathf.Pow(Mathf.Pow((p1.x - p0.x), 2) + Mathf.Pow((p1.y - p0.y), 2), 0.5f);
}
}