如何让页面动起来?支付宝2020新春红包前端3D技术揭秘
簡介:?新春紅包項(xiàng)目,作為每年用戶基數(shù)最大的支付寶活動(dòng)之一,對整個(gè)項(xiàng)目組的技術(shù)都是一個(gè)很大的考驗(yàn)。
新春紅包項(xiàng)目,作為每年用戶基數(shù)最大的支付寶活動(dòng)之一,對整個(gè)項(xiàng)目組的技術(shù)都是一個(gè)很大的考驗(yàn)。而作為前端,我們的技術(shù)考驗(yàn)就是如何在保證穩(wěn)定性的同時(shí),為用戶不斷帶來更好的創(chuàng)新體驗(yàn)。
原文鏈接:點(diǎn)擊這里?
而今年的新春紅包項(xiàng)目相比以前,多了不少互動(dòng)圖形方面技術(shù)的運(yùn)用,尤其是第一次對 3D(WebGL)技術(shù)的引進(jìn)。對于新春這個(gè)億萬量級的活動(dòng)而言,這無疑是個(gè)巨大的挑戰(zhàn)。但作為合格的工程師,效果和穩(wěn)定性的平衡是我們的一貫的追求,經(jīng)過了前期的積累,我們使用自研的 Web3D 游戲引擎以及特效編輯器,學(xué)習(xí)了許多在整個(gè)橫向前端領(lǐng)域、做的相對最好的游戲領(lǐng)域的經(jīng)驗(yàn),最終達(dá)到了比較復(fù)雜 3D 場景下極低的異常率。
我們的成果
我們在此次新春活動(dòng)的兩個(gè)場景中都達(dá)到了極好的效果和穩(wěn)定性的平衡:
- 首頁 3D 展示:5 個(gè)復(fù)雜模型的內(nèi)存總開銷為峰值 30M,穩(wěn)定 20M,對整體穩(wěn)定性無影響。
- 福滿全球:3D+UI 總內(nèi)存開銷峰值 70M,穩(wěn)定 40M,加 Webview 總開銷 100M。
?
為了最好的效果
技術(shù)的使命只有一個(gè)——為用戶帶去最好的體驗(yàn)。所以在項(xiàng)目最初肯定是先按照最高視覺效果來,針對新春中的兩個(gè)使用到了 3D 的場景,我們首先進(jìn)行了嘗試,然后發(fā)現(xiàn)了問題。
并非最佳體驗(yàn)
在這種情況下,我發(fā)現(xiàn)雖然視覺效果達(dá)到了最優(yōu),但又出現(xiàn)了很多其他方面的問題,這使得最終的用戶體驗(yàn)反而并不是很好:
而這某種程度上也符合我們一開始的預(yù)測,因?yàn)樵谝苿?dòng)端 Web 這種技術(shù)方案中,有些限制是不可避免的,而這些不安定要素會(huì)在億萬用戶的量級被無限放大。在經(jīng)過數(shù)據(jù)的詳細(xì)的分析,我們找到了針對這兩個(gè)場景的瓶頸共性。
瓶頸在何處
為了找到瓶頸,讓我們先來看一些數(shù)據(jù)。
首先是首頁 3D 動(dòng)畫,首頁總共五個(gè)場景模型,使用的資源包括:
可見統(tǒng)計(jì)下來,3D 部分最終可以預(yù)計(jì)的傳輸大小為 15M,峰值內(nèi)存為 65M,而穩(wěn)定下來最好情況也有 30M 內(nèi)存開銷(這種策略下一般達(dá)不到最好,預(yù)計(jì) 40M 左右)。同時(shí)由于單場景 5W 三角形,對于中低端機(jī)的幀率也有較大挑戰(zhàn)。
其次是福滿全球頁面,福滿全球的模型資源開銷基本可以忽略,但卻有其他方面的問題:
可見,福滿全球 3D 部分的主要開銷是在峰值 70M 的紋理,以及高清屏大量透明物體的渲染開銷。
死磕解決方案
通過瓶頸分析可知,問題主要集中在內(nèi)存、傳輸體積和運(yùn)行性能三個(gè)方面,而這三者又互相關(guān)聯(lián)。那么自然的,我想到了從相對容易解決同時(shí)收益又大的方面入手。
削減模型大小
首先就是削減模型大小了,注意這個(gè)大小指的是三角形 / 頂點(diǎn)數(shù)量。為什么這個(gè)如此重要呢?很簡單——模型的大小可以直接影響到以上的三個(gè)要素:
1. 內(nèi)存:模型的大小和其占據(jù)的內(nèi)存是線性正相關(guān)的。
2. 傳輸體積:和內(nèi)存一致。
3. 運(yùn)行性能:單幀三角形數(shù)量越多,頂點(diǎn)著色器的壓力越大,尤其是在首頁 3D 模型這種具有骨骼動(dòng)畫的情況下。
所以削減模型大小顯然是必須要做的,那么我們?nèi)绾稳プ瞿?#xff1f;一般來講,這件事應(yīng)該交由設(shè)計(jì)同學(xué),讓他們?nèi)ソ档湍P途葋磉_(dá)到一個(gè)可以接受的程度,但是結(jié)果不容樂觀,經(jīng)過研究,我們最終采用了以下兩個(gè)策略:
1. 使用工具減模
首先是尋求能否使用工具自己進(jìn)行減模,我們自研的 Web3D 游戲引擎使用 Unity 進(jìn)行場景編輯,而 Unity 作為身經(jīng)百戰(zhàn)、擴(kuò)展性極強(qiáng)的一個(gè)游戲引擎,有沒有這么一個(gè)工具來幫助我們呢?答案是有的—— UnityMeshSimplify 就提供了讓我們在 Unity 中自由調(diào)整模型精度并序列化的能力。而也正是使用了它,在視覺效果損失較低的情況下,平均降低了所有場景 30% 的圖元數(shù)據(jù)大小:
2. 削減不必要的數(shù)據(jù)
在工具減模以后,圖元數(shù)據(jù)大小從 12M 降到了 7.5M,但這顯然還是不夠,那么還有什么辦法呢?在思考后發(fā)現(xiàn)了一個(gè)關(guān)鍵點(diǎn)——處于性能考量,此次模型的光影是烘焙到紋理的,也就是說整個(gè)場景沒有光照。
這里就需要我們了解一些細(xì)節(jié)了,即頂點(diǎn)數(shù)據(jù)的構(gòu)成。
圖元的最基本單元是頂點(diǎn),一個(gè)頂點(diǎn)有包含著若干信息,在繪制時(shí)這些頂點(diǎn)數(shù)據(jù)將會(huì)被送入頂點(diǎn)著色器進(jìn)行一系列處理,然后進(jìn)入光柵化階段。而一個(gè)頂點(diǎn)的信息,最常見來看,包含:
而其中的法線和切線在首頁 3D 展示中并沒有作用,所以可以將其刪除,我在 UnityToolkit 中添加了 Unlit(No Normals) 選項(xiàng)來讓導(dǎo)出時(shí)可以自動(dòng)剔除這兩項(xiàng):
而最終效果也令人滿意,圖元數(shù)據(jù)大小進(jìn)一步降低到了 5MB。
3.成果小結(jié)
模型裁剪主要是針對首頁 3D 展示的,經(jīng)過優(yōu)化,我們得到了成果:
(1)單場景最大三角形數(shù)量從 5.5W 降到 2.9W;
(2)所有場景圖元和動(dòng)畫數(shù)據(jù)大小從 12MB 降到 5MB。
可見,我們成功將成功將圖元數(shù)據(jù) + 動(dòng)畫大小縮減了一半,還保證了最復(fù)雜的場景的三角形數(shù)量也縮減了將近一半,使得內(nèi)存開銷低了不少,同時(shí)傳輸體積小了不少,還大幅優(yōu)化了渲染性能開銷。
但顯然傳輸體積還是太大了,這里我們還進(jìn)行了進(jìn)一步的優(yōu)化。
使用壓縮紋理
解決了模型圖元大小,接下來就是紋理的開銷了。通過上面的瓶頸分析可知,福滿全球項(xiàng)目的開銷主要就是在紋理方面。
1. 何為紋理
紋理讀者也可以理解為貼圖、圖片。一般來講,我們存儲(chǔ)的圖片都是以 JPG、PNG 等格式存儲(chǔ)的,而格式?jīng)Q定的是什么呢?其實(shí)是壓縮和編碼算法。實(shí)際上,無論我們把一張 JPG 或者 PNG 圖片壓縮得再小,它最終被解碼后在內(nèi)存中還是以 Bitmap 的形式存在的,而且在瀏覽器中,基本都是以 RGBA 的像素格式存在的。
無論使用那種方式編碼存儲(chǔ),最終都會(huì)被解碼為 RGBA32 的 Bitmap,一個(gè)像素 4 字節(jié)。
這就意味著無論我們將圖片的存儲(chǔ)體積壓縮到多么小,其內(nèi)存開銷總是固定的,比如 512x512 的圖片內(nèi)存開銷就是 1M,而 1024x1024 的就是 4M。那么有沒有辦法解決這個(gè)問題呢?當(dāng)然有——游戲業(yè)界為了解決這個(gè)問題,提出了壓縮紋理技術(shù)。
2. 壓縮紋理
壓縮紋理是一種游戲領(lǐng)域常用的紋理壓縮技術(shù),其依賴于特定硬件實(shí)現(xiàn),本質(zhì)上可以以固定速率交由 GPU 即時(shí)解壓,其有如下優(yōu)勢:
(1)內(nèi)存:大幅節(jié)省內(nèi)存開銷。
(2)解碼:免去圖片解碼開銷,直接丟給 GPU,提升啟動(dòng)性能。
(3)采樣:提升紋理隨機(jī)采樣性能。
(4)可控:由于其本身就是在 JSHeap 上申請的 buffer,所以在 Web 容器下,提供了一個(gè)可以精確控制內(nèi)存的方式。
PVRTC 的 Block 說明
經(jīng)過調(diào)研和一些測試,我們最終選擇了安卓下使用 ASTC 和 iOS 下使用 PVRTC 的策略來進(jìn)行紋理壓縮,其中更為細(xì)節(jié)的配置暫且不表(都是中等精度壓縮),最終在項(xiàng)目中得出的成果如下:
(1)首頁 3D 展示:
(2)福滿全球:
可見壓縮紋理對于內(nèi)存的開銷有著極大的優(yōu)化,基本完全解決了內(nèi)存問題。
3. 條件和代價(jià)
當(dāng)然,這世界上并沒有免費(fèi)的午餐,我們接受了壓縮紋理的優(yōu)點(diǎn),就要相對得付出代價(jià)以及接受它的約束:
(1)壓縮紋理是有損壓縮,會(huì)對圖片的質(zhì)量有一定減損,這個(gè)需要視項(xiàng)目而定。
(2)壓縮紋理的傳輸體積可能比 JPG/PNG 方案要高 1~4 倍。
(3)壓縮紋理要求 POT,即長寬都是二的冪次。
(4)對于 iOS 的 PVRTC,還要求長寬相等。
(5)由于壓縮紋理格式在不同平臺(tái)不能通用,加上降級需要三份資源,對于離線加速技術(shù)不友好。
對于某些代價(jià),比如視覺質(zhì)量損失、傳輸體積我們是可以自行調(diào)整的,不屬于原則性難題,但這個(gè) POT 對于很對前端應(yīng)用可真是個(gè)原則性問題了,比如福滿全球中的地標(biāo)和紅包貼圖,就不是 POT 的,那么怎么辦呢?有辦法——使用圖集。
4. 紋理標(biāo)準(zhǔn)化 - 圖集
圖集是一種紋理標(biāo)準(zhǔn)化的方式,在游戲領(lǐng)域常常用于處理 UI、2D 精靈等,簡單來講,圖集就是將許多圖片拼到一張上,不錯(cuò)就是我們常說的雪碧圖(精靈圖):
?
如圖,我們將四個(gè) 500x500 的地標(biāo)圖片拼到了一張 1024x1024 的圖集中,來滿足壓縮紋理的需求。那么我們又如何去使用這個(gè)圖集呢?很簡單,我們的引擎內(nèi)置了 AtlasManager,可以讓你非常簡單得使用它,并且在引擎標(biāo)準(zhǔn)的開發(fā)流程中,依賴于 Unity+Webpack 工作流,這個(gè)能力能夠十分方便得引入——在 Unity 中直接編輯圖集,后面會(huì)說到。
圖集還有別的優(yōu)勢,就是減少內(nèi)存碎片,減少數(shù)據(jù)提交次數(shù),某些情況下還可以減少資源請求。
精確掌控內(nèi)存
目前我們擁有了削減模型和壓縮紋理兩種策略,大幅降低了內(nèi)存開銷,并降低了一部分傳輸體積,但通過上面的論述不難發(fā)現(xiàn)其實(shí)我們還可以更進(jìn)一步——我們很容易發(fā)現(xiàn),在整個(gè)過程中,同一份數(shù)據(jù)可能在 CPU 和 GPU 端同時(shí)存在,尤其是移動(dòng)設(shè)備 CPU 和 GPU 是共享內(nèi)存的。所以我們一定有辦法再更進(jìn)一步去解決這個(gè)問題。
這也就是我選用壓縮紋理的另一個(gè)理由——壓縮紋理本質(zhì)上是 JSHEAP 上的 ArrayBuffer,我們可以很好得通過控制引用來幫助 GC,這也就是為何上面的數(shù)據(jù)分析中能保證穩(wěn)定開銷是峰值的一半。
在我們引擎的設(shè)計(jì)中,這個(gè)功能是可選的,通過紋理的 isImageCanRelease 來開啟,而如果遵守標(biāo)準(zhǔn)工作流,這一切都是自動(dòng)的,無需開發(fā)者操心。
當(dāng)然這也有代價(jià),就是在 GL 上下文丟失后無法恢復(fù),請酌情使用。
進(jìn)一步減少傳輸體積
到目前為止,內(nèi)存已經(jīng)被控制得很好了,但是在傳輸體積上還是有更大的優(yōu)化空間,在這個(gè)方面我首先考慮的就是內(nèi)部的 Hilo3d 團(tuán)隊(duì)提供的模型壓縮方案。
1. 模型壓縮
我們采用的模型壓縮方案原理很簡單,針對移動(dòng)端使用的模型,并不需要每個(gè)頂點(diǎn)數(shù)據(jù)都是 32bits 的 float 型,一般來講 13bits 或者 14bits 就夠用了,所以這里有很大的可壓縮空間。而事實(shí)上經(jīng)過測試,發(fā)現(xiàn)確實(shí)如此,但當(dāng)然這也是有代價(jià)的,通過模型壓縮:
也就是說,模型壓縮后,首頁的所有資源大小達(dá)到了安卓 5.8M、iOS5.2M。但代價(jià)是增加了解壓時(shí)間和 1.5M 的峰值內(nèi)存。相對于收益,開銷是可以接受的。
然而即便如此,5M 的資源大小對于億萬 UV 的量級還是有些大,我們還有更多的辦法嗎?有,這時(shí)候就要請出我們的老朋友 GZIP 了。
2. GZIP
大家都熟知的 GZIP 其實(shí)在很多時(shí)候都能發(fā)揮意想不到的作用,而在我們的工作鏈路下,模型壓縮會(huì)提升 GZIP 的效果,而壓縮紋理也能獲得收益,在 GZIP 后:
可見,我們讓資源體積再減半,和一開始相比縮減了六倍。
3. 一般圖片資源
當(dāng)然除了 3D 相關(guān)的資源,我們也提供了方法來對普通圖片進(jìn)行了壓縮,主要是將 PNG 圖片編碼壓縮成了索引色,這是一種有損壓縮,也就是大家常用的 TinyPNG 的策略,當(dāng)然這個(gè)并沒有什么神奇的,我們已經(jīng)將這種算法作為了一個(gè)插件融入了工具鏈中,可以通過 Webpack 工作流直接無縫整合,最終普遍帶來了 2~4 倍的體積壓縮。
減少資源請求
到了這里我們解決了大部分主要問題,但還有一些邊角問題會(huì)對體驗(yàn)的極致構(gòu)成影響。這一點(diǎn)就是資源請求數(shù)量,我們不難發(fā)現(xiàn),對于兩個(gè)場景而言,3D 場景的資源請求數(shù)量都接近 20 個(gè),而這個(gè)問題并非不可解。
對 3D 領(lǐng)域有一定了解的讀者想必是知道 glTF 這個(gè)格式的,而我們自研引擎的場景序列化也是使用了這個(gè)格式。為了應(yīng)對某些場合,glTF 有它的二進(jìn)制形式 GLB,其可以將索引、紋理、圖元數(shù)據(jù)等等都打包到一個(gè)二進(jìn)制文件中,大幅降低請求數(shù)量,在兩個(gè)新春場景中,請求數(shù)量均被降到了 1 次。
而打包 GLB 的功能也被我們整合進(jìn)了 Webpack 鏈路中,開發(fā)者可以零成本將其引入。
剩余的性能問題
以上問題解決完成后,基本就可以保證項(xiàng)目穩(wěn)定了。對于福滿全球大量透明物體和高清屏的問題,經(jīng)過業(yè)務(wù)層面的調(diào)優(yōu),最終發(fā)現(xiàn)在可控范圍內(nèi)。這個(gè)是由于業(yè)務(wù)性質(zhì)決定的,否則我們當(dāng)然可以采用強(qiáng)制最大畫布尺寸來降低開銷。
除此之外,還有一點(diǎn)需要注意的是我們很可能忽略的一點(diǎn)——運(yùn)行時(shí)的 GPU 資源提交。由于引擎的設(shè)計(jì)是用到了在提交的原則(當(dāng)然這很符合規(guī)范),但對于這兩個(gè)項(xiàng)目,保證用戶操作時(shí)不卡頓的優(yōu)先級是很高的,而同時(shí)經(jīng)過了上面的內(nèi)存優(yōu)化我們也已經(jīng)保證了即使所有資源都被提交也可控,所以就需要一個(gè)策略將所有資源先提交到 GPU,并預(yù)編譯所有 Shader。
為了做到這一點(diǎn),我們采取了一個(gè)簡單的策略:在第一幀將所有物體渲染一遍,再結(jié)束 Loading,這增加了些許的加載時(shí)間,但保證了整個(gè)過程中不會(huì)卡頓。
而對于首頁 3D 展示,為了做到極致的效果,我們設(shè)計(jì)了漸進(jìn)式展示的策略。
漸進(jìn)式展示
做這個(gè)策略是考慮到項(xiàng)目用戶量級極大,網(wǎng)絡(luò)情況不一,所以不可能等待 Loaing 結(jié)束才展示頁面,那樣首次性能會(huì)很差,所以我們敲定方案——總是先展示靜態(tài)圖片,3D 資源加載、解析、提交 GPU 成功后,才無縫切換為 3D 動(dòng)畫。
首頁 3D 動(dòng)畫的這種策略是值得很多展示型項(xiàng)目參考的,這里還需要注意的的一點(diǎn)是:若模型比較復(fù)雜,首幀渲染會(huì)卡住用戶操作。所以針對本項(xiàng)目的場景,我們采用了時(shí)間分片的策略,將五個(gè)模型拆分為五次渲染,每次間隔 200ms,留給用戶操作的時(shí)間:
并且我們還保證靜態(tài)圖片和 3D 場景的姿態(tài)完全一致,從而達(dá)到視覺上無縫切換的目的。
酷炫易用 - 粒子特效
我們在大促的時(shí)候都需要炫酷的頁面來吸引用戶,但是動(dòng)畫通常都是開發(fā)的噩夢,通常我們在做動(dòng)畫會(huì)遇到以下三個(gè)問題:
- 動(dòng)畫粗糙,不能打動(dòng)用戶;
- 還原度不高,和設(shè)計(jì)差距較大;
- 性能優(yōu)化不足,兼容性不好。
這次的新春紅包項(xiàng)目大量使用了 3D 場景,在 3D 中加入了很多粒子特效,那么這些特效是如何產(chǎn)出并且解決以上三個(gè)問題的?
讓動(dòng)畫設(shè)計(jì)更精美
我們在首頁切換的時(shí)候增加旋轉(zhuǎn)的粒子特效,效果如下:
這個(gè)是設(shè)計(jì)同學(xué)的原稿,由于 Lottie 技術(shù)的普及,設(shè)計(jì)同學(xué)做動(dòng)畫大多使用 After Effect 在 AE 中制作好的 transform 動(dòng)畫(僅使用 translate、scale、rotate 變化)導(dǎo)出可使用 Lottie 播放,大大降低開發(fā)成本。而 AE 本身是一個(gè)視頻后期軟件,里面除了可以制作簡單的 transform 動(dòng)畫,還可以開啟 3D 渲染,進(jìn)行圖像跟蹤,加濾鏡等等。這個(gè)粒子特效就是用 AE 里 Particular 插件制作的,所以 AE 的上限就是設(shè)計(jì)師設(shè)計(jì)的上限。
設(shè)計(jì)師的設(shè)計(jì)工具將直接決定設(shè)計(jì)產(chǎn)物的質(zhì)量。如果沒有 particular 插件,那么我們的設(shè)計(jì)產(chǎn)物永遠(yuǎn)都只會(huì)是 transform 動(dòng)畫,很多影視級別的特效就不會(huì)出現(xiàn)在產(chǎn)品頁面中,所以提高設(shè)計(jì)工具能力將直接決定動(dòng)畫產(chǎn)出的質(zhì)量。當(dāng)然還有一個(gè)值得焦慮的問題,我們的產(chǎn)品開發(fā)并不知知道 particular 的插件是怎么實(shí)現(xiàn)的,那么很大概率是無法還原的,所以既要提高設(shè)計(jì)工具的質(zhì)量,也要限制設(shè)計(jì)隨意使用設(shè)計(jì)工具導(dǎo)致無法實(shí)現(xiàn)。
新春紅包項(xiàng)目的粒子特效設(shè)計(jì)全部在工具里實(shí)現(xiàn):
如果是手寫代碼還原設(shè)計(jì)稿的話,恐怕最要命的就是函數(shù)曲線的還原,動(dòng)畫為了更加順滑會(huì)加入很多曲線來控制,比如說剛才的旋轉(zhuǎn)上升的星星,會(huì)有一個(gè)先加速再減速的過程:
轉(zhuǎn)存失敗重新上傳取消
一個(gè)復(fù)雜的粒子系統(tǒng)有 60 多個(gè)屬性,如果開發(fā)通過肉眼還原數(shù)據(jù),哪怕是復(fù)制粘貼屬性值,都可能會(huì)出問題。
最好的還原方法是不寫代碼。編輯器直接導(dǎo)出動(dòng)畫數(shù)據(jù),在手機(jī)上進(jìn)行播放,開發(fā)完全不用關(guān)心各種參數(shù)。而產(chǎn)物很容易使用,直接保存項(xiàng)目工程,通過 webpack 進(jìn)行加載,像使用圖片一樣簡單。
新春紅包項(xiàng)目中 3D 場景由 引擎 搭建渲染,使用的時(shí)候也是類似的方式,將編輯器工程作為資源引入,直接播放就可以了。動(dòng)畫播放起來之后就是開發(fā)最關(guān)心的問題了。
保證動(dòng)畫性能
其實(shí)任務(wù)首頁的粒子效果還很少,談不上性能瓶頸,而福滿全球大量使用粒子,特別是煙花作為常駐特效,需要特別進(jìn)行優(yōu)化。這里我們參考了游戲領(lǐng)域粒子系統(tǒng)的許多優(yōu)化策略,將其運(yùn)用到了本次的優(yōu)化中。
優(yōu)化一:粒子運(yùn)動(dòng)完全 GPU 運(yùn)算
對于粒子系統(tǒng)來說,因?yàn)榱W訑?shù)量大,使用曲線控制后運(yùn)動(dòng)計(jì)算復(fù)雜,如果通過 CPU 計(jì)算粒子的運(yùn)動(dòng),那么網(wǎng)頁將不堪重負(fù),所以粒子的運(yùn)動(dòng)旋轉(zhuǎn)和顏色變化計(jì)算全部放在 GPU 中,通過定制 shader 完成,在 shader 中計(jì)算曲線是比較復(fù)雜的事情(此處省略 3 千字)。
優(yōu)化二:優(yōu)化粒子發(fā)射器
可以看到進(jìn)度條的粒子持續(xù)產(chǎn)生,因?yàn)榱W佑猩芷?#xff0c;所以會(huì)有老的粒子死亡,新的粒子出生,繁衍不息。首先我們在內(nèi)存中開辟一塊固定的地址,有一個(gè)按照粒子的生命周期排序的雙向列表,每一幀需要產(chǎn)生新粒子的時(shí)候,檢查列表最先死亡的粒子,如果此粒子已經(jīng)死亡,那么會(huì)把這個(gè)粒子的地址寫入新粒子的數(shù)據(jù),同時(shí)將此列表元素從后插入。大概類似如下過程:
這樣的列表可以保證粒子插入的速度,假設(shè)一個(gè)粒子系統(tǒng)有 200 個(gè)粒子,每幀其實(shí)只有 3-4 個(gè)新粒子的插入,在 CPU 中的計(jì)算量很小。
優(yōu)化三:合并發(fā)射器
一個(gè)煙花是由兩個(gè)發(fā)射器組成的,構(gòu)成了雙層煙花的效果,同時(shí)每個(gè)煙花增加一個(gè)拖尾效果,煙花飛過的地方就有個(gè)小尾巴。編輯效果如下:
可以看到煙花以相同的模式爆炸了 6 次,但是每次爆炸的位置不一樣,通常情況下我們在編輯器會(huì)做好一次的爆炸,然后復(fù)制 6 次,時(shí)間軸類似如下:
但這樣的話會(huì)導(dǎo)致頻繁創(chuàng)建銷毀繪制元素,性能消耗很大,所以編輯器提供了合并粒子爆炸的選項(xiàng),并且每次可以修改爆炸的位置。對于習(xí)慣了復(fù)制粘貼的設(shè)計(jì)師來說,很容易復(fù)制很多相同元素導(dǎo)致性能開銷過大,將六個(gè)繪制元素合并成一個(gè)元素可以大大降低開銷,同時(shí)重復(fù)利用內(nèi)存。
優(yōu)化四:減少拖尾使用
拖尾就是飛線,在粒子運(yùn)動(dòng)過的地方生成一個(gè)頂點(diǎn),繪制的時(shí)候連成一條線,這樣就有流星劃過的感覺。但是因?yàn)榱W拥挠?jì)算都是在 GPU 中的,所以每幀如果要生成新的頂點(diǎn),必須在 CPU 中也重新計(jì)算粒子的位置,這樣的計(jì)算量是很大的。如果煙花只是進(jìn)場爆炸一次,那么開銷可以忽略,但是有一些煙花是常駐的,隔一段時(shí)間就會(huì)播放一次,那么對于常駐的動(dòng)畫,就要避免使用拖尾。這次我們選擇了用貼圖縮放的方法來替代拖尾。
如果不用貼圖的話,看起來就是一圈延展的小菊花,這是通過通過增加長方形長度實(shí)現(xiàn)的,換上我們尖角的貼圖就非常像一條尾巴,最后常駐煙花沒有使用拖尾,但是視覺效果仍然很像劃過的流星,這樣保證所有的計(jì)算都在 GPU 中進(jìn)行,提高動(dòng)畫性能。
做到極致 - 工程自動(dòng)化
當(dāng)然,作為引擎開發(fā)者,除了將這些技術(shù)應(yīng)用到新春項(xiàng)目中,使得更多開發(fā)者可以簡便使用這些功能也是很重要的,所以我將這一切都封入了引擎的標(biāo)準(zhǔn)工作流中:
引擎工作流
引擎的工作流集成了以上所論述的所有優(yōu)化策略,其主要包括 UnityToolkit 和 Webpack 鏈路兩部分。
1. UnityToolkit
UnityToolkit 是 Unity 的一個(gè)插件,用于將 Unity 中的各種特性導(dǎo)出供引擎使用,整個(gè)流程集成度很高,目前已經(jīng)支持了大量特性,包括但不限于 GameObject、模型、材質(zhì)、紋理、動(dòng)畫、光源、攝像機(jī)、天空盒、圖集、精靈、物理、音頻、環(huán)境反射、環(huán)境照明、光照貼圖的導(dǎo)出和導(dǎo)入,支持自定義擴(kuò)展組件,支持腳本邏輯綁定等等。
2. Webpack 鏈路
然后就是 Webpack 鏈路了,我對 Webpack 鏈路做了深度定制,用于滿足引擎的工作流的需求。上面提到的壓縮紋理、模型壓縮、資源預(yù)處理、資源自動(dòng)化發(fā)布等都被集成到了其中,包括多平臺(tái)適配也是通過 Webpack 插件實(shí)現(xiàn)的。
這里先大概介紹一下此次項(xiàng)目用到的最主要的鏈路:gltf-loader
這個(gè) Loader 是整個(gè)鏈路中非常核心的一貫,其提供了加載 gltf 文件并進(jìn)行復(fù)雜預(yù)處理的能力。使用它,我們可以做到:
(1)模型壓縮。
(2)紋理壓縮。
(3)打包 GLB。
(4)資源預(yù)處理:對 gltf 文件引用的資源進(jìn)行預(yù)處理,通過定制 Processor 接口你可以實(shí)現(xiàn)任何你想要的任何預(yù)處理。
(5)資源發(fā)布器:自定義發(fā)布器,在 gltf 文件引用的資源(包括自身)被產(chǎn)出時(shí),攔截并進(jìn)行自動(dòng)化處理。
而在這兩個(gè)項(xiàng)目中,這幾個(gè)功能都被用到了,也為最終項(xiàng)目的穩(wěn)定可靠提供了重要的保障。
關(guān)于團(tuán)隊(duì)
本次分享來自于支付寶 Turandot Studio,Turandot Studio 致力于通過互動(dòng)和圖形技術(shù),讓前端變得更加具有創(chuàng)意,為用戶帶來更美好的體驗(yàn),如果你有意加入我們,請聯(lián)系我的郵箱:shunguang.dty@antfin.com。
總結(jié)
以上是生活随笔為你收集整理的如何让页面动起来?支付宝2020新春红包前端3D技术揭秘的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 前端生产方式:过去 10 年回顾和未来
- 下一篇: 阿里和浙大的“AI 训练师助手”是这样炼