unity 控制点 贝塞尔曲线_Unity中的曲线绘制(二)——贝塞尔曲线

本文介绍了如何在Unity中实现二次和三次贝塞尔曲线,通过BezierCurve类和OnSceneGUI方法绘制曲线,并提供了GetPoint、GetVelocity和GetDirection等方法,用于计算曲线上的点、速度和方向。此外,还讨论了从二次到三次贝塞尔曲线的升级过程。
摘要由CSDN通过智能技术生成

新建一个BezierCurve类,它包含三个点,同样定义Reset方法来初始化点的值,当绑定了BezierCurve脚本的对象创建或重置时,Unity editor会自动调用Reset方法。这个类代表了一个二次贝塞尔曲线。

1234567891011121314

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)};}}

同样地,我们为curve写一个inspector,它和LineInspector颇为类似。为了减少重复代码,我们把显示点的代码放在单独的ShowPoint方法里,通过传入参数index来调用。将curve,handleTransform和handleRotation作为全局变量,这样在调用ShowPoint时不用再传一次参数。

贝塞尔曲线可以定义为一个参数方程。给定一个[0,1]区间内的参数t,就能得到曲线上的一个点,当t从0增至1,我们就能得到一条完整的贝塞尔曲线。

为了在场景中显示一条贝塞尔曲线,我们可以通过连续地画直线来模拟。做一个简单的循环,在点和点之间连续地绘制直线,并且将颜色设置为灰色。假设已经有GetPoint方法。

123456789101112131415161718192021222324

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;}}

现在我们必须在BezierCurve里添加GetPoint方法,否则会编译报错。这一次要假设我们已经有一个工具类Bezier,对控制点进行插值处理。同样要将控制点转为世界坐标。

添加一个静态类Bezier,暂时忽略中间点,只对p0和p1做插值试试看。

当然,端点之间的线性插值完全忽略了中间点。那么,我们如何将中间点也考虑进来呢?答案是多次插值。第一步,在起点和中间点之间进行插值,第二步在中间点和终点之间进行插值。这样就得到了两个点。再对这两个点进行一次插值,得到的结果就是贝塞尔曲线上的一个点。

这种曲线又被称为二次贝塞尔曲线,因为它的数学表示是二次多项式。

线性贝塞尔曲线:

升一阶就可以得到

,即将线性贝塞尔曲线中的P0和P1换成了两个新的插值点。整理后可以得到二次贝塞尔曲线的数学表示:

根据上面的公式我们可以用二次多项式来代替原代码中的Vector3.Lerp。

既然已经得到了二次贝塞尔曲线的多项式表示,我们可以写出它的一阶导: ,添加相关方法。

曲线上某个点的一阶导就是该点的切线,这个方法返回的值可以认为是点沿曲线移动的速度,因此我们可以在BezierCurve中添加GetVelocity方法来获取速度。

因为它返回的是一个速度的向量而非一个点,它同样会受到曲线对象位置的影响,因此我们需要对它进行位置变换。

因为TransformDirection方法不会考虑缩放的转换,但是我们需要把这个因素也考虑进去。因此我们把速度向量先当成一个点来处理,得到转换后的结果后再减去曲线对象的位置,就能得到正确的速度向量,即使缩放系数为负数,这个方法也会生效。为什么这里要用TransformPoint而不是TransformDirection呢?

现在我们也绘制一下速度,同样在BezierCurveInspector中的OnSceneGUI方法中进行。

我们可以很清楚地看到速度沿曲线变化的过程,但是这些线的长度太长,影响视图。我们改为只显示速度方向即可。

在BezierCurve中添加GetDirection方法,对速度进行标准化。

123

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

接下来我们再升一阶,为Bezier添加新的方法,来处理三次贝塞尔曲线。和二次贝塞尔曲线类似,只不过它有四个点,其中两个控制点,两个起始点,共需要6次线性插值。整理后的曲线方程为:

,它

的一阶导为

将BezierCurve从二次升为三次贝塞尔曲线,为它添加第四个点,记得重置组件。

BezierCurveInspector 同样也要进行更新,显示新添加的点。

12345678

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);

可以看到,我们利用直线绘制出来了初步的贝塞尔曲线,通过增加lineSteps的值,曲线会变得更为平滑。实际上,Unity已经封装了三次贝塞尔曲线的绘制方法 - Handles.DrawBezier

点击阅读原文,即刻参与程序虚幻引擎的大赛

点击一下

立即阅读相关好文章

......

近期热文

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值