贝塞尔曲线

贝塞尔曲线

欢迎前往个人博客 驽马点滴 和视频空间 哔哩哔哩-《挨踢日志》

一.相遇Bezier曲线

 

      在写这篇文章的时候,我正在广州一家游戏公司从事客户端的研发工作,使用Cocos2dx引擎。在游戏的开发过程中,有时候需要让对象沿着一条光滑的曲线运动,比如说怒气粒子沿着光滑的曲线运动到UI层的指定怒气槽。关于曲线的实现,直接调用Cocos2dx引擎中类CCBezierBy的API接口:static CCBezierBy* create(float t, const ccBezierConfig& c)

该接口需要曲线运动的时间t以及贝塞尔曲线的结构为ccBezierConfig的参数c.

引擎中ccBezierConfig定义如下:

 

/** @typedef bezier configuration structure
 */
typedef struct _ccBezierConfig {
    //! end position of the bezier
    CCPoint endPosition;
    //! Bezier control point 1
    CCPoint controlPoint_1;
    //! Bezier control point 2
    CCPoint controlPoint_2;
} ccBezierConfig;

 

简而言之,ccBezierConfig结构定义了三阶贝塞尔曲线的4个控制点: 起点(0,0), 控制点controlPoint_1, controlPoint_2和结束点endPosition.(当然,其中(0,0)点是隐藏知识)

转到其update函数中看看:

 

void CCBezierBy::update(float time)
{
    if (m_pTarget)
    {
        float xa = 0;
        float xb = m_sConfig.controlPoint_1.x;
        float xc = m_sConfig.controlPoint_2.x;
        float xd = m_sConfig.endPosition.x;

        float ya = 0;
        float yb = m_sConfig.controlPoint_1.y;
        float yc = m_sConfig.controlPoint_2.y;
        float yd = m_sConfig.endPosition.y;

        float x = bezierat(xa, xb, xc, xd, time);
        float y = bezierat(ya, yb, yc, yd, time);

#if CC_ENABLE_STACKABLE_ACTIONS
        CCPoint currentPos = m_pTarget->getPosition();
        CCPoint diff = ccpSub(currentPos, m_previousPosition);
        m_startPosition = ccpAdd( m_startPosition, diff);

        CCPoint newPos = ccpAdd( m_startPosition, ccp(x,y));
        m_pTarget->setPosition(newPos);

        m_previousPosition = newPos;
#else
        m_pTarget->setPosition(ccpAdd( m_startPosition, ccp(x,y)));
#endif // !CC_ENABLE_STACKABLE_ACTIONS
    }
}

 

可以看出,在知道了4个点p0, p1, p2, p3后,贝塞尔曲线在各个维度上的计算公式由bezierat(p0, p1, p2, p3)给出.

 

转到实现,其实现细节如下:

 

 

 

// Bezier cubic formula:
//    ((1 - t) + t)3 = 1 
// Expands to… 
//   (1 - t)3 + 3t(1-t)2 + 3t2(1 - t) + t3 = 1 
static inline float bezierat( float a, float b, float c, float d, float t )
{
    return (powf(1-t,3) * a + 
            3*t*(powf(1-t,2))*b + 
            3*powf(t,2)*(1-t)*c +
            powf(t,3)*d );
}

 

好,这就是和Bezier曲线的正式相遇,到现在,只知道了所谓的3阶Bezier曲线的一个应用,那么,它究竟是什么样的一条曲线?

 

 

二.贝塞尔曲线初探

     为了给对函数不太理解的朋友一些入门, 我这里用一个例子描述一下接下来内容所要表达的意思:

接下来的内容, 要做的事情就是:假定贝塞尔曲线的表达式是y=f(u),0≤u≤1, 其表达式是怎么样的?

举个例子: 我们都知道抛物线的表达式是

          y=f(x)=ax^2 + bx + c (a≠0)    也就是说,给定一个x值, 就确定了一点(x,ax^2 + bx + c)

          于是,当x取遍R上的每一个值,那么函数也就确定了其每一点, 其图像因此确定.

那么你懂了这个以后, 接下来的工作内容为,给定一个u, 请确定Bezier曲线上的一点(u, Bezier(u))

也就是确定y = Bezier(u) 0≤u≤1的函数解析式.

 

1.de Casteljau's 算法

    根据Bezier曲线的结构,一个重要的任务是:对于给定的u,0≤u≤1,如何确定贝塞尔曲线上的一点Bezier(u) ?

    

     1.1 线段u分点

    从A点出发,B为终点的向量为B-A, 假若u是0~1之间的一个数,那么u*(B-A)是向量B-A的u倍,加上起点A,那么向量 A+u(B-A)确定了点C, 且它分线段AB的比例为u:(1-u).

 

   由于C=A+u(B-A)=(1-u)A + uB,我们称:

线段AB的u分点C的表达式为   C=(1-u)A + uB

 

 

     1.2 de Casteljau's 算法

n阶贝塞尔曲线有n+1个控制点.

 

 

  • n=1时, 也就是贝塞尔曲线只由两个点P0, P1决定,直接取线段u分点,得到Bezier(u)=(1-u)P0 + uP1, 于是1阶Bezier曲线就是连接P0和P1的线段.

 

 

 

 

  • n=2时,贝塞尔曲线由三个点P0,P1,P2决定,
    • 先对P0P1线段u分点, 得到P10 = (1-u)P0 + uP1
    • 再对P1P2线段u分点, 得到P11 =(1-u)P1 + uP2
    • 于是得到两条线段上的两个u分点P10P11
    • 对于两个u分点P10P11, 再取线段u分点, 得到P20 = (1-u)P10 + uP11 = (1-u)((1-u)P0 + uP1) + u((1-u)P1 + uP2)=(1-u)^2P0 + 2(1-u)uP1 + u^2P2
    • P20即为贝塞尔曲线在u时的点;
    • 即: Bezier(u) = (1-u)^2P0 + 2(1-u)uP1 + u^2P2

 

 

 

 

  • n时, 贝塞尔曲线由n+1个点P0, P1,P2, ..., Pn决定.
    • 分别对线段P0P1, P1P2, ..., Pn-1Pn线段u分点, 得到n个点P10, P11, ... P1n-1
    • 分别对线段P10P11, ... P1n-2P1n-1取线段u分点, 得到n-1个点P20, P21, ... P2n-2
    • ......
    • 分别对Pn-10Pn-11取线段u分点, 得到最后1个点Pn0. 这个点即为Bezier曲线在给定u时的点.

 

此过程可以由递归式:

表示.

 

 

而我们所求即为i=n, j=0时的值:

 

(此公式可以应用数学归纳法并利用递推公式证明)

 

 

至此, 在Coco2dx引擎中关于Bezier曲线的计算方法,就很明朗了, 它就是3阶的贝塞尔曲线:

 

其系数恰是3阶二项展开式的系数.

 

 

二.Bezier曲线的性质

 

2.1 系数性质

Bezier曲线其系数为下面的二项展开式第K项的系数:

因此二项式系数拥有的性质,它都有,包括但不限于[权性: 系数和为1].

2.2 曲线性质

2.2.1对称性

Bezier曲线的全部控制顶点位置不变,但次序颠倒,那么其曲线形状不变,参数u变为1-u.

2.2.2仿射不变性

即对于贝塞尔曲线做任意的仿射变换A, 可以将A作用在各个控制顶点上后再线性求和.
 
这点重要的性质, 意味着对Bezier曲线做几何变换是极其便利的.
 
举个例子, 当一个物体a在某个坐标系内做贝塞尔曲线运动, 而这个坐标系同时在做一个旋转运动,那么,如果旋转变换如果为R(theta), 那么该旋转变换可以相应作用在控制定点上;

2.2.3其他

略.

三.以下是参考的资料:

http://www.cs.mtu.edu/~shene/COURSES/cs3621/NOTES/spline/Bezier/de-casteljau.html

 

 

欢迎前往个人博客 驽马点滴 和视频空间 哔哩哔哩-《挨踢日志》

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值