贝塞尔曲线是图形学中非常重要的知识,是绘制曲线以及曲面的基础,在很多地方都有着非常广泛的应用,比如Photoshop里的钢笔工具,字体设计,各种过渡动画等等。本文将记录贝塞尔曲线的原理公式,以及使用Three.js中的贝塞尔曲线API进行简单的心形绘制。

贝塞尔曲线详解

贝塞尔曲线就是在起始点和终止点之间,设置控制点,通过控制点的移动来控制曲线的形状。根据控制点数量的不同,可以将贝塞尔曲线分为一阶曲线、二阶曲线、三阶曲线……等等。

一阶曲线

一阶曲线非常简单,因为没有控制点,所以就是一条从起始点到终止点的线段。

二阶曲线

opengl es 绘制贝塞尔曲线 js贝塞尔曲线动态画线_javascript

二阶曲线由起始点、终止点和一个控制点组成。贝塞尔曲线由以下规则形成:对于[0, 1]内任何t,在opengl es 绘制贝塞尔曲线 js贝塞尔曲线动态画线_javascript_02上取一个点opengl es 绘制贝塞尔曲线 js贝塞尔曲线动态画线_贝塞尔曲线_03,满足opengl es 绘制贝塞尔曲线 js贝塞尔曲线动态画线_贝塞尔曲线_04opengl es 绘制贝塞尔曲线 js贝塞尔曲线动态画线_贝塞尔曲线_05的关系为opengl es 绘制贝塞尔曲线 js贝塞尔曲线动态画线_opengl es 绘制贝塞尔曲线_06,同样的,在在opengl es 绘制贝塞尔曲线 js贝塞尔曲线动态画线_three.js_07上取一个点opengl es 绘制贝塞尔曲线 js贝塞尔曲线动态画线_javascript_08,满足opengl es 绘制贝塞尔曲线 js贝塞尔曲线动态画线_贝塞尔曲线_09opengl es 绘制贝塞尔曲线 js贝塞尔曲线动态画线_three.js_10的关系为opengl es 绘制贝塞尔曲线 js贝塞尔曲线动态画线_opengl es 绘制贝塞尔曲线_06。最后将opengl es 绘制贝塞尔曲线 js贝塞尔曲线动态画线_javascript_12相连,在opengl es 绘制贝塞尔曲线 js贝塞尔曲线动态画线_javascript_12上继续取一点满足opengl es 绘制贝塞尔曲线 js贝塞尔曲线动态画线_three.js_14。所有的t所形成的opengl es 绘制贝塞尔曲线 js贝塞尔曲线动态画线_图形学_15形成一道曲线,这道曲线就是贝塞尔曲线。对应的点的坐标在向量表示下很容易表示出来:
opengl es 绘制贝塞尔曲线 js贝塞尔曲线动态画线_opengl es 绘制贝塞尔曲线_16

三阶以及多阶曲线

类似于二阶曲线,三阶以及多阶贝塞尔曲线也是采用同样的方法,不断进行迭代,每一个t确定一个点,最后形成一条曲线。

opengl es 绘制贝塞尔曲线 js贝塞尔曲线动态画线_javascript_17

计算贝塞尔曲线有一个对于任意阶通用的公式:德卡斯特里奥算法 (De Casteljau’s algorithm),是一种递归的计算贝塞尔曲线的方法:
opengl es 绘制贝塞尔曲线 js贝塞尔曲线动态画线_three.js_18

使用Three.js中的贝塞尔曲线绘制心形

绘制圆形

我们首先可以通过贝塞尔曲线绘制出一个圆形,心形可以在圆形的基础上进行一定的控制点的调整就可以绘制而成。

opengl es 绘制贝塞尔曲线 js贝塞尔曲线动态画线_javascript_19

从上图中可以看出,一个圆形可以被分成四个弧线,每条弧线可以通过一个三阶贝塞尔曲线绘制而成(两个控制点),控制点的位置在geometry - How to create circle with Bézier curves? - Stack Overflow已经有人计算好了,我们可以直接使用(这里的计算也并不是特别复杂,简单的数学知识就可以计算出来)。由此,我们可以通过贝塞尔曲线创建出一个圆的形状:

const x = 0, y = 0;
const radius = 30;
const c = 0.551915024494 * radius;

const heartShape = new THREE.Shape()
    .moveTo(x, y+radius)
    .bezierCurveTo(x+c,y+radius, x+radius, y+c, x+radius, y)
    .bezierCurveTo(x+radius,y-c, x+c, y-radius, x, y-radius)
    .bezierCurveTo(x-c,y-radius, x-radius, y-c, x-radius, y)
    .bezierCurveTo(x-radius,y+c, x-c, y+radius, x, y+radius)

bezierCurveTo()是Three.js中的贝塞尔曲线的API,它接受六个参数,前四个分别是两个控制点的x,y坐标,最后两个是终止点的x,y坐标。这里只需要设定好参数,使用四段贝塞尔曲线一一绘制出来就可以了。

绘制心形

心形其实就是在圆形的基础上移动了三个控制点的位置,将y轴上上方的起始点稍向下移动,以及下方左右两个控制点向上移动,就可以绘制出一个心形,代码以及效果图如下所示。

const x = 0, y = 0;
const radius = 30;
const c = 0.551915024494 * radius;

const heartShape = new THREE.Shape()
    .moveTo(x, y+radius/3)
    .bezierCurveTo(x+c,y+radius, x+radius, y+c, x+radius, y)
    .bezierCurveTo(x+radius,y-c, x+c, y-radius/2, x, y-radius)
    .bezierCurveTo(x-c,y-radius/2, x-radius, y-c, x-radius, y)
    .bezierCurveTo(x-radius,y+c, x-c, y+radius, x, y+radius/3)

opengl es 绘制贝塞尔曲线 js贝塞尔曲线动态画线_图形学_20