腾讯自主研发动画组件PAG开源
PAG (Portable Animated Graphics) 是一套完整的動畫工作流。它提供從AE導(dǎo)出插件,到桌面預(yù)覽工具,再到各端的跨平臺渲染SDK,助力于將AE動畫方便快捷的應(yīng)用于各平臺終端。PAG目前是公司AVGenerator OTeam開源協(xié)同小組的核心組件之一,廣泛應(yīng)用于公司內(nèi)外40余款主流APP或業(yè)務(wù),涵蓋UI動畫、視頻編輯、特效模板、服務(wù)端特效渲染等多個場景,于2022年1月開源至GitHub。
PAG(Portable Animated Graphics)是騰訊自主研發(fā)的一套完整的動畫工作流解決方案,助力于將 AE 動畫方便快捷的應(yīng)用于各平臺終端。和 Lottie、SVGA 相比,支持的 AE 特性更多,支持的平臺更廣(增加了 mac OS、Windows 和 Linux),性能方面也做了深層次的優(yōu)化,支持圖層編輯,可以與視頻編輯場景緊密結(jié)合。目前已經(jīng)廣泛應(yīng)用于公司內(nèi)外幾十款 APP,包括國民級 APP 微信、QQ、騰訊視頻、QQ 音樂、QQ 空間等。
本文將會對 PAG 與 Lottie、SVGA 的工作流程、實現(xiàn)方案、性能等進行對比,并且將會介紹 PAG 特有的一些能力,為一些想要了解或接入 PAG 的開發(fā)同學(xué)提供一些參考。
1、 工作流程
下面將對 Lottie、SVGA、PAG 的工作流程進行對比。
1.1 Lottie 的工作流程
下面是 Lottie 的實現(xiàn)流程圖,設(shè)計師使用 AE 設(shè)計好動畫, 通過 bodymovin 插件將 AE 工程文件導(dǎo)出為 json 文件,在客戶端(使用 Lottie SDK)解析,最后通過各平臺原生渲染方案進行渲染,其中在 Android 平臺上通過 Canvas 進行繪制,在 iOS 上通過 CALayer 進行繪制,在 web 端支持 SVG、Canvas 和 HTML 繪制。
圖1 Lottie工作流程圖rLottie 與 lottie 工作流一致,在 SDK 上實現(xiàn)不一樣,rLottie 沒有使用平臺特定實現(xiàn),是統(tǒng)一 C++實現(xiàn)。
1.2 SVGA 工作流程
SVGA 流程如圖 2 所示,大體流程與 Lottie 類似,使用 SVGAConverter 插件導(dǎo)出,文件是 PB 序列化以后 zip 壓縮的格式,在具體實現(xiàn)上通過設(shè)置幀率來生成一個配置文件,使得每一幀一個配置,每一幀都是關(guān)鍵幀,從而在繪制的過程中不用解析高階插值。SVGA 在 Lottie 方案基礎(chǔ)上進行了優(yōu)化和完善,但是不支持復(fù)雜的矢量形狀圖層和特效。
圖2 SVGA工作流程圖1.3 PAG 的工作流程
PAG 的流程類似 Lottie,設(shè)計師使用 AE 設(shè)計好動畫以后,通過 PAGExporter 插件讀取 AE 工程文件,根據(jù)具體需求選擇矢量導(dǎo)出、BMP 預(yù)合成、混合導(dǎo)出方式中的一種導(dǎo)出一個 PAG 二進制文件,客戶端對該 PAG 二進制文件進行解碼、渲染,各端共享一套 C++實現(xiàn),平臺端只做接口封裝。(導(dǎo)出插件:PAGExporter;桌面預(yù)覽工具:PAGViewer;客戶端渲染 SDK:PAG SDK)
圖3 PAG工作流程圖以上 3 個庫的工作流程大體相似,不同之處在于導(dǎo)出和渲染。
2、 實現(xiàn)方案對比
下面對 Lottie、SVGA 和 PAG 的實現(xiàn)方案進行對比。
2.1 誕生背景
Lottie 最早從UI動畫場景出發(fā)解決矢量動畫渲染的問題,從官方社區(qū)來看,我們能容易發(fā)現(xiàn) Lottie 的矢量基因,社區(qū)作品大多是矢量圖形類動畫。SVGA 是 YY 直播的開發(fā)工程師 2017 年發(fā)布的一套跨平臺動畫解決方案,誕生于直播場景,SVGA 不支持復(fù)雜矢量圖形動畫,對位圖動畫的支持超過 Lottie,其最初的目標(biāo)是為了改善和彌補Lottie。不可否認(rèn),兩者都是業(yè)界優(yōu)化的動畫解決方案。PAG誕生于2016年,最初的原因是為了解決更為復(fù)雜的視頻編輯場景下動畫渲染問題,同時又完美覆蓋了UI動畫和直播場景。
一個有意思的共同點,以上三種方案的作者都有比較豐富的 Flash 相關(guān)背景,都在把Flash完善動畫工作流的實現(xiàn)方式帶到移動端,三者出發(fā)的場景不同,因此實現(xiàn)的方式也會存在一些差異。
2.2 導(dǎo)出插件
Lottie 和 SVGA 都使用 AE Script SDK 來導(dǎo)出 AE 工程,但是 AE Script SDK 本身存在一定限制,不能訪問 AE 文件中的所有屬性,PAG 則使用 AE C++ SDK,能訪問 AE 文件中所有屬性和一些高級 API,能夠?qū)崿F(xiàn)對 AE 文件的完整導(dǎo)出。
2.3 SDK 實現(xiàn)
渲染層面
Lottie 和 SVGA 渲染層面的實現(xiàn)依賴平臺端接口,因此不同平臺會存在支持的 AE 特性有所差異、渲染效果不一致等問題。PAG 渲染層面使用 C++實現(xiàn),所有平臺共享同一套實現(xiàn),平臺端只是封裝接口調(diào)用,提供渲染環(huán)境,因此 PAG 所有平臺支持特性一致,渲染效果一致。rLottie 跟 PAG 類似,底層共享一套 C++實現(xiàn),素材支持 lottie 的 json 文件,矢量渲染性能還不錯,但缺少各平臺封裝,支持的 AE 特性不全,也不支持文本、序列幀等。
渲染緩存層面
Lottie 和 SVGA 依賴平臺端的接口繪制,只能依賴平臺側(cè)接口的渲染緩存,PAG 內(nèi)部有三級緩存機制,從素材結(jié)構(gòu)到渲染結(jié)構(gòu)都有緩存,實現(xiàn)了非常高性能的繪制效率。
文件格式方面
Lottie 導(dǎo)出素材格式是 json 文本,可讀性高,但是承載 AE 特性能力差,文件體積大,解碼速度慢。SVGA 使用 ProtoBuffer 序列化,解碼速度快,最終生成的文件直接使用 zip 壓縮。PAG 采用二進制的編碼方法,配套自研編解碼器,動態(tài)比特位壓縮,冗余信息極少,文件體積最小,解碼速度最快,且支持圖片和音頻信息編碼。
平臺端支持方面
目前 Lottie 僅支持 Android、iOS、web、mac OS,SVGA 支持 Android、iOS 和 web 端,PAG 可以支持到 Android、iOS、web、mac OS、windows、Linux,涵蓋到所有平臺。
3、 動畫文件及性能對比
3.1 矢量動畫文件對比
表1 動畫文件對比如上表所示,PAG 采用了動態(tài)比特位的壓縮技術(shù),動畫文件可以做到足夠小。相同的 AE 工程,PAG 導(dǎo)出的動畫文件大小是 Lottie 動畫文件的 51%,SVGA 動畫文件的 22%。
3.2 矢量動畫渲染性能
表2 矢量動畫渲染性能對比如表所示,在矢量圖形渲染方面,PAG 優(yōu)化 Lottie 和 SVGA,內(nèi)存占用方面會偏大一些。
4、 PAG 版本迭代與技術(shù)演進
PAG 從第一行代碼寫下到現(xiàn)在已經(jīng)經(jīng)歷了 5 年,期間經(jīng)歷了多個版本迭代:在 PAG 1.0 版本中,我們重點設(shè)計了高壓縮率的文件格式,以及游戲引擎級別的跨平臺的渲染架構(gòu)。雖然還支持了帶動畫的文本編輯能力,但 1.0 版本跟 Lottie 一樣僅覆蓋了 AE 的純矢量導(dǎo)出能力,很多復(fù)雜動畫效果無法被完整還原。
于是在 PAG 2.0 版本中,我們引入了 BMP 預(yù)合成的混合導(dǎo)出能力,同時解決了 AE 全特性的支持和可編輯性的問題。2.0 版本還引入了占位圖替換的能力,為照片模板和視頻模板的生產(chǎn)帶來了工業(yè)化量產(chǎn)的能力。
到 3.0 版本時,固定時間軸的模板已經(jīng)越發(fā)沒法滿足需求,PAG 在編輯性上又進行了一步探索突破,開放了圖層級別的原子編輯組合能力,支持了從原子特效組件動態(tài)構(gòu)建模板,很好的支撐了游戲戰(zhàn)報和一鍵出片等動態(tài)模板的需求。
截止到本月,PAG 4.0 版本的開發(fā)也接近收尾。這個版本耗時了近一年時間完成了在渲染架構(gòu)上最大的一次升級,徹底脫離了谷歌的 Skia 2D 繪圖庫,PAG SDK 包體也直線下降了約 60%,并完成了包括 Web 平臺在內(nèi)的全平臺覆蓋。
下面詳細介紹一下各個版本迭代過程中的重點技術(shù)演進細節(jié):
4.1 跨平臺渲染架構(gòu)
PAG 方案最早就是誕生在視頻編輯的場景下,要讓動畫能夠在視頻編輯場景下無縫整合使用,需要解決兩個問題:支持離屏渲染繪制、子線程渲染。Lottie 的動畫方案之所以無法應(yīng)用在視頻合成中,主要是因為依賴了平臺相關(guān)的 UI 框架,開發(fā)成本較低,但也導(dǎo)致了它只能渲染到 UI 視圖上,并且無法在子線程中使用。
PAG 的整套動畫方案就是基于 C++跨平臺架構(gòu)研發(fā)的,一直從最底層的動畫插值器,還原到上層的時間軸和圖層渲染樹系統(tǒng),雖然開發(fā)成本較高,但是所有端共享同一套代碼,天然的能保障跨端渲染一致性。最重要的是能直接渲染到離屏紋理上,并完美支持子線程動畫渲染。
圖4 PAG與視頻渲染相結(jié)合在解決完整合視頻渲染的問題后,還需要考慮怎么優(yōu)化動畫的性能。視頻編輯的場景本身資源耗費比較高,每幀并行地存在多個視頻解碼以及各種特效處理,此時留給 PAG 的渲染時間就不太多。我們需要把 PAG 的渲染性能優(yōu)化到極致,來滿足視頻編輯場景的實時預(yù)覽需求。
時間靜態(tài)區(qū)間
分析動畫文件的特效,我們發(fā)現(xiàn)大部分的動畫素材實際上并不是整個時間軸上都在變化,或多或少會存在一些畫面靜止的區(qū)間。而 PAG 在刷新時,如果遇到這些靜態(tài)區(qū)間,會直接返回上一幀的動畫內(nèi)容,自動跳過任何重復(fù)的繪制。極限情況下,假設(shè)有一個一分鐘的動畫素材,但實際上全程都是靜止的,它對 PAG 來說就相當(dāng)于一張靜態(tài)圖片,整個刷新的過程中都是 0 開銷。而在 Lottie 方案中,整個刷新過程都是全量的開銷,因為它每幀都會清空屏幕重新刷新。
三級緩存結(jié)構(gòu)
這里的解決思路是用空間來換時間。
第一個層面是文件緩存,主要解決 PAG 文件從文件解碼到內(nèi)存過程的耗時,同一個動畫文件只需要解碼一次,就可以放在多個動畫實例中渲染,避免多個相同動畫的重復(fù)解碼。
第二個層面是繪制緩存,解碼后的文件有多個時間軸屬性,我們將生成的繪制數(shù)據(jù)緩存到共享文件中,一個文件的任何一幀,只要繪制過一次,第二次繪制就可以得到加速。同時還利用了靜態(tài)區(qū)間的特點來優(yōu)化內(nèi)存,將每個圖層拆分成多個屬性組,每個屬性組計算出靜態(tài)區(qū)間的列表后,只緩存每個靜態(tài)區(qū)間第一幀數(shù)據(jù)。
第三個層面是內(nèi)容緩存,這個層級的加速效果是最明顯的。通常情況下,圖層的內(nèi)容繪制是最耗時的,因為要經(jīng)歷柵格化等操作。但是內(nèi)容一般不會隨著時間軸變化,反而是輕量的矩陣參數(shù)會頻繁的變化。根據(jù)這個原理,如果一個圖層內(nèi)容是靜止的,我們會把他的內(nèi)容緩存成一張紋理。這樣整個時間軸上,只會經(jīng)歷一次柵格化的過程,后續(xù)每幀的繪制都可以復(fù)用第一幀的紋理,快速套用矩陣變換,接近零成本地渲染出動畫效果。這里的內(nèi)容緩存我們同樣考慮了內(nèi)存優(yōu)化問題。例如一個動畫文件預(yù)設(shè)的大小是 500x500,但是實際使用中,整體被縮放到了 50x50 的大小,那么內(nèi)部創(chuàng)建的內(nèi)容緩存,會對應(yīng)的縮小相應(yīng)的面積倍數(shù)。這樣可以做到在保證清晰度的前提下,只緩存最小的面積。
4.2 BMP 預(yù)合成
在純矢量的導(dǎo)出模式下,無論是那種實現(xiàn)方案,在眾多的 AE 特性面前,都只支持將有限的 AE 特性導(dǎo)出渲染。因為在有桌面顯卡的情況下,有部分 AE 特性都還需要跑進度條才能完成預(yù)覽,在移動端根本沒可能做到實時。另外還存在第三方 AE 插件的效果無法導(dǎo)出的問題。這在一定程度上限制了設(shè)計師的創(chuàng)造力。另一方面,由于相同的動畫在 AE 中有很多實現(xiàn)方式,但性能卻千差萬別。于是我們思考如何解決眾多 AE 特性支持的問題,通過分析 AE 提供的 SDK 的能力,我們發(fā)現(xiàn) AE SDK 可以直接截圖,可以導(dǎo)出任何效果,且包含第三方 AE 插件的效果,但缺點也很明顯,圖片無法進行編輯,如果通過截圖的方式,文件會比較大。
圖5 BMP預(yù)合成導(dǎo)出實現(xiàn)文件大問題解決
針對截圖后文件比較大的問題(動畫一般不低于 24 幀),我們首先想到了視頻編碼的極限幀間壓縮能力,相對于原始的圖片序列幀,可以壓縮到百分之一點幾的大小,另外視頻格式還可以使用硬件解碼,從而獲得比較高的渲染性能。但這里遇到的一個問題是:動畫一般都是透明的,而視頻格式卻不支持透明通道。于是我們視頻編碼的同時,擴展了透明通道,如上圖所示,左邊為 RGB 的視頻內(nèi)容,右邊為 Alpha 通道的灰度圖,最終渲染的時候再合并回 RGBA 的圖片,從而實現(xiàn)對透明通道的支持。渲染的過程中,由于啟用了硬件加速解碼,可以直接得到一個 YUV 的紋理。我們在這里的優(yōu)化點主要是不使用常見的 FFmpeg 來執(zhí)行 YUV 到 RGB 轉(zhuǎn)換,從而避免紋理在 CPU 和 GPU 之間來回拷貝,而是自定義了一個 Shader 腳本,利用硬件加速在一次繪制過程中,同時完成 YUV 轉(zhuǎn)換和 Alpha 通道合并。這里平均就能夠提高 10%的渲染性能。
可編輯性問題解決
針對 BMP 預(yù)合成無法編輯的特點,我們將 BMP 預(yù)合成支持的粒度由文件延伸到合成,支持矢量和 BMP 預(yù)合成混合導(dǎo)出,從而實現(xiàn)了支持所有的 AE 特性又能保持運行時的可編輯性。
4.3 圖層編輯能力
在照片模板和視頻模板不斷地量產(chǎn)過程中,固定時間軸和尺寸的模板已經(jīng)逐漸出現(xiàn)了在應(yīng)用上的瓶頸。特別是當(dāng)一鍵出片、王者戰(zhàn)報等智能模板需求的出現(xiàn),整個模板不是由固定的時間軸組成,而是可能由多個原子特效組件拼裝而成,設(shè)計師即使投入非常高的人力,也無法針對每一種情況進行排列組合輸出。這里對 PAG 的編輯能力也提出了進一步的挑戰(zhàn):就是要能對多個 PAG 文件,同時具有空間位置和時間軸的組合能力。由業(yè)務(wù)方去控制組合的規(guī)則?;谶@個需求,我們引入了圖層渲染樹的編輯架構(gòu),不僅支持文本和占位圖比編輯,還支持圖層級別的編輯。一個文件就是一棵渲染樹,支持圖層級別的任意修改位置甚至增刪圖層,也可以把別的 PAG 文件添加到這棵渲染樹中作為子樹。能在空間維度上進行自由的排列擺放。而在時間軸的組合上,我們提供了 PAG 時間伸縮的能力,包含循環(huán),變速,定格等多種自適應(yīng)模式。每個圖層又提供了起始時間的調(diào)整能力,能夠自由設(shè)置在時間軸上的相對位置,能夠靈活適配用戶視頻的時長。
圖6 PAG圖層編輯經(jīng)過這些改造,新的接口不僅滿足了智能模板的編輯性需求,也簡化了原有業(yè)務(wù)調(diào)用的復(fù)雜度。例如原先業(yè)務(wù)上除了要構(gòu)建外部的視頻時間軸,還需要在渲染的過程中不斷手動更新每個視頻片段和 PAG 進度的對應(yīng)關(guān)系?,F(xiàn)在無論哪種使用場景,都可以簡化為兩個步驟:利用空間和時間的組合能力構(gòu)建一個渲染樹,然后播放或者導(dǎo)出即可。
4.4 全新渲染引擎升級
在 PAG 的前 3 個大版本的迭代過程中,大部分的業(yè)務(wù)痛點問題都已經(jīng)得到了很好的解決和覆蓋。但是接入過程中始終一直還存在一個難以回避的痛點:SDK 包體能否進一步壓縮?例如在某些頭部的 App 對接過程中,甚至要求接入后包體 0 增量。對大部分應(yīng)用來說,包體直接影響增長拉新的數(shù)據(jù),因此包體優(yōu)化確實是個剛需。在之前的版本里,我們的渲染架構(gòu)由于依賴了谷歌的 Skia 2D 繪圖庫。我們也已經(jīng)針對性做了非常多的定制和裁剪,但是 Skia 依然占據(jù)了 PAG SDK 75%左右的包體,無法在進一步進行裁剪。
而在性能方面,3.0 版本上層的 PAG 渲染架構(gòu)已經(jīng)做了游戲引擎幾乎所有能做的優(yōu)化策略。但是由于 Skia 需要兼容歷史遺留的 CPU 繪制模式,在 API 上暴露會比較保守,很多針對現(xiàn)代 GPU 繪制管線可以進一步優(yōu)化性能的接口都沒暴露出來。另外由于 Skia 是針對 UI 這種隨機繪制設(shè)計的引擎,內(nèi)部做了大量的緩存來確保隨機渲染的性能。而對于動畫這種可預(yù)測的渲染模式?jīng)]有很好的優(yōu)化,如果針對性優(yōu)化可以有效降低平均的內(nèi)存占用。整體上由于渲染對 Skia 的依賴,導(dǎo)致我們在性能上想要進一步突破也遇到了瓶頸。
為了徹底打破包體和性能的限制,我們花了將近一整年時間自研實現(xiàn)了一套輕量的純 GPU 繪圖引擎。在包體方面,我們最大化利用了平臺端提供的所有可用能力,例如復(fù)雜矢量圖形的柵格化, iOS 直接使用平臺自帶的 CoreGraphics,文本方面利用起 CoreText ,Android 端圖片解碼直接利用 Java 反射等。最終實現(xiàn)以 500K 左右的包體覆蓋了 Skia 絕大部分功能。
而在接口設(shè)計上,我們充分暴露了針對 GPU 渲染的優(yōu)化能力給到調(diào)用層,例如提交紋理后統(tǒng)一不再重復(fù)緩存一份 CPU 圖片,暴露傳入紋理遮罩緩存的能力實現(xiàn)一次性上屏,并在移動端全面開啟了 HardwareBuffer 接口的使用來加速紋理提交。在減小包體和內(nèi)存占用的同時進一步提升了渲染性能的天花板。在接口易用性方面也自帶線程安全的設(shè)計,所有 GPU 資源統(tǒng)一管理,外部任意線程釋放引用都可以確保正確銷毀,降低了使用 Skia 的 GPU 繪制模式時,容易出錯并需要大量封裝平臺相關(guān)上下文代碼的門檻。
表3 PAG 4.0 包體優(yōu)化數(shù)據(jù)另外在 PAG 4.0 版本中,我們也提供了對 Web 平臺的支持。之前遲遲未覆蓋這最后一個平臺,部分原因也是在等待新的渲染引擎升級完成后,可以減少 Web 端的包體加載壓力。在 Web 端,Lottie 和 SVGA 使用 Web 的 HTML、CSS 和 Javascript 重新實現(xiàn)了一遍。而 PAG 依然保持了全平臺共享一套 C++ 代碼的架構(gòu)。通過 WebAssembly 將全新的渲染引擎直接綁定到 WebGL 接口上進行渲染,僅在文本和柵格化等模塊上對 Web 平臺做了針對性的優(yōu)化適配。
目前這個新的繪圖引擎仍然內(nèi)置在 PAG 4.0 版本內(nèi),未來有可能會進一步抽離成獨立的 2D 繪圖庫,應(yīng)用到動畫工作流以外更多的渲染場景中。目標(biāo)實現(xiàn)成針對現(xiàn)代 GPU 渲染優(yōu)化的,包體和性能達到最佳平衡的 2D 繪圖引擎。
5、 結(jié)束語
除了本文描述的 PAG 技術(shù)能力,相對于 Lottie 和 SVGA,PAG 的輔助工具也非常完善,如果需要了解,大家可以訪問 PAG 官網(wǎng):https://pag.io/
如果大家對改進 PAG 項目有任何的想法或建議,歡迎訪問 Github 主頁:
https://github.com/Tencent/libpag?
提交 issue 或 pull request,一起參與到開源項目建設(shè)中,幫助 PAG 動畫方案做到更好。
官方交流QQ 群: 893379574
總結(jié)
以上是生活随笔為你收集整理的腾讯自主研发动画组件PAG开源的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 云原生背景运维转型之 SRE 实践
- 下一篇: 新一代消息队列 Pulsar