贝塞尔定时动画路径

时间:2009-11-20 03:02:34

标签: javascript animation canvas bezier

我正在尝试定义一条点的路径。每个点都有x,y和时间。然后,我想查询此路径并获取该时间点的当前位置。让我分享一些伪代码。

point {x, y, time}


function initialisePath(point[] path) {
    ... // Create Bezier Path
}

function getXYAtTime(time) {
    return ... // Get interpolated point along the bezier path at the specified time
}

我正在尝试使用canvas标签在javascript中实现此功能。但是,任何语言的样本都可以。有没有人知道任何创建这种可查询路径的开源库(使用任何语言)?

注意:我一直在尝试从DynApi project开始研究这个示例和代码,但是从这个样本转移到时间感知路径对我的动画技能很差。

由于

2 个答案:

答案 0 :(得分:6)

Bézier curve不仅包含起点和终点,还包含指导曲线形状的控制点。在您链接的DynApi演示中,端点标记为黄色,控制点标记为红色。

您的路径将是一系列Bézier曲线,端到端连接。

所以我们假设您的伪代码,但我们会将 not 的所有点都视为控制点。

function Path(points) {
    this.points = points;

    // Sanity check.
    if (points[0].time == undefined || points[points.length - 1].time == undefined)
        throw new Error("all control points must be between two real points");
}

Path.prototype.getXYAtTime = function (t) {
    var points = this.points;

    // First, see if t is out of range.
    if (t < points[0].time)
        return points[0];
    if (t > points[points.length - 1].time)
        return points[points.length - 1];

    // OK, t is in range. Find out which Bezier curve we're in.
    //
    // Specifically we want 'start' and 'stop' to be the indexes of two points
    // that each have a .time property, bracketing the current time t; and
    // all the points in between 'start' and 'stop' should be control points.
    //
    var start = 0, stop = points.length - 1;
    for (var i = 1; i < points.length; i++) {
        var p = points[i];
        if (t < p.time) {
            stop = i;
            break;
        }
        if (p.time != undefined)
            start = i;
    }
    var n = stop - start;

    // Adjust t to be in the range [0, 1).
    var t0 = points[start].time, t1 = points[stop].time;
    t = (t - t0) / (t1 - t0);
    var tInv = 1 - t;

    // Now calculate the current position in the curve.
    // Wikipedia says this is:
    //   sum for i = 0 to n of (n C i * (1 - t) ^ (n - i) * t ^ i * P[i])
    // 
    var x = 0, y = 0;
    for (var i = 0; i <= n; i++) {
        var p = points[start + i];
        var c = nCr(n, i) * Math.pow(1 - t, n - i) * Math.pow(t, i);
        x += c * p.x;
        y += c * p.y;
    }
    return {x: x, y: y};
}

// The number of k-combinations of a set of size n.
function nCr(n, k) {
    var z = 1;
    for (var i = 1; i <= k; i++)
        z *= (n + 1 - i) / i;
    return z;
}

这就是数学部分。你可以把它连接到画布上然后就可以了。

以下是您调用该方法的方法:

// Here's a Path consisting of a single Bezier curve.
var path = new Path([
    {x: 200, y: 150, time: 0},  // start point
    {x: 200, y: 500},           // 2 control points
    {x: 250, y: 100},
    {x: 500, y: 300, time: 50}  // end point
  ]);

var p = path.getXYAtTime(2.718);
alert(p.x + ", " + p.y);

答案 1 :(得分:0)

贝塞尔曲线的控制点实际上正是通过在每个端点处向端点添加所需的速度矢量而得到的。例如,如果您想要速度vx0,vy0在点x0,y0然后前进到点x1,y1以速度vx1,vy1到达那里,那么使用以下四个点来定义贝塞尔曲线:(x0,y0); (x0+vx0,y0+vy0); (x1-vx1,y1-vy1); (x1,y1)。 (中间两个是你的控制点。)