二次曲线的速度

9
我正在编写一款2D游戏,其中有鸟在摄像机空间中。我想让它们飞翔。因此,我生成了3个随机点,第一个点位于左上方,第二个点位于中心底部,第三个点位于右上方。
结果是我得到了一个180度旋转的三角形。
为了沿着曲线路径移动鸟,我有一个参数t,每帧(渲染循环)增加一些增量。
问题在于,在不同的曲线中,鸟的速度不同。如果三角形“宽”(1),它们会更慢,如果它被Y坐标拉伸(2),则速度非常快。
但我想使不同曲线的速度相等。逻辑上说,我必须为每个曲线更改附加到每帧的delta。
我已经尝试这样解决:
通过将2个向量的长度相加:P1P2和P2P3,找到曲线的长度。
然后我定义了虚拟米每帧的速度。以下是一些伪代码:
float pixelsInMeter = 92.f; // One virtual meter equals to this number of pixels
float length = len(P1P2) + len(P2P3)
float speed  = 0.0003f; // m/frame

// (length * speed) / etalon_length
float speedForTheCurve = toPixels( (toMeters(length) * speed) / 1.f);

// ...
// Each frame code:
t += speedForTheCurve;
Vector2 newPos = BezierQuadratic(t, P1, P2, P3);

但是鸟类的速度各不相同,这是什么原因呢?或许有更好的方法。


你为什么要除以 1.f?这有什么特殊的意义吗? - Tyler Jandreau
@TylerJandreau 只是为了展示公式。 - Max Frai
你的目标是让鸟以相同的速率飞行吗?还是无论二次贝塞尔曲线的长度如何,你希望它们在相同的时间开始/结束? - Tyler Jandreau
@TylerJandreau 我希望所有曲线不同的鸟都能以相同的时间飞越它们,对于所有鸟来说时间是相等的。 - Max Frai
@Ockonal:但这意味着它们的速度将取决于曲线的长度,以在恒定的时间内完成它。 - GManNickG
@GManNickG 噢,是的,抱歉。我想要另一种效果:相同的速度,但到达终点的时间不同。 - Max Frai
1个回答

2
您正在使用的Bezier函数是一个参数化函数,其范围为[0...1]。您正在修改步长,这就是为什么速度会变得疯狂的原因。一般来说,距离d是方程中的因变量,这意味着它们的速度将根据曲线长度而不同。
由于速度是您的因变量,我们将通过计算步长来向量化您的函数。
请查看以下伪代码:
P1 =(x1,y1)
P2 =(x2,y2)
P3 =(x3,y3)
int vec[100][2]

int getPoint(int p1, int p2, float stepSize) {
   return p1 + (p2 - p1)*stepSize;
}

for (float i = 0.0; i < 1.0; i += 0.01 ) {
   int newX = getPoint(getPoint(x1, x2, i), getPoint(x2, x3, i), i);
   int newY = getPoint(getPoint(y1, y2, i), getPoint(y2, y3, i), i);
   vec[iter++][0] = newX;
   vec[iter][1] = newY;
}

您可以通过进行第一差分来获取delta值,但我认为这并不必要。只要你根据步进迭代将所有的鸟移动到适当的距离,它们就会移动不同的距离,但它们的起始和结束轨迹都是相同的。
从您的方程式中,我们可以计算像素增量步长:
int pixelsToMove = toMeter(sqrt((x2 - x1)^2 + (y2 - y1)^2))/pixelsInMeter;

这段话的意思是:“这将为您提供适当的像素数量以移动鸟。这样它们将以不同的步长移动,但它们的速度将不同。这样说清楚了吗?”
或者,尝试类似于这样的内容(更难):
  1. 获取您选择的三个点的实际二次函数。
  2. 在两个 xy 直角坐标之间积分二次函数
  3. 将计算出的长度转换为像素或任何您正在使用的单位
  4. 获取依赖变量速度,使所有曲线在相同时间结束。
让我们从二次函数开始: y = Ax^2 + Bx + C 其中 A != 0,因此由于您有三个点,您将需要三个方程。使用代数,您可以解决常数: A = (y3 - y2)/((x3 - x2)(x3 - x1)) - (y1 - y2)/((x1 - x2)(x3 - x1)) B = (y1 - y2 + A(x2^2 - x1^2))/(x1 - x2) C = y1 - Ax1^2 - Bx1 然后,您可以使用上面的公式来获得一个闭合弧长。查看此网站,wolfram将为您进行积分,您只需键入即可:
中译英:

二次积分的闭合形式解

现在你已经计算出弧长,将actualArcLength转换为速度或你正在使用的任何单位:

float speedForTheCurve = toPixels( (toMeters(actualArcLength) * speed) / 1.f);

希望能有所帮助。如果需要任何帮助,请告诉我。 - Tyler Jandreau
谢谢;) 我会在不久的将来检查它,并将其标记为答案,否则会问你:) - Max Frai

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接