什么是贝塞尔曲线
贝塞尔曲线,英文名Bezier Curve,是计算机图形学非常重要的一种曲线
它可以将若干的点,用一条平滑自然的曲线来连接起来
比如我们在地图库中绘制用户行走轨迹时,如果用折线来展示,就比较难看
如果通过贝塞尔曲线,转为曲线来显示,就特别舒服自然了
像安卓中的水纹,波形等,很多就是通过贝塞尔曲线实现的
所以在讲绘制之前,先把这个基础知识给讲了
贝塞尔曲线简单示例
如图,P0和P2为贝塞尔曲线要经过的点,P1为控制点
选择不同的控制点,可以得到不同的曲线路径,但都可以结果P0和P2
贝塞尔曲线上的点如何确定
以上图为例,我们来推演下,最简单的贝塞尔曲线是如何确定点的
从P0开始,连接所有控制点,最后再连接到终点P2
我们随便在P0-P1上取一个点Q1,假设Q1的位置为t
t是指Q1到起点的位置,占整条线段长度的比例,所以它的范围是在0-1之间的小数
我们再在P1-P2上位置为t的地方,取一个点Q2
连接Q1-Q2,就形成了图中的绿线
再在Q1-Q2上位置为t的地方,取一个点R,就是图中的黑点
当t从0开始变化,逐渐增长到1,所有的黑点加起来,就形成了图中的红色曲线,它就是一条贝塞尔曲线
为什么贝塞尔曲线是连续的
从上面的推演过程,我们可以知道,贝塞尔曲线的路径,是一个关于t的函数
它的公式具体如何我们暂时不写出来,但一定是一个比较容易推到出来的公式
因为点确定的过程,就是根据两点的坐标,取线上中间某个比例位置的坐标,这就是个简单的乘法运算
当有多个控制点时,实际也就是进行了多次乘法运算,曲线是一个关于t的n次方的函数
学过高中数学的基本都知道,乘方函数,当变量t是均匀变化的,形成的肯定是一个圆滑连续的曲线
在高数中,这也叫做函数的连续性
贝塞尔曲线的阶数和公式
上面已经提到,贝塞尔曲线是关于比例t的乘方函数,t最高的次方数,就是贝塞尔曲线的阶数
上面的简单曲线,是一个二阶的贝塞尔曲线,只有一个控制点,公式中t的最高次方为2
L阶的贝塞尔曲线,有L-1个控制点,公式中t的最高次方为L
L阶的贝塞尔曲线公式如下
F ( t ) = P L 0 = ∑ i = 0 L C L i ∗ P 0 i ∗ ( 1 − t ) L − i ∗ t i F(t) = P{^0_L} = \sum_{i=0}^{L}\ C^i_L * P{^i_0} * (1 - t)^{L-i} * t^i F(t)=PL0=i=0∑L CLi∗P0i∗(1−t)L−i∗ti
多阶贝塞尔曲线效果展示
曲线 |
---|
一阶贝塞尔曲线 |
二阶贝塞尔曲线 |
三阶贝塞尔曲线 |
四阶贝塞尔曲线 |
五阶贝塞尔曲线 |
通过递归函数计算贝塞尔曲线
通过上面的数学公式,我们可以求得贝塞尔曲线上的点,但在编程中编写复杂的数学公式,是有点繁琐的
其实我们可以通过递归函数,直接算出比例t对应的坐标位置
递归运算的效率会比数学公式低,但是更加简单,偷懒的可以使用递归方法
这里我们以四阶贝塞尔曲线为例,简单讲解下递归过程
- 将所有起点-控制点-终点连接起来,形成4条灰色线段
- 每条灰色线段上的t位置取一个点,再连接起来,形成3条绿色线段
- 每条灰色线段上的t位置取一个点,再连接起来,形成2条蓝色线段
- 每条蓝色线段上的t位置取一个点,再连接起来,形成1条粉色线段
- 在粉色线段上的t位置取一个点,这个点就是贝塞尔曲线上t对应的位置
可以看出,整个过程就是一个不断递归的过程,每次在t位置取点,重新连接成新的线段,直到最后只有一个点
这个递归实现起来非常简单,这里就不给出具体代码了
- 用一个List存储全部的坐标值
- 再每相邻两个元素取t位置的中间值,形成一个新的List
- 如此递归,直到List中只剩一个点,这个点就是贝塞尔曲线上t对应的位置
贝塞尔曲线公式推导
这部分属于数学公式推导,不感兴趣或看不懂的,可以直接跳过,直接使用上面的结论公式即可
设最大阶数为Level,P[n,i]表示递归过程中的所有取点,n表示第几轮递归,i表示P在该轮所有取点中的顺序
已知所有P[0,i]的坐标,就是最初的已知点坐标,每一轮递归,n加1,i的最大值,也就是取点的总数减1
当n=Level时,只能取到唯一一个点,这个点就是我们想要求得的,贝塞尔曲线上比例t对应的点P[Level,0]
通过图示,我们可以很明显地看出,相邻两轮取点间的递推关系
P n i = ( 1 − t ) P n − 1 i + t P n − 1 i + 1 P{^i_n} = (1 - t)P{^i_{n-1}} + tP{^{i+1}_{n-1}} Pni=(1−t)Pn−1i+tPn−1i+1
根据这个递推公式,我们就可以得到最终的贝塞尔曲线公式(需要一定的数学知识和想象力)
F ( t ) = P L 0 = ∑ i = 0 L C L i ∗ P 0 i ∗ ( 1 − t ) L − i ∗ t i F(t) = P{^0_L} = \sum_{i=0}^{L}\ C^i_L * P{^i_0} * (1 - t)^{L-i} * t^i F(t)=PL0=i=0∑L CLi∗P0i∗(1−t)L−i∗ti
这个递推算法又叫做"德卡斯特里奥算法",下面的图可以帮助我们更好地理解推理过程
参考文献
这篇博客中的图片,转载自这里
贝塞尔曲线(Bezier Curve)原理及公式推导_CCC的专栏-CSDN博客
在此对原作者表示感谢和点赞