【问题标题】:Drawing tangents for a bezier curve in OpenGL using c++使用 C++ 在 OpenGL 中绘制贝塞尔曲线的切线
【发布时间】:2017-06-12 17:54:39
【问题描述】:

所以我有一个有 4 个控制点的程序

std::vector<ControlPoint> cam_pos_points;
    cam_pos_points.push_back(ControlPoint(-0.79, 0.09, 0.2, 0));
    cam_pos_points.push_back(ControlPoint(-0.88, -0.71, 0.2, 1));
    cam_pos_points.push_back(ControlPoint(1.3, -0.8, 0.2, 2));
    cam_pos_points.push_back(ControlPoint(0.71, 0.76, 0.2, 3));

基本上,发生的情况是我设置了一种移动控制点的方法,当控制点移动时,新位置会被保存,并根据这个新位置重新计算曲线。我绘制曲线的方式是使用这些方程式:

for (double t = 0; t < 1; t += 0.1){
    float Px =(pow((1 - t), 3) * cam_pos_points[0].positionx()) + 
        ((pow((1 - t), 2) * t) * cam_pos_points[1].positionx()) + 
        (((1 - t) * pow(t, 2)) * cam_pos_points[2].positionx()) + 
        (pow(t, 3) * cam_pos_points[3].positionx());

    float Py =(pow((1 - t), 3) * cam_pos_points[0].positiony()) + 
        ((pow((1 - t), 2) * t) * cam_pos_points[1].positiony()) + 
        (((1 - t) * pow(t, 2)) * cam_pos_points[2].positiony()) + 
        (pow(t, 3) * cam_pos_points[3].positiony());
}

然后使用这两个浮点值,我将它们放入 vec3 中并生成一堆点。然后,我通过声明曲线中的点,然后在每个点之间画一条直线,将它们放入多线类中,在所有这些点之间画一条线。最终结果将是贝塞尔曲线。

我现在遇到的问题是绘制贝塞尔曲线的切线。我的想法是,对于第一个控制点,就是说切线在 P1 - P2 线上。那么在绘制切线之后,当我移动切点时,我应该使用什么方程来重新绘制曲线的形状?我已经找到了贝塞尔曲线方程的导数,但我不知道如何处理它们:

float dx = (-3*(pow((1 - t), 2)) * cam_pos_points[0].positionx()) + 
             (((-2*(1 - t)) * t) * cam_pos_points[1].positionx()) + 
              (((1 - t) * (2*t)) * cam_pos_points[2].positionx()) + 
                  ((3*pow(t, 2)) * cam_pos_points[3].positionx());

float dy = (-3*(pow((1 - t), 2)) * cam_pos_points[0].positiony()) + 
             (((-2*(1 - t)) * t) * cam_pos_points[1].positiony()) + 
              (((1 - t) * (2*t)) * cam_pos_points[2].positiony()) + 
                  ((3*pow(t, 2)) * cam_pos_points[3].positiony());

【问题讨论】:

  • 为什么使用pow 而不是直接计算? float mt = 1-t, t2 = t*t, mt2 = mt * mt, t3 = t2*t, mt3=mt2*mt; 然后使用它们。削减一些开销。在那张纸条上:我不知道你在计算什么,但这不是贝塞尔曲线。三次贝塞尔曲线采用 a * (t-1)^3 + b * 3 * t * (t-1)^2 + c * 3 * (t-1) * t^2 + d * t^3 的形式,其中 a、b、c 和 d 是您的坐标。前往pomax.github.io/bezierinfo/#control 并通读前几节以确保您的数学是正确的。现在:你还没有。

标签: c++ opengl point bezier curve


【解决方案1】:

你的起始切线将从第一个控制点到第二个控制点,结束切线将从第四个控制点到第三个控制点。我建议您每次重画时都重新开始;即,每当控制点移动时,都将其视为一个全新的方程。

如果您的一个(或两个)切线长度为零,那么它们实际上并不是切线本身,但曲线将朝向相反的端点。

这就是为什么您可以使用没有切线的贝塞尔曲线来表示直线。

【讨论】:

  • 这就是我对控制点所做的。每次移动控制点时,都会重新计算整个曲线。使用切线,当切点移动时,我希望在不移动任何控制点的情况下调整曲线的角度或形状。我遇到的问题是我在计算曲线后确定切线的位置,因此移动切线将无济于事。我可以做些什么来使用切点计算曲线,以便在移动切线时重新计算它?
【解决方案2】:

等式是错误的。

正确的公式是

(1-t)^3 * p0 + 3*(1-t)^2*t * p1 + 3*(1-t)*t^2 * p2 + t^3 * p3. 

展开和微分得到切线。

【讨论】:

  • 当您说扩展和微分时,您的意思是只取该方程的导数并插入某些 t 值即可得到切线?
  • 所以我找到了该方程的导数,但我不知道如何处理它。数字是位置还是方向,如果是方向,如何将其变成可以修改的控制点?
  • 没错。展开,你会得到两个三次方程,一个在 x 中,一个在 y 中,其中 t 是自变量。取 dx/dt 和 dy/dt 得到两个二次方程,使用初等微积分,然后代入 t 得到在给定 t 的点处切线的方向。
【解决方案3】:

您似乎想在贝塞尔曲线的起点和终点绘制切向量的切点,以便用户可以通过移动切点来调整曲线的形状。如果是这种情况,您需要注意移动切点也会移动第二个或第三个控制点。因此,正确的程序是从移动的切点重新计算第二个或第三个控制点,然后重新绘制曲线。

对于三次贝塞尔曲线,t=0 和 1 处的 C'(t) 为

C'(0)=3*(P1-P0)
C'(1)=3*(P3-P2)

假设你的起始切线的切点是 T0 并且位于

T0= P0+s0*C'(0)=P0+3*s0*(P1-P0)

其中 s0 是​​一个常数比例因子,用于确保您的切点不会离控制点太远。当 T0 变为 T0* 时,可以将控制点 P1 更新为

P1* = (T0*-P0)/(3*s0)+P0。

当结束切线的切点移动时,对控制点 P2 进行类似的更新。然后,您可以重新绘制曲线。

【讨论】:

  • 控制点和切线有区别吗?人们说要找到切线,您必须计算导数,这使我认为它与控制点不同,但是如果您还要移动控制点,则通过移动切线,移动切线和移动控件之间有什么区别点还是切线只是移动控制点的一种更简单的方法?
  • @OP:三次贝塞尔曲线由 4 个控制点表示。因此,它的一阶导数(或切线)也可以用这 4 个控制点来表示。所以。移动切线只是移动相应控制点的一种间接方式。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-18
  • 1970-01-01
  • 1970-01-01
  • 2013-08-21
  • 1970-01-01
相关资源
最近更新 更多