c++ - 二次曲线速度

标签 c++ bezier

我正在编写一个 2d 游戏,我在相机空间中有鸟。我想让它们飞起来。所以,我生成了 3 个随机点。第一个是左上侧,第二个:中下侧,第三个:右上侧。

结果我得到了 180 度旋转的三角形。

为了让一只鸟通过曲线的路径移动,我有一个 t 参数,它在每一帧(渲染循环)中增加一些增量。

问题在于,在不同的弯道中,鸟类的速度不同。如果三角形“宽”(1),则速度较慢,如果按 Y 坐标拉伸(stretch) (2),则速度非常快。

enter image description here

但我想让速度在不同的曲线上相等。从逻辑上讲,我必须更改 delta,它附加在每条曲线的每一帧上。


我试过这样解决:

通过对 2 个 vector 的长度求和求出曲线的长度:P1P2P2P3

我已经定义了每帧 1 虚拟米的速度。一点伪代码:

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

但是鸟类无论如何都有不同的速度。怎么了?或者也许有更好的方法。

最佳答案

您使用的 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;
}

您可以通过执行一阶差分来获得增量值,但我认为这不是必需的。只要您根据 step 迭代将所有鸟移动适当的距离,它们都会移动不同的距离,但它们的轨迹开始和结束将相同。

根据您的等式,我们可以计算像素增量步长:

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 会为你整合它,你只需要输入它:

Closed form solution for quadradic integration

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

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

关于c++ - 二次曲线速度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14790854/

相关文章:

c++ - 我的坐标系中的一个小错误计算

javascript - 如何根据可拖动助手精确更改 svg 路径的控制点

python - 如何将这些注释添加到这个二次贝塞尔曲线中?

javascript - 寻找三次贝塞尔曲线控制点的算法(实现细节)

c++ - 如何获取 libmathplot.a

c++ - 如何知道线程上下文切换何时发生?

c++ - 与 C 直接兼容的语言

c++ - 如何使用推力将具有相同键的值从一个数组复制到另一个数组?

r - 使用网格填充在 R 中绘制的贝塞尔曲线

计算立方贝塞尔曲线长度的廉价方法