動態

詳情 返回 返回

掌控物體運動藝術:圖撲 Easing 函數實踐應用 - 動態 詳情

現如今,前端開發除了構建功能性的網站和應用程序外,還需要創建具有吸引力且尤為流暢交互的用户界面,其中動畫技術在其中發揮着至關重要的作用。在數字孿生領域,動畫的應用顯得尤為重要。數字孿生技術通過精確模擬現實世界中的對象、過程和系統,對動畫的需求遠遠超過傳統前端開發。

在這種環境中,動畫不僅僅是為了美觀,更是用於實現系統與現實的同步、演示覆雜過程和數據可視化的關鍵手段。

HT 動畫介紹

在足夠短的時間內快速連續地改變物體的某個屬性,人的眼睛會感知到物體在平滑移動,這種利用人類視覺持續性產生的效果就是動畫。圖撲自研 HT for Web 產品中提供了多種創建動畫方式,其中很常見的是使用 ht.Default.startAnim 創建動畫

ht.Default.startAnim 支持兩種動畫模型:Frame-Based 和 Time-Based。這兩種類型的動畫所需的參數各不相同:

Frame-Based 幀動畫具有固定的幀數,即 action 被調用的次數,創建動畫時需傳入一下參數:

  • frames:動畫的幀數。
  • Interval:動畫幀間隔毫秒數。
  • easing:動畫緩動函數,默認為 ht.Default.animEasing。
  • finishFunc:動畫完成後的回調函數。
  • action:必須提供 action 函數,用於實現動畫過程。第一個參數代表通過 easing 函數運算後的值,第二個參數代表當前動畫進度(0~1)。

Time-Based 週期動畫,動畫幀數(action 的調用次數)取決於系統環境,創建動畫需要傳入的參數:

  • duration:動畫週期的毫秒數,默認使用 ht.Default.animDuration。
  • easing:動畫的緩動函數,默認使用 ht.Default.animEasing。
  • finishFunc:動畫結束時的回調函數。
  • action:必須提供 action 函數,用於實現動畫過程。


以小球落地過程為例,只需在動畫過程中不斷調整小球的位置屬性,就能實現小球落地的動畫效果:

const ball = dm.getDataByTag('ball'); // 獲取小球節點
const elevation = ball.getElevation(); // 獲取小球節點縱向位置
ht.Default.startAnim({
    duration: 1500, 
    easing: t => t,
    finishFunc: function () { }, 
    action: function (v, t) {
        ball.setElevation(elevation - elevation * v); // 在動畫中調整節點縱向位置
    }
});

在上圖中,小球的落地動畫效果已實現,但動畫看起來仍顯得有些生硬。這是因為在現實中,小球落地是加速運動的,並且當小球接觸地面後,受力變化會導致回彈。因此,我們還需要在動畫中控制小球的速度和運動趨勢,以便更真實地模擬這一過程。

那麼如何在動畫中控制速度呢?

這就需要引用下面的 easing 函數使用。

關於 Easing 函數

Easing(緩動函數)是用於調整動畫速度的函數,它們定義了動畫在開始、進行中和結束時的速度變化。這些函數允許動畫以非線性方式運行,使動畫效果更自然、流暢和有吸引力。緩動函數在座標軸中的表現可以看作是一個以時間(t)為橫軸、值為縱軸的圖表。以下附圖展示了一些常用的 easing 函數,從圖中可以清晰地看到不同 easing 的變化趨勢。

瞭解了 easing 函數的作用後,我們可以通過調整它來實現小球落地時的加速運動以及接觸地面後的回彈效果。

ht.Default.startAnim({
    duration: 1500,
    easing: function (t) {
        const n1 = 7.5625;
        const d1 = 2.75;
        if (t < 1 / d1) {
            return n1 * t * t;
        } else if (t < 2 / d1) {
            return n1 * (t -= 1.5 / d1) * t + 0.75;
        } else if (t < 2.5 / d1) {
            return n1 * (t -= 2.25 / d1) * t + 0.9375;
        } else {
            return n1 * (t -= 2.625 / d1) * t + 0.984375;
        }
    },
    finishFunc: function () { }, 
    action: function (v, t) {
        ball.setElevation(elevation - elevation * v);
    }
});

在實際項目中,物體的運動通常較為複雜,因此我們需要根據不同的運動類型選擇合適的 easing 函數。以下示例展示了在場景內的節點進行不同運動時,不同 easing 函數所產生的效果。

大家也可以該通過鏈接進行操作感受,通過切換不同的 easing 函數將呈現出不一樣的動畫效果:https://hightopo.com/demo/easing_animation_demo/ 。

示例展示了多個動畫的連續播放效果。 我們可以在動畫的 finishFunc 回調結束時,調用下一個動畫,從而實現連續的動畫效果。

ht.Default.startAnim({
    duration: 1500,
    easing: function (t) {    ......},
    action: function (v, t) { ...... },
    finishFunc: function () {
        // 調用下一個動畫        
        ht.Default.startAnim({            
            ......        
        })    
     }, 
});

總結

常聽人説 Easing 是動畫的靈魂,就如同生命的節奏。有些人厚積薄發,有些人平穩一生,而也有些人起起伏伏,經歷着高山低谷的跌宕起伏。無論過程如何多樣精彩,終點都是一致的——正如動畫中無論怎樣變化的 Easing 曲線,最終都通向同一個終點幀。動畫和人生一樣,豐富的過渡和變化,賦予它們獨特的美感和深意。

user avatar steven_code 頭像 pantao 頭像
點贊 2 用戶, 點贊了這篇動態!
點贊

Add a new 評論

Some HTML is okay.