2015-12-24 52 views
0

我想創建一個具有相同動畫曲線的自定義動畫,如果我使用的是CAMediaTimingFunction(我在OpenGL中做動畫,所以我無法使用它)。我還想遠離UIKit,因爲我希望它儘可能多平臺。使用立方貝塞爾函數的自定義動畫

CAMediaTimingFunction使用三次Bezier函數從已經過去的時間計算動畫進度。我不知道它是如何做到的。

據我瞭解,三次貝塞爾函數參數化定義,當您試圖從他們那裏獲得笛卡爾式它變成凌亂。

要清楚:我想要一個方法,它接受一個x值輸入並返回一個沿三次貝塞爾曲線的y值輸出。控制點將從(0,0)到(1,1)被限制。

我打算做下面的函數使用參數方程兩​​次每個點(一次x,一旦y)的產生點(如100)的貝塞爾曲線的軌跡,使用到1

static inline CGFloat bezierFunc1D(CGFloat t, CGFloat p0, CGFloat p1, CGFloat p2, CGFloat p3) { 
    return 
    (1-t)*(1-t)*(1-t) * p0 
    + 3 * (1-t)*(1-t) * t * p1 
    + 3 * (1-t) * t*t * p2 
    + t*t*t * p3; 
} 

100個值的t0這是p0通過到p3是控制點和t是參量的標量從01。我可以通過預先計算t的平方和立方值來相當容易地對此進行優化。

然後,我要使用線性插值來生成一個點陣列,其中x的值是線性分離的(例如x = 0.01, 0.02... 0.99),然後使用此數組來定義我的動畫進度。

這是要去了解這個問題的最好方法是什麼?對於一個非常簡單的任務來說,這似乎是一個相當密集的過程,儘管它可能都是在啓動時預先計算好的。

我上this question看到回答者建議簡單地刪除x和定義功能yt但是,這會給出非常不準確的結果,因爲從0.01.0的線性貝塞爾曲線不會線性生成動畫。

有沒有更有效的方法呢?

有誰知道蘋果在CAMediaTimingFunction如何實現這個還是有一個圖書館,在那裏,獲得相同的結果呢?

還是有使用三次貝塞爾函數,這將使在兩個進出動畫的階段的平滑動畫曲線簡單的替代方案?

+0

這聽起來像你的問題基本上是,退房http://stackoverflow.com/a/26131682/ 77567和http://stackoverflow.com/a/17227585/77567和http://stackoverflow.com/a/13667092/77567 –

+0

那麼這些問題集中在使用'CGPath'繪製貝塞爾曲線。我很抱歉,如果我沒有在問題中明確表達出來,但是我想盡可能遠離UIKit,因爲我在OpenGL中這樣做,並希望它像多平臺一樣可能。也沒有一個實際上幫助獲得Bezier曲線的一組線性值(你不能從CGPath中讀取一組點,你只能沿着它進行渲染)。 – Hamish

+1

如果您需要多平臺答案,您應該從標籤中取出'ios'。順便說一句,那些答案** do **使用'CGPathCreateCopyByDashingPath'複製函數沿'CGPath'讀取一組線性值。 –

回答

2

這是蘋果如何樣的CSS相當於CAMediaTimingFunction WebKit中。感興趣的功能是double solve(double x, double epsilon),它返回yx ± epsilon

/* 
* Copyright (C) 2008 Apple Inc. All Rights Reserved. 
* 
* Redistribution and use in source and binary forms, with or without 
* modification, are permitted provided that the following conditions 
* are met: 
* 1. Redistributions of source code must retain the above copyright 
* notice, this list of conditions and the following disclaimer. 
* 2. Redistributions in binary form must reproduce the above copyright 
* notice, this list of conditions and the following disclaimer in the 
* documentation and/or other materials provided with the distribution. 
* 
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/ 

#ifndef UnitBezier_h 
#define UnitBezier_h 

#include <math.h> 

namespace WebCore { 

    struct UnitBezier { 
     UnitBezier(double p1x, double p1y, double p2x, double p2y) 
     { 
      // Calculate the polynomial coefficients, implicit first and last control points are (0,0) and (1,1). 
      cx = 3.0 * p1x; 
      bx = 3.0 * (p2x - p1x) - cx; 
      ax = 1.0 - cx -bx; 

      cy = 3.0 * p1y; 
      by = 3.0 * (p2y - p1y) - cy; 
      ay = 1.0 - cy - by; 
     } 

     double sampleCurveX(double t) 
     { 
      // `ax t^3 + bx t^2 + cx t' expanded using Horner's rule. 
      return ((ax * t + bx) * t + cx) * t; 
     } 

     double sampleCurveY(double t) 
     { 
      return ((ay * t + by) * t + cy) * t; 
     } 

     double sampleCurveDerivativeX(double t) 
     { 
      return (3.0 * ax * t + 2.0 * bx) * t + cx; 
     } 

     // Given an x value, find a parametric value it came from. 
     double solveCurveX(double x, double epsilon) 
     { 
      double t0; 
      double t1; 
      double t2; 
      double x2; 
      double d2; 
      int i; 

      // First try a few iterations of Newton's method -- normally very fast. 
      for (t2 = x, i = 0; i < 8; i++) { 
       x2 = sampleCurveX(t2) - x; 
       if (fabs (x2) < epsilon) 
        return t2; 
       d2 = sampleCurveDerivativeX(t2); 
       if (fabs(d2) < 1e-6) 
        break; 
       t2 = t2 - x2/d2; 
      } 

      // Fall back to the bisection method for reliability. 
      t0 = 0.0; 
      t1 = 1.0; 
      t2 = x; 

      if (t2 < t0) 
       return t0; 
      if (t2 > t1) 
       return t1; 

      while (t0 < t1) { 
       x2 = sampleCurveX(t2); 
       if (fabs(x2 - x) < epsilon) 
        return t2; 
       if (x > x2) 
        t0 = t2; 
       else 
        t1 = t2; 
       t2 = (t1 - t0) * .5 + t0; 
      } 

      // Failure. 
      return t2; 
     } 

     double solve(double x, double epsilon) 
     { 
      return sampleCurveY(solveCurveX(x, epsilon)); 
     } 

    private: 
     double ax; 
     double bx; 
     double cx; 

     double ay; 
     double by; 
     double cy; 
    }; 
} 
#endif 

來源:「?我怎麼樣沿貝塞爾三次曲線等距點」 https://github.com/WebKit/webkit/blob/67985c34ffc405f69995e8a35f9c38618625c403/Source/WebCore/platform/graphics/UnitBezier.h

+0

哇,正是我所期待的!感謝你的幫助。 – Hamish