我有一个样条曲线我可以沿着曲线以可变速度移动一个物体,但我想以恒定速度移动我该如何实现呢?
public static class SplineCurve {
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);
}
}
我将恒定参数t发送到此曲线并获取该点,然后将对象移动到该点,但这给了我可变速度。我想以恒定的速度移动我的物体,我怎么能实现这个目标?
我能解决特定距离的任何等式吗?
B(t) = (1 - t)^3 * P0 + 3 * (1 - t)^2 * t * P1 + 3 * (1 - t) * t^2* P2 + t^3* P3
我用过这个等式
答案 0 :(得分:2)
您正在寻找的是贝塞尔曲线的重新参数化,该参数化是按时间参数化的,而不是“时间t
的曲线点”,您可以计算“曲线点”距离(或比率)d
“。这实际上是一个非常困难的问题,它是迄今为止最有效的实现你正在为“计算机屏幕”工作:构建一个LUT(查找表)点,其中每个点记录x / y(/ z)以这种方式覆盖的曲线起点的坐标,时间值和线性距离,这样您就可以沿着曲线移动(而不是曲线在数学上精确) )基于具有简单功能的LUT:
getCoordinate(d):
// get a known coordinate at, or before, distance 'd'
s = findBefore(d)
// get a known coordinate after distance 'd',
// or 'false' if 'd' is actually a real LUT point
e = findAfter(d)
// if it was a real LUT point, we're done.
if (e is false): return LUT[d]
// if it wasn't, perform linear interpolation
// between the known before/after coordinates,
// and treat that as the coordinate-for-distance.
return interpolate(d, e, s)
随着曲线上的距离单调增加,您可以通过写入距离的LUT 来让您的生活更轻松,因此LUT [0]是开始,LUT [len / 2]是曲线中途行走,LUT [len-1]结束。
要确保牢记的一件事是,为了正确使用它,您需要将曲线标记为两个长度:基于类似传奇的东西的真正的数学弧长-assass正交计算,以及此LUT的近似长度,基于您计算的坐标之间的所有线性距离的总和。您将第一个用于通用“告诉用户曲线长度”,但您使用 second 实际沿曲线移动东西。
(因为你不沿着曲线移动东西,你沿着曲线的多边形近似移动东西,其中99.99%的时间正是你想要的)
此代码未指定findbefore
和findafter
函数,但有太多方法可以执行此操作 - 二进制搜索(i = len, v = len >> 1
,检查LUT [iv];高于d
=> i -= v
,低于d
=> i += v
,修正v到v >> 1
,重复直到v
变为零,然后你找到了你的边界数组索引。
答案 1 :(得分:0)
不幸的是,Bezier曲线长度不能表示为闭合公式(它是椭圆积分)。但是对于移动你可能会忽略精度并使用一些简单的近似。
Arbitrary found example - “我做了什么”部分。
使用这种方法,您可以将曲线分成小段,为这些段获取长度并定义每个段的t变化速度。