週末長知識: Google的彈指特效小研究

隨著「復仇者聯盟:終局之戰」的上映,Google 在和薩諾斯與無限手套相關的搜尋結果頁面加了一個灰飛煙滅的特效:

google_thanos_effect

特效被發現後引起了各界熱烈的討論,所以這週末的長知識就來蹭個熱度,看一下灰飛煙滅的特效是如何完成的。

將元素轉換為圖片

其實這個特效很直覺就認為有用 html2canvas,因為需要作出後續的類粒子特效,明顯需要是用圖片下去操作。

稍微用 Chrome devtools 追查一下之後就可以看到 html2canvas 的蹤跡:

1556430899758

1556430910104

粒子效果

如果在特效運作的時候觀察一下 DOM 的狀態,會發現似乎有大量的 canvas 被塞進來。深入追查特效本體的區塊,不像一般的粒子特效會有比較多粒子相關的運算,Google 這個特效的程式碼相對簡潔。

1556431244196

這個粒子效果其實是用一個比較平民的方法達成: 用 canvas 層層疊 + CSS transition 。

在動畫進行中的 Layer view 截圖是長這樣:

螢幕快照 2019-04-26 下午5.42.58

層層疊的學問

已經知道了原理是層層疊起來,是不是後面就簡單了?

仔細看一下上面的動畫截圖,可以發現其實它是稍微有 左 -> 右 這樣散開的傾向,而這點其實是需要靠一些巧思來達到的:

  • 多層 canvas 分開負責由左至右的像素
  • 用不同的 transition-delay 來讓動畫由左至右完成
  • 為了粒子效果的隨機性,對原圖取樣的時候也要加入隨機成分

取樣的方法

取樣的方法一樣是從程式碼裡面挖出來:

對所有像素 x, y:
  重複 n 次:
    layer = 隨機選出哪一層(x 值越靠前,層數越靠前)
    完整複製像素到 layer
  • 圖層疊起來一定可以拼出原本的圖
  • n 可以控制視覺上的紮實度,Google 取 2 看起來剛好

用此方法做一維取 8 層,大概會是像這樣:

1556436479412

幾層比較好?

看 code 可以發現 canvas 的數量就是 32 層,照上面的幾點推論下來,理論上層數越多看起來會越自然,當然也相對的越吃效能。

32 層大概是他們權衡效果與效能之後取得的一個最佳數字。

效果重現

把 Google 的版本整理一下,並且讓層數變成可以設定的參數,歡迎大家玩看看不同層數的效果。

如果想要知道對原圖取樣的方法,這個版本的程式碼應該也比打亂過的原版好讀很多。

注意1:使用手機觀看的話,層數過高瀏覽器會直接 crash

注意2:選用的 html2canvas 版本在 Firefox 上的繪製效果會有較大誤差,建議用其他瀏覽器觀看

後記

好久沒寫 blog,這次回來寫有一種力不從心的懶散感 Orz

再接再厲。