2024 抖音歡笑中國年之Wasm、WebGL 在互動技術中的創新應用
前言
隨著 Web 前端技術的不斷發展,越來越多的新興技術方案被引入到 Web 開發中,其中 Wasm 和 WebGL 作為前端領域的兩大利器,為開發者帶來了更多的可能性。
本文將結合2024 年抖音歡笑中國年的部分項目,重點介紹如何利用 Wasm 和 WebGL 對目前流行的一些前端互動技術(比如 Lottie、渲染引擎、動畫圖片等)進行創新和實踐,利用 Wasm 和 WebGL 等新技術方案的特性和優勢提升業務性能和流暢度,給用戶帶來更好的體驗。
Simple 渲染引擎
WebAssembly(Wasm)是一種可以在 Web 瀏覽器中運行,提供比 JavaScript 更高的性能,并且支持多種編程語言的全新的字節碼格式;基于其高性能的優勢,我們團隊嘗試將其應用到渲染場景中,推出了基于 Wasm + WebGL 的高性能、輕量化的 Simple 渲染引擎。
以期借助于 Wasm 的高性能計算,以 Simple 引擎為基礎,保持輕量化的同時,解決目前前端動效和輕互動場景主流技術方案如 Lottie 動畫、動畫圖片(序列幀、 Apng 、WebP)、JS 渲染引擎等存在的能力受限、資源體積大、性能較低等問題。
引擎架構
考慮到前端用戶學習和使用成本,Simple 引擎使用 TypeScript 語言開發上層接口,主要是利用 TS 封裝簡單對象,同時做類型提示方便前端用戶使用,另外還提供盡可能高性能的方式和 Wasm 進行交互;底層則使用 C/C++,主要處理計算工作,比如:矩陣計算、圖形計算、動畫計算、動態合批等;
Simple 引擎目前的渲染管線主要以 2D 為主,也分為兩部分:JS 部分負責處理數據量少但是 GL 調用頻繁的操作,Wasm 部分則相反負責處理數據量多但是 GL 調用少的操作,盡可能達到性能最優解。
整體架構如下:
性能收益
受益于 Wasm 的計算性能優勢,Simple 引擎相比主流的 JS 渲染引擎,比如:PixiJS 6.3、Cocos 2.4 在 Spine 動畫、精靈旋轉、精靈跳動、圖形水平移動等基準性能測試場景中取得了不俗的表現:
以上測試數據來自 Android OPPO Find X1 抖音 跨端框架 V8 環境,可以看到基于 Wasm 的 Simple 引擎相比基于 JS 的引擎性能提升明顯,計算任務越復雜,性能收益越大。
計算任務復雜度:骨骼動畫 > 圖形計算 > 旋轉變換 > 位移變換
測試代碼
100 個 Spine 動畫 Simple 和 Cocos 2.4 測試代碼如下:
- Cocos 2.4
- Simple
兼容性
從 2015 年 Wasm 項目正式啟動到現在,經過多年的發展 Wasm 規范不斷完善和擴展,目前主流的瀏覽器已經全面支持 Wasm 技術;同時 Simple 引擎最早在 2022年7月啟動,之后在直播、財經、頭條、音樂、小說等多個業務場景中落地,并在 2024 年初獲得了在春節項目中應用的機會。
從數據來看抖音跨端框架中使用 Wasm 的用戶占比高達 96.97% ,對于不支持 Wasm 的情況也可以使用 Simple 引擎編譯的 asm.js 版本來進行降級。
經過一年多的反復實踐與驗證,總得來說 Simple 引擎兼容性表現穩定可靠。
Lottie WebGL 渲染
Lottie WebGL 渲染是利用上文提到的 Wasm + WebGL 渲染引擎去渲染 Lottie 動畫的方案,在幾乎完美還原 Lottie 動畫的基礎上,利用引擎封裝好的相關機制(事件、渲染對象)擴展 Lottie 動畫的交互控制能力,豐富其特性支持,以及基于 Wasm + WebGL 渲染提升動畫性能。
性能收益
Lottie 是動畫 Airbnb 公司開源的跨平臺動畫框架,支持將 AE 中設計的動畫導出為 Json 協議,是前端最流行的動畫協議;但是在 Web 上官方只提供了三種渲染方式(SVG、Canvas 2D、HTML),并沒有支持 WebGL:
而前端最流行的那些 JS WebGL 渲染引擎也沒有直接支持 Lottie 動畫,這就會帶來三個問題:
官方渲染方案性能低
SVG、HTML 不適合處理大量元素的動畫,而 Canvas 2D 的使用方式決定了它很難充分利用緩存機制,因此官方提供的這三種渲染方案其實性能是偏低的,會在較多、較復雜動畫場景遭遇性能瓶頸。
如上圖所示某 Lottie 動畫在 Chrome 6 倍降速模擬移動端設備的性能表現,Lottie SVG 每幀耗時 5.77 毫秒,而 Simple Lottie 每幀耗時僅 1.10 毫秒,性能提升近 6 倍。
離屏 Canvas 渲染性能低
目前主流的 JS WebGL 渲染引擎只能使用離屏 Canvas 的方式去渲染 Lottie 動畫,這種方式需要先創建一個離屏的 Canvas 然后用 Lottie 官方提供的 Canvas 2D 方式把動畫的當前狀態渲染到離屏 Canvas 中,接著再把這個離屏的 Canvas 用紋理的方式上傳到 GPU,如果動畫更新還需要重復這個流程。
相對復雜的渲染流程會導致其性能較低:
如上圖所示,12 * 18 個 Lottie 動畫在 i7 Mac Chrome 上測試,右側 WebGL 直接渲染 Lottie 動畫比左側離屏 Canvas 渲染幀數高了 35 fps,性能提升近 3 倍。
JS 圖形計算性能低
提升 Lottie 動畫性能,除了要考慮渲染性能,還需要考慮計算性能,比如上面兩個例子中的 Lottie 動畫更多是圖片元素,但是矢量圖形也是 Lottie 動畫中非常重要的功能。
如果基于目前主流的 JS WebGL 渲染引擎去渲染 Lottie 動畫,在以矢量圖形為主的 Lottie 動畫中對比 Lottie 官方提供的 SVG 或者 Canvas 甚至會出現性能劣化的情況:
可以看到左側 SVG 在動畫峰值每幀僅需 6.26 毫秒,而右側 PixiJS 在動畫峰值每幀需要 11.68 毫秒。
基于 JS WebGL 渲染引擎渲染 Lottie 動畫在矢量圖形場景出現性能劣化最主要原因在于 SVG 的計算在瀏覽器封裝的 Native 模塊中進行,而 JS WebGL 渲染引擎的計算在 JS 中進行,哪怕是幾乎優化到極致的 PixiJS 受限于 JS 也只能在圖片元素等部分 Lottie 動畫中取得性能優化收益;因此只有采用 Simple 引擎這種 Wasm + WebGL 的方案才能徹底、全面優化 Lottie 動畫的性能:
相同場景 Simple Lottie 在動畫峰值每幀僅需 5.35 毫秒(這其中還包含了 JS 動畫參數插值計算部分,后續這部分 JS 計算也下沉 Wasm ,整體估計還能優化 1 毫秒 )。
交互控制
使用 Simple 引擎直接去渲染 Lottie 動畫,除了性能上的收益之外,還利用引擎提供的能力增加了很多交互控制上的便利,比如:素材替換、事件監聽、動畫混合、文字變更、物理碰撞等等。
在 2024 年春節群紅包雨項目中幾乎全部的素材都是 Lottie 動畫素材:
靜態的 Lottie 素材結合 Simple Lottie 提供的動態交互能力就可以很方便的實現諸如紅包點擊、紅包動態紋理、點中動畫動態文字、大紅包點擊、連擊動畫動態數字等等。
舉個例子,用戶點中紅包雨之后需要播放一個動畫,整體是一個煙花的效果,需要隨機展示不同的文字:
對于這個需求,設計同學只需要提供一個固定的 Lottie 動畫,然后再提供一些其它的文字素材;開發則需要在代碼中首先從動畫中查找到文字精靈,然后隨機選取一張文字紋理,最后更新文字精靈的紋理即可。
特性支持
使用 Simple 引擎去渲染 Lottie 動畫,還能在原有 Lottie 特性支持的基礎上增加更多的能力。比如從動畫素材上來說我們可以把原始 Lottie 動畫產物中零散的圖片合成一張雪碧圖,減少資源請求數量,減少紋理個數,提升渲染性能:
左側是散圖,右側是雪碧圖。除此之外甚至還能把圖片轉成壓縮紋理,減少內存占用和加快渲染速度。
除了動畫素材上的優化,還能給 Lottie 動畫增加更多的渲染效果,比如:
粒子
濾鏡
Simple 引擎通過 Shader 實現了很多常用的濾鏡效果,比如:
左側是模糊效果、右側是顏色卷積效果。
自定義效果
基于 Simple 引擎提供的 WebGL 能力封裝,還可以實現更多更豐富的自定義效果,比如:透明視頻以及下面將要介紹 WebGL 幀差序列幀。
WebGL 幀差序列幀
幀差序列幀是一種基于 WebGL 1.0 標準的動畫圖片規范,由首幀圖片、幀差圖片(不透明幀差、半透明幀差)、幀差配置信息組成,一般包含 4 個文件:
背景
由于原始 Lottie 動畫只支持少部分 AE 特性,對于不支持的特性設計師往往會把這些效果轉成序列幀實現,這就會導致動畫素材產物體積增加。而另一方面目前常用的視頻、Apng、WebP 這些主流素材又各有各的問題,比如:
- 視頻存在兼容性問題、不能交互、對低端機來說存在一定的性能壓力;
- Apng、WebP 這些傳統動畫圖片格式基本沒怎么考慮幀間壓縮:
上圖是一張 Apng 解碼后的信息,IDAT 表示首幀、fdAT 表示后續幀,可以看到后續幀和首幀幾乎一樣大,也就是說對于這個素材生成的 Apng 效果和簡單拼接的原始序列幀差不多。
資源體積優化
基于上述現狀,如果能基于兼容性最好的 WebGL 1.0 標準去實現一些類視頻的簡單自定義幀間壓縮算法, 就能在動畫場景以更小的資源體積完美替代序列幀、 Apng 、 WebP 。
對于一般素材幀差序列幀在體積上相比序列幀、 Apng 、 WebP 會減少 50% 左右。
交互能力
幀差序列幀還能以更高的性能和提供任意時刻切任意幀的能力,實現一定的交互能力,從而滿足一些輕互動場景的需求,對視頻和 3D 模型形成差異化優勢。
我們以小火人、打年獸和徽章項目為例:
- 小火人、年獸的動畫狀態是會隨著用戶的操作發生變化的,而視頻是很難實現無縫的幀切換;
- 徽章需要 360 度旋轉展示,同時還需要響應用戶的滑動操作,一般情況下這里只能使用 3D 模型,那么整個項目就得以傳統 3D 項目的流程去做,一方面成本會高出很多,另一方面考慮實時渲染性能壓力,效果上可能還做不到百分百還原。而采用幀差序列幀的方案去做,項目成本就會低很多,同時效果上也不會有任何折扣。
未來展望
以上即是我們團隊在 Wasm 和 WebGL 上的一些嘗試與思考,雖然取得了一定的突破,但是方案本身還有很多需要優化和完善的地方:
- Wasm 標準依然在繼續更新,SIMD、線程、垃圾回收、WASI 等新特性會進一步提升性能,同時可能會對現有引擎架構的升級產生很大影響;
- 幀差序列幀目前的幀間壓縮效率只是優于序列幀、Apng、WebP,和視頻相比還有很大差距;在保持現有優勢的前提下怎么更接近視頻是充滿挑戰的問題;
- Lottie 動畫性能得到了優化,增加了很多能力;這些能力怎么高效率的開放給設計和開發去使用,怎么改進現有工作流效率,動效、輕互動的完美工作流需要滿足哪些標準等等。