Get to know the Bezier curve


data citation

Station B video: wow, magical Bezier curve!

Blog: A Brief Introduction to Bezier Curves

Zhihu: Curves: Bezier Curves


Uses of Bezier curves

  • Born based on the fluid design of the car's body structure
  • Handle image changes between video state points
  • Draw curves as you like, such as:

insert image description here

insert image description here


First order Bezier curve

insert image description here

As above, P 0 P_0P0 P 1 P_1 P1Two points constitute a line segment, and we can use a function - linear interpolation (lerp) to calculate a ttt 值( t ∈ [ 0 , 1 ] t \in [0,1] t[0,1 ] )PPon the line segmentP (the point that keeps sliding in the graph). whilePPThe trajectory of P (red line) is the first-order Bezier line segment (curve). The mathematical form of linear interpolation (first-order Bezier formula) is:

P = l e r p ( P 0 , P 1 , t ) = ( 1 − t ) P 0 + t P 1 P=lerp(P_0,P_1,t)=(1-t)P_0 + tP_1 P=lerp(P0P1t)=(1t)P0+tP1

A first-order Bezier curve has two endpoints ( P 0 P_0P0 P 1 P_1 P1), 0 control points .


Second-order Bezier curve

insert image description here

As above, suppose now point P 2 P_2P2, which is related to P 1 P_1P1constitutes a new line segment, we get two first- order interpolation points ( Q 1 Q_1Q1 Q 2 Q_2 Q2) , they constitute the green line segment, and it is worth noting that the two interpolation points have the same ttt -value.

At this time, we generate a second-order interpolation point ( PPP ), and let it havettt -value. Then the trajectory of the point is the second-order. Its formula is derived as:

  • The trajectory of the left endpoint of the green line segment:

Q 1 = ( 1 − t ) P 0 + t P 1 Q_1 = (1-t)P_0 + tP_1 Q1=(1t)P0+tP1

  • The trajectory of the right endpoint of the green line segment:

Q 2 = ( 1 − t ) P 1 + t P 2 Q_2 = (1-t)P_1 + tP_2 Q2=(1t)P1+tP2

  • Second-order Bezier curve formula:

P = ( 1 − t ) Q 1 + t Q 2 P = (1-t)Q_1 + tQ_2 P=(1t)Q1+tQ2
= ( 1 − t ) ( ( 1 − t ) P 0 + t P 1 ) + t ( ( 1 − t ) P 1 + t P 2 ) =(1-t)((1-t)P_0 + tP_1) + t((1-t)P_1 + tP_2) =(1t)((1t)P0+tP1)+t((1t)P1+tP2)
= ( 1 − t ) 2 P 0 + 2 t ( t − 1 ) P 1 + t 2 P 2 =(1-t)^2P_0+2t(t-1)P_1+t^2P_2 =(1t)2P0+2t(t1)P1+t2P2

A second-order Bezier curve has two endpoints ( P 0 P_0P0 P 2 P_2 P2), a control point ( P 1 P_1P1)。


Third-order Bezier curve

insert image description here

After studying and studying the first-order and second-order Bezier curves, we can know that the Bezier curve achieves order reduction by taking points between two points, and each point selection is a reduction in order.

  • P 0 P_0 P0 P 1 P_1 P1 P 2 P_2 P2 P 3 P_3 P3Interpolation points Q1 are generated by Q_1Q1 Q 2 Q_2 Q2 Q 3 Q_3 Q3to form a second-order Bezier (green line segment)
  • Generate interpolation point O 1 O_1 on this basisO1O 2 O_2O2to form a first-order Bezier (blue line)
  • Then with O 1 O_1O1O 2 O_2O2Interpolation point PP onP 's trajectory to generate a third-order Bezier curve.

The derivation process of the formula is the same as that of the second-order Bezier curve, so the formula is posted directly without going into details:

P = ( 1 − t ) 3 P 0 + 3 t ( 1 − t ) 2 P 1 + 3 t 2 ( 1 − t ) P 2 + t 3 P 3 P=(1-t)^3P_0+3t(1-t)^2P_1+3t^2(1-t)P_2+t^3P_3 P=(1t)3P0+3 t ( 1t)2P1+3 t2(1t)P2+t3P3

A third-order Bezier curve has two endpoints ( P 0 P_0P0 P 3 P_3 P3), two control points ( P 1 P_1P1 P 2 P_2 P2)。


Higher-order Bezier curves

  • Schematic diagram of a fourth-order Bezier curve:

insert image description here

  • Schematic diagram of the fifth-order Bezier curve:

insert image description here

  • Higher-order Bezier curve formula:

P ( t ) = ∑ i = 0 n P i B i , n ( t ) , t ∈ [ 0 , 1 ] P(t)=\sum_{i=0}^{n}P_iB_{i,n}(t),t \in [0,1] P(t)=i=0nPiBi,n(t)t[0,1]

B i , n ( t ) = C n i t i ( 1 − t ) n − i = n ! i ! ( n − i ) ! t i ( 1 − t ) n − i ,【 i = 0 , 1 , . . . , n 】 B_{i,n}(t)=C_n^it^i(1-t)^{n-i}=\frac{n!}{i!(n-i)!}t^i(1-t)^{n-i},【i=0,1,...,n】 Bi,n(t)=Cniti(1t)ni=i!(ni)!n!ti(1t)ni,【i=0,1,...,n


Third-order Bezier curve interpolation (Slerp)

After getting familiar with the related concepts of Bezier curve, let's understand its specific application. Usually its application scenarios are:

When two endpoints and two control points are known, according to the animation progress vector P x P_xPxseek ttt , then byttFind the curve confirmed by t P y P_yPy

Recall the third-order Bezier curve formula:
P = ( 1 − t ) 3 P 0 + 3 t ( 1 − t ) 2 P 1 + 3 t 2 ( 1 − t ) P 2 + t 3 P 3 P=( 1-t)^3P_0+3t(1-t)^2P_1+3t^2(1-t)P_2+t^3P_3P=(1t)3P0+3 t ( 1t)2P1+3 t2(1t)P2+t3P3

P 0 P_0 in the formulaP0 P 1 P_1 P1etc. are two-dimensional vectors, composed of two one-dimensional vectors P x P_xPxP and P_yPyconstitute. And we according to ttt forPPP , essentially according tottt to find a coordinate( x , y ) (x,y)(x,y ) . Therefore, the formula can be decomposed on two one-dimensional vectors:
y = ( 1 − t ) 3 P y 0 + 3 t ( 1 − t ) 2 P y 1 + 3 t 2 ( 1 − t ) P y 2 + t 3 P y 3 y=(1-t)^3P_{y0}+3t(1-t)^2P_{y1}+3t^2(1-t)P_{y2}+t^3P_{y3}y=(1t)3Py 0+3 t ( 1t)2Py 1+3 t2(1t)Py 2+t3Py 3

x = ( 1 − t ) 3 P x 0 + 3 t ( 1 − t ) 2 P x 1 + 3 t 2 ( 1 − t ) P x 2 + t 3 P x 3 x=(1-t)^3P_{x0}+3t(1-t)^2P_{x1}+3t^2(1-t)P_{x2}+t^3P_{x3} x=(1t)3Px 0+3 t ( 1t)2Px 1+3 t2(1t)Px 2+t3Px 3

And since we usually start at P 0 P_0 when dealing with animationsP0and end point P 3 P_3P3All can be determined [ P 0 ( 0 , 0 ) , P 3 ( 1 , 1 ) P_0(0,0), P_3(1,1)P0(0,0)P3(1,1 ) ], so the above formula can be simplified as (withxxx example,yyy in the same way):

x = 3 t ( 1 − t ) 2 P y 1 + 3 t 2 ( 1 − t ) P y 2 + t 3 x=3t(1-t)^2P_{y1}+3t^2(1-t)P_{y2}+t^3 x=3 t ( 1t)2Py 1+3 t2(1t)Py 2+t3

Fully expanded:
= 3 P y 1 t − 6 P y 1 t 2 + 3 P y 1 t 3 + 3 P y 2 t 2 − 3 P y 2 t 3 + t 3 =3P_{y1}t-6P_{y1 }t^2+3P_{y1}t^3+3P_{y2}t^2-3P_{y2}t^3+t^3=3Py 1t6 p.my 1t2+3Py 1t3+3Py 2t23Py 2t3+t3

Extract the cubic coefficient aaa
a = 3 P y 1 − 3 P y 2 + 1 a=3P_{y1}-3P_{y2}+1 a=3Py 13Py 2+1

Extract the quadratic coefficient bbb
b = 3 P y 2 − 6 P y 1 b=3P_{y2}-6P_{y1} b=3Py 26 p.my 1

Extract the first power coefficient ccc
c = 3 P y 1 c=3P_{y1} c=3Py 1

Simplifies the formula to:
x = at 3 + bt 2 + ctx=at^3+bt^2+ctx=at3+bt2+ct

move xxx , change the formula into a one-dimensional cubic equation:
at 3 + bt 2 + ct − x = 0 at^3+bt^2+ct-x=0at3+bt2+ctx=0

At this point, you can use the Cardan formula according to xxFind x out ttt . later according tottt can getyyy
y = ( 1 − t ) 3 P y 0 + 3 t ( 1 − t ) 2 P y 1 + 3 t 2 ( 1 − t ) P y 2 + t 3 P y 3 y=(1-t)^3P_{y0}+3t(1-t)^2P_{y1}+3t^2(1-t)P_{y2}+t^3P_{y3} y=(1t)3Py 0+3 t ( 1t)2Py 1+3 t2(1t)Py 2+t3Py 3

Code:

double SlerpWithCubicBazier(double pX1, double pY1, double pX2, double pY2, double x) {
    
    
    // x为动画进度,并不是t,t只是一个参数,先根据x求t,再由t确认的曲线上求y
    // 参考 https://github.com/gre/bezier-easing/blob/master/src/index.js
    double t = 0.0;
    if (x <= 0.0) {
    
    
        t = 0.0;
    }else if (x >= 1.0) {
    
    
        t = 1.0;
    }else {
    
    
        // x = (1-t)^3*P0x + 3*(1-t)^2*t*P1x + 3*(1-t)*t^2*P2x + t^3*P3x
        // 提取系数:
        double a = 0.0 + 3 * pX1 - 3 * pX2 + 1.0;
        double b = 3 * 0.0 - 6 * pX1 + 3 * pX2;
        double c = 0.0 + 3 * pX1;
        // 公式可化简为: x = at^3 + bt^2 + ct
        // 转换为基于 t 的一元三次方程:at^3 + bt^2 + ct - x = 0
        double d = 0 - x;

        // 那么就可以通过 SolveCubic 函数根据a、b、c、d四个系数来求解一元三次方程的一个实根
        // 可能该一元三次方程的根不止一个,但不重要,即使有多个根我们也只需要其中之一,且要求这个根是在 0~1 之间的,符合 t 的取值范围要求,如果没有根/没有符合要求的根我们会返回 -1
        double tTemp = SolveCubic(a, b, c, d);
        if (tTemp == -1) {
    
    
            return -1;
        }
        t = tTemp;
    }
    
    // Gy(t) = P0*(1-t)^3 + 3*P1*t*(1-t)^2 + 3*P2*t^2*(1-t) + P3*t^3  t[0,1]
    // PY0=0.0 PY3=1.0
    double coef1 = 0.0 * (1.0 - t) * (1.0 - t) * (1.0 - t);
    double coef2 = pY1 * 3 * t * (1.0 - t) * (1.0 - t);
    double coef3 = pY2 * 3 * t * t *  (1.0 - t);
    double coef4 = 1.0 * t * t * t;
    
    double gt = coef1 + coef2 + coef3 + coef4;
    return gt;
}

SolveCubicThe specific implementation of the function is as follows. It is worth noting that the function of this function cannot be simply equated with solving a cubic equation in one variable. The essential function of this function is to xfind out t? To give a specific example, line 5 of the following code has this statement:

if (d == 0) return 0;
  • In the case of d=0, ordinary unary cubic equations can continue to be solved;
  • But when SlerpWithCubicBaziercalling SolveCubic, with d = 0 − xd=0-xd=0The value is passed in the form of x , d = 0 d=0d=0 meansx = 0 x=0x=0 , the curve is at the starting point at this time,tthe value of which can be determined without solving the equation, that is,t = 0 t=0t=0
double FCPSolveCubic(double a, double b, double c, double d) {
    
    
    /* a=0 视为一元二次方程式 */
    if (a == 0) return FCPSolveQuadratic(b, c, d);
    /* d=0表明x=0,则t=0*/
    if (d == 0) return 0;
    
    /* 将三次方的系数变为1,方便后续判别式中的计算,即不用考虑 a^2 这一项了 */
    b /= a;
    c /= a;
    d /= a;
    /* q和r对应求根公式中的p和q,dis即是求根公式的判别式 △ */
    double q = (3.0 * c - FCPSquared(b)) / 9.0;
    double r = (-27.0 * d + b * (9.0 * c - 2.0 * FCPSquared(b))) / 54.0;
    double disc = FCPCubed(q) + FCPSquared(r);
    double term1 = b / 3.0;
    
    if (disc > 0) {
    
    
        /* 运用卡尔丹公式求得一个实根 */
        double s = r + sqrtf(disc);
        s = (s < 0) ? - FCPCubicRoot(-s) : FCPCubicRoot(s);
        double t = r - sqrtf(disc);
        t = (t < 0) ? - FCPCubicRoot(-t) : FCPCubicRoot(t);
        
        double result = -term1 + s + t;
        if (result >= 0 && result <= 1) return result;
    } else if (disc == 0) {
    
    
        double r13 = (r < 0) ? - FCPCubicRoot(-r) : FCPCubicRoot(r);
        
        double result = -term1 + 2.0 * r13;
        if (result >= 0 && result <= 1) return result;
        
        result = -(r13 + term1);
        if (result >= 0 && result <= 1) return result;
    } else {
    
    
        q = -q;
        double dum1 = q * q * q;
        dum1 = acosf(r / sqrtf(dum1));
        double r13 = 2.0 * sqrtf(q);
        
        double result = -term1 + r13 * cos(dum1 / 3.0);
        if (result >= 0 && result <= 1) return result;
        
        result = -term1 + r13 * cos((dum1 + 2.0 * M_PI) / 3.0);
        if (result >= 0 && result <= 1) return result;
        
        result = -term1 + r13 * cos((dum1 + 4.0 * M_PI) / 3.0);
        if (result >= 0 && result <= 1) return result;
    }
    
    return -1;
}

Knowledge used in the above code:

  • Discriminant formula for unary cubic equation:

△ = q 2 4 + p 2 27 △ = \frac{q^2}{4} + \frac{p^2}{27} =4q2+27p2

  • A real root of Cartan's formula in standard form equations:

insert image description here

Guess you like

Origin blog.csdn.net/Jormungand_V/article/details/125885941