打造高大上的Canvas粒子動畫

LouanneY23 8年前發布 | 12K 次閱讀 設計 前端技術

首先來看下我們準備要做的粒子動畫效果是怎么樣的~

是這樣:

或者是這樣:

甚至是這樣:

很酷炫!

那如何去實現類似上面的粒子動畫甚至根據自己的喜好去做更多其他軌跡的動畫呢~請看下面詳細的講解。

技術選擇

因為粒子數量很多,而且涉及到圖像像素處理,所以這里使用 Canvas 是不二選擇。

注意,以下演示的代碼只是關鍵代碼,重點在于解決思路。

一、繪制粒子輪廓圖

首先要在canvas畫布上繪制一個由粒子組成的輪廓圖,記錄下每一個粒子的坐標,這樣才能有后續的動畫。

1. 創建一個<canvas>元素,并獲取Canvas畫布渲染上下文

< canvas>是一個雙標簽元素,通過width和height的值來設置畫布的大小。至于ctx(畫布渲染上下文),可以理解為畫布上的畫筆,我們可以通過畫筆在畫布上隨心所欲的繪制圖案。如果瀏覽器不支持canvas會直接顯示<canvas>標簽中間自己設定的文字。當然 <canvas> 標簽中間也可以是一張當不支持canvas時需要替換顯示的圖片。

2. 使用canvas的圖像操作API繪制圖像

繪制圖像的關鍵API及參數說明:

引用MDN上的一張圖會比較清晰的看出每個參數的作用:

drawImage就是把一個image對象或者canvas上(甚至是video對象上的的每一幀)指定位置和尺寸的圖像繪制到當前的畫布上。而在我們的需求中,是要把整個圖像繪制到畫布中。

對應瀏覽器看到的 效果

3. 獲取圖像的像素信息,并根據像素信息重新繪制出粒子效果輪廓圖

canvas有一個叫getImageData的接口,通過 該接口可以獲取到畫布上指定位置的全部像素的數據:

把獲取的imageData輸出到控制臺可以看到,imageData包含三個屬性:

其中,width、height是讀取圖像像素信息完整區域的寬度和高度,data是一個Uint8ClampedArray類型的一維數組,包含了整個圖片區域里每個像素點的RGBA的整型數據。這里必須要理解這個數組所保存像素信息的排序規則,請看下圖描述的data數組:

每一個色值占據data數組索引的一個位置,一個像素有個4個值(R、G、B、A)占據數組的4個索引位置。根據數列規則可以知道,要獲取第n個位置(n從1開始)的R、G、B像素信息就是:Rn = (n-1)*4 ,G n = (n-1)*4+1 ,B n = (n-1)*4+2  ,so easy~  當然,實際上圖像是一個包括image.height行,image.width列像素的矩形而不是單純的一行到結束的,這個n值在矩形中要計算下:

由于一個像素是帶有4個索引值(rgba)的,所以拿到圖像中第i行第j列的R、G、B、A像素信息就是 Rij = [(j-1)*imageData.width + (i-1)]*4 ,G ij = [(j-1)*imageData.width + (i-1)]*4 + 1, B ij = [(j-1)*imageData.width + (i-1)]*4 + 2,A ij = [(j-1)*imageData.width + (i-1)]*4 + 3  。每個像素值都可以拿到了!

接下來就要把圖像的粒子化輪廓圖畫出來了。那么,怎么做這個輪廓圖呢,我們先讀取每個像素的信息(用到上面的計算公式),如果這個像素的色值符合要求,就保存起來,用于繪制在畫布上。另外,既然是做成粒子的效果,我們只需要把像素粒子保存一部分,展示在畫布上。

具體做法是,設定每一行和每一列要顯示的粒子數,分別是cols和rows,一個粒子代表一個單元格,那么每個單元格的的寬高就是imageWidth/cols和imageHeight/rows,然后循環的判斷每個單元格的第一個像素是否滿足像素值的條件,如果滿足了,就把這個單元格的坐標保存到數組里,用作后續繪制圖案用。

關鍵參考代碼:

用完整代碼做出的demo及 效果 :

至此,粒子輪廓圖已經制作完成。

二、制作粒子動畫

制作粒子動畫分兩種:

一種是粒子漂浮類,這種比較簡單,只需要隨機的改變每個粒子的位置值,然后一直執行setInterval或者requestAnimationFrame重繪畫布即可,具體的效果因人喜好而去設定,就不具體講解了,做了個簡單的粒子漂浮的 例子 。

另一種是粒子的軌跡動畫,這個相對復雜一些。這里要介紹的是每個粒子按照指定的軌跡在指定的時間內做位移,最終匯聚成指定圖案的動畫效果(也就是文章一開始的動效),要做成這類動畫效果需要解決兩個問題:一個是動畫軌跡,另外一個是每個粒子執行動畫的時機。

粒子動畫軌跡

動畫位移的軌跡,最常見的就是單位時間內改變固定的位移值,從而達到動畫效果。但要做到炫酷的效果依賴這種單調固定的位移肯定是不行的。所以位移可以依賴緩動函數去做到單位時間內改變不一樣的位移值,從而達到特別的效果。

制作緩動效果有兩種方法:

一種是自己設定好控制點,然后通過貝塞爾曲線公式來計算每個單位時間的坐標值。

引用了 wikipedia 里面的圖:

上面兩個圖都是在繪制一條特定曲線,可以看出二次曲線需要一個特定控制點P1,三次曲線需要兩個特定控制點P1和P2來確定一條曲線,高階曲線甚至需要更多的控制點來確定曲線軌跡。

求曲線的公式是根據 德卡斯特里奧算法 計算得來的,直接上公式。

二次曲線對應的公式:

三次曲線對應的公式:

從公式可以看出,只要確定控制點坐標、起始坐標和終點坐標后,就可以確定了一條曲線,然后就可以根據曲線公式求出每個時刻t對應的位置值B(t)。

當然使用這種方法需要自己去制定控制點坐標,計算也比較復雜,實現起來很繁瑣。沒事,我們還有別的辦法確定曲線。

另外一種方法就是使用已有的緩動函數,不需要自己制定控制點,這里推薦出名的Tween算法的 緩動函數 ,用其中一個緩動函數來介紹下參數值,其他緩動函數所傳的參數值是一樣的:

是不是覺得很熟悉?對沒錯,jquery用的動畫擴展插件 easing.js 就是Tween算法的緩動函數。有了這現成的緩動函數,就可以制定粒子的起始點、終點(終點就是圖案本身的坐標位置)以及動畫執行持續時間來做我們要的 效果。

關鍵參考代碼:

根據參考代碼做出一個 效果 :

嗯,動畫效果是有了,但總感覺不太對勁。。。唔,仔細觀察一下,是圖案動畫執行太過整體了,沒有明顯的顆粒動畫效果,這就引出粒子動畫的另一個關鍵點,粒子執行動畫的時機。

粒子執行動畫的時機

要讓粒子效果比較明顯,那就不能讓動畫效果執行太過整體了,需要讓圖案上每個粒子有不同的時間間隔啟動,根據一定的規律交錯的執行動畫。這里的粒子啟動間隔有兩種,一種是每一行粒子執行時間間隔,要讓每一行的粒子啟動時間有規律錯開;另外一種是每一行粒子之間啟動時間隨機的錯開,這樣執行的粒子動畫才會有一種層次感和每個粒子有獨立動畫的顆粒感。看下加了粒子啟動時間間隔之后的 效果 對比 :

比上面不加粒子啟動時間間隔的效果好多了。

嗯,介紹差不多就是這樣了,如果上面介紹的方法還是解決不了問題的話,還有辦法。。。我把粒子動畫效果和Tween的緩動函數一起封裝了一下。直接配置一下就可以用了。 用法就是創建一個帶有id的canvas,設定好寬度和高度,引入 particle.min.js ,然后配置一下參數即可,  demo :

 

來自:https://isux.tencent.com/canvas-particle-animation.html

 

 本文由用戶 LouanneY23 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!