2016-03-25 85 views
2

當循環縮放動畫時,線性時間不會感覺線性,但開始時相當緩慢,結束時很快。計算線性縮放的貝塞爾曲線

你將如何去計算正確的曲線? 如果您需要更多信息,請在評論中提問。

在這支筆中,我使用手繪曲線來嘗試解決這個問題,因爲我顯然太愚蠢以找出邏輯。

http://codepen.io/pixelass/pen/qZjBQy

// mathematically correct curve ? 
@function linear-zoom() { 
    // add your code here 
    $sx: 0; 
    $sy: 0; 
    $ex: 1; 
    $ey: 1; 
    $curve: ($sx, $sy, $ex, $ey); 
    @return $curve; 
} 

zoom hack

+0

手動調整參數和觀察目標是否看起來不錯,有什麼問題?這實際上是獲得「感覺正確」的唯一方法 - 數學無法告訴你一般人會遇到什麼樣的「最平滑的遍歷」(事實上,如果你是A/B測試這個) –

+0

@ Mike'Pomax'Kamermans我認爲我最感興趣的是它背後的邏輯。 – pixelass

+0

看過http://cubic-bezier.com?或者,如果你想要很多邏輯,https://pomax.github.io/bezierinfo? –

回答

3

您正在使用的尺度參數是二的倍數,所以當你使用線性動畫速度線性比例增加,但距離增加對數。

讓我們看看一些數字。首先,我們從規模到0.5一個2一圈,於是兩個的log 2步:

t=0 => scale(0.5) 
t=0.25 => scale((0.75 * 0.5 + 0.25 * 2)) = scale(0.875) 
t=0.5 => scale((0.5 * 0.5 + 0.5 * 2)) = scale(1.25) 
t=0.75 => scale((0.25 * 0.5 + 0.75 * 2)) = scale(1.625) 
t=1 => scale(2) 

所以看起來起點和終點之間的大,線性過渡。我們可能認爲這意味着我們可以添加更多的圈子來做同樣的事情,但如果我們做到了,我們最終會得到對數行爲。讓我們看看爲什麼:假設我們添加一個縮放0.251

t=0 => scale(0.25) 
t=0.25 => scale((0.75 * 0.25 + 0.25)) = scale(0.4375) 
t=0.5 => scale((0.5 * 0.25 + 0.5)) = scale(0.625) 
t=0.75 => scale((0.25 * 0.25 + 0.75)) = scale(0.8125) 
t=1 => scale(1) 

似乎好:在每一個時間間隔,大圓的半徑是小了一圈兩次......但是這你想要什麼,因爲這也意味着,在較小的圓上一點在大圓上的一個點移動兩倍的距離(1.5個單位)時,只移動0.75個單位。我們看到一個簡單的2^t公式後,一個圓圈開始越大,它在屏幕上移動得越快。

爲了抵消這種情況,您希望補償特定的對數增長,因爲參數不同,所以獨立於每個動畫。獲得一條單曲貝塞爾曲線來完成所有曲線在數學上是不可能的,但由於人類並不是完美的數學機器,因此您可以像屏幕一樣在一小部分屏幕上擺脫它 - 爲任何啓動「正確」 /結束參數集ab您需要設置一個貝塞爾曲線,該曲線在間隔t=[a,b]上近似於函數1/(2^t),這並不好玩:我們需要用貝塞爾曲線在特定間隔上近似series for 1/2^x up to order 2,然後使用這個座標給我們提供了三次簡化參數。

有兩種方法可以做到這一點 - 要麼找到一個貝塞爾曲線,從您的全局最小值到最大值找到最適合的函數,然後使用曲線分割來查找每個子區間的參數,或者找到每個子區間的貝塞爾曲線單獨的間隔。第一個(稍微)更容易,但由於1/2^x的低階系列近似而容易出錯,第二個更好,但工作量很大,所以如果您想了解如何做到這一點,math.stackexchange.com是獲取更好的地方到這裏真正的數學底部。

大多數程序員將能夠使用的「Stackoverflow答案」是爲自己構建一個「某些間隔的某些曲線」的查找表,然後使用它們之間的插值來處理間隔位於間隔之間某處的間隔你曾經建立LUT:使用任何一種語言繪製間隔圖,然後只用cubic-bezier.com這樣的圖來覆蓋這個圖,然後通過目測控制點找到每個圖的「非常合適」。比如說,你使用了10個間隔時間,而且你很好。

這是肯定的少數學,你不能「節目」該解決方案作爲一個通用的解決方案,但它高效:從用戶感知的角度來看,這個解決方案應該已經足夠多好感覺光滑。

+1

或者只是乘以(或重複)除以0.97。 –

+1

@ArifBurhan雖然正確,但對於找到Bezier適合每個區間並不是非常有用,因爲您仍然需要近似*那個*函數(CSS,由於我不太瞭解的原因,沒有自定義緩動函數如果是的話,這會很容易,你只需要一個'(t,a,b)=> 1 /(2^lerp(t,a,b))'數字發生器) –

+0

個別的lerps會讓你想出一個體面的Bezier,但是你可能想要做一個控制點的圖表來逼近特定的時間間隔(給你兩條他們需要通過的線),然後看看你是否可以很容易地表達函數對於他們來說,按照區間起始值。如果是這樣,這也是一種非常穩定的方法,可以始終獲得正確的參數。 –