2009-11-20 92 views
2

我想要定義一個點的路徑。每個點都有一個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 
} 

我想在JavaScript中使用畫布標記實現這一點。然而,任何語言的樣本都可以。有誰知道任何創建這種查詢路徑的開源庫(以任何語言)?

注意:我一直在試着從DynApi project這個樣本和代碼中找到我的頭,但是從這個樣本移動到一個時間感知的路徑對於我可憐的動畫技能來說是一個延伸。

由於

回答

6

Bézier curve不僅具有起點和終點還控制點該引導曲線的形狀。在您鏈接的DynApi演示中,終點標記爲黃色,控制點標記爲紅色。

您的路徑將是一系列貝塞爾曲線,端對端連接。

所以我們來看看你的僞代碼,但我們會把所有的點做對而不是有一個.time屬性作爲控制點。

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); 
+0

哇,非常感謝描述性的答案。我現在感到愚蠢的是,我添加的路徑(點集合)沒有包含任何控制點。 我真的應該提到,我只是想平滑這條道路。因此,我想要生成一個流暢的動畫,通過這些點,而不是一個鋸齒狀的加入點動畫。 我一直在玩弄'猜測'這些控制點的概念,給出了前一點和下一點(2點路徑段),但是這並沒有讓我感到太過分。 Tnx再次爲一個很大程度上描述的響應。 – gatapia 2009-11-20 20:22:40

+0

哦!我不明白你想要什麼,我現在感到很愚蠢。這聽起來像是一個合理的方法,但可能很難猜測這些控制點。你需要弄清楚約束是什麼。例如,在給定點和控制點之前和之後需要排隊。否則,你會在這個點上突然改變方向。 – 2009-11-21 14:26:35

+0

我曾經在這種情況下做過的事情是(a)根據周圍的點來選擇我想要的每個點的速度; (b)給出兩點,以及每個點所需的速度,計算適合賬單的唯一三次函數。在你的情況下,你有一個額外的限制,但是:固定的時間量。 – 2009-11-21 14:33:25

0

貝塞爾曲線的控制點,其實你在每個端點到端點添加所需的速度矢量得到什麼。例如,如果您想要速度vx0,vy0在點x0,y0處,然後進入點x1,y1以速度vx1,vy1到達那裏,然後使用以下四點來定義您的貝塞爾曲線:(x0,y0); (x0+vx0,y0+vy0); (x1-vx1,y1-vy1); (x1,y1)。 (中間兩個是你的控制點。)