自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

QQ空間萌寵之舞:HTML5骨骼動畫實踐

企業(yè)動態(tài)
QCon是由InfoQ主辦的全球頂級技術(shù)盛會,每年在倫敦、北京、東京、紐約、圣保羅、上海、舊金山召開。自 2007年 3月份首次舉辦以來,已經(jīng)有超萬名高級技術(shù)人員參加過QCon大會。QCon內(nèi)容源于實踐并面向社區(qū),演講嘉賓依據(jù)熱點(diǎn)話題,面向 5年以上工作經(jīng)驗的技術(shù)團(tuán)隊負(fù)責(zé)人、架構(gòu)師、工程總監(jiān)、高級開發(fā)人員分享技術(shù)創(chuàng)新和最佳實踐。

 4月16日QCon前端工程實踐專場會議上,騰訊QQ空間營收方向負(fù)責(zé)人、web前端工程師李振文以”QQ空間萌寵之舞——HTML5骨骼動畫實踐”為主題,用去年上線的QQ空間萌寵作為實踐案例,為大家分享了骨骼動畫的實踐技術(shù)點(diǎn)、骨骼動畫實踐中遇到的問題以及最終的解決方案,***是根據(jù)總結(jié)的經(jīng)驗得出得性能優(yōu)化方案。

李振文:我是來自QQ空間的李振文,很高興在QCon上跟大家交流,QQ空間去年上線了一個寵物,我們使用了骨骼動畫實現(xiàn)這個游戲。從零基礎(chǔ)最終到這個游戲上線,我們開發(fā)實踐過程當(dāng)中遇到很多的問題。開發(fā)實踐中遇到的問題和一些思路想和大家交流一下。

這是我今天介紹的一個大綱,首先給大家介紹一下骨骼動畫的基礎(chǔ)知識點(diǎn)。然后是項目中幾個工程技術(shù)實踐,以及遇到的問題和解決方案,***講性能優(yōu)化上面的幾個實踐點(diǎn)。

先介紹一下骨骼動畫的基礎(chǔ)知識點(diǎn),我拿幀動畫和骨骼動畫的素材做了一個對比。屏幕上幀動畫實現(xiàn)不停的切換每一張圖片實現(xiàn)動畫播放的。這樣如果我們要去實現(xiàn)多套動作的話,就需要準(zhǔn)備很多套圖,靈活性很差,素材體積也大。但骨骼動畫是將素材拆解成一個個零件,圖片上人拆解成頭、身子、盾、矛,然后用這一套素材拼成不同的動作,跑步、跳躍等都可以實現(xiàn)。骨骼動畫設(shè)計上的做法跟我們代碼模塊化游戲相似。

這里列出了骨骼動畫的特點(diǎn)。

***,資源體積更小,骨骼動畫保存骨骼相關(guān)的動畫數(shù)據(jù),不需要把每一幀圖片都保存下來,所以需要的資源很小,小的圖片就可以實現(xiàn)。

第二,多角色可以共用同一套數(shù)據(jù),我們實現(xiàn)一套骨骼之后,只需要把骨骼上面圖片素材更換或者修改就可以實現(xiàn)不同的角色。

第三,動作可以自由組合,比如一個角色它可以這樣搖頭,搖頭同時把手抬起來,把腳起來,可以自由組合。

第四,骨骼動畫有網(wǎng)格的功能,可以實現(xiàn)蒙皮、自由變換,動畫更加逼真。

第五,骨骼動畫對處理器要求性能更高,骨骼動畫運(yùn)動的時候需要大量的計算,因此性能要求更高,這也是我們實踐當(dāng)中遇到的***挑戰(zhàn)。

這是一個組裝好的骨骼動畫,圖片中將骨骼顯示出來的,每一條灰色線就是一根骨骼,骨骼上面的小黑點(diǎn)是關(guān)節(jié),每個都可以旋轉(zhuǎn),骨骼動畫運(yùn)動只需要動一個骨骼,與之相連的骨骼就可以一起運(yùn)動。這張圖藍(lán)色線條的部分,是手的上臂骨骼,移動這個上臂骨骼,子骨骼,前臂和手掌也跟著一起運(yùn)動。這樣就非常美妙了,我們實現(xiàn)聳肩只需要關(guān)注肩膀的運(yùn)動,不需要關(guān)注手臂和手掌的運(yùn)動。

 

 

這是我們整理出來的骨骼動畫的組成結(jié)構(gòu),這個組成結(jié)構(gòu)對應(yīng)的動畫編輯器是SPINE。包括有骨骼、插槽、附件和動畫。骨骼是核心,是豎狀結(jié)構(gòu),插槽附著到骨骼上面,插槽上面可以放很多附件,附件包括圖片和網(wǎng)格,圖片是我們?nèi)庋劭梢钥吹降?,圖片素材頭、腳、身子、腿這些。網(wǎng)格可以用來實現(xiàn)自由變形和蒙皮效果,讓動畫更加逼真。動畫控制每一幀骨骼位移和旋轉(zhuǎn)位置。

 

 

這是一個骨架的樹狀結(jié)構(gòu),這個骨架下面有軀干、左腿、右腿和盆骨。而軀干下面又有左臂、右臂和脖子。可以看到骨骼上面是附著有圖片的,這些圖片其實就是附著在骨骼的插槽上面,紅色圓圈部分就是插槽。插槽是SPINE編輯器的一個概念,為了讓骨骼不影響繪制順序而創(chuàng)造的,例如,如果我的軀干部分有衣服和肚子,髖骨有褲子,繪制順序應(yīng)該是肚子在最下面,褲子在中間,衣服在最上面,如果沒有插槽這個概念,那么就要建立三個骨骼,軀干要拆成兩根骨骼,這樣不合理,但是有了插槽就只需要兩根骨骼,可以在軀干這一根骨骼上面建立兩個插槽分別放衣服和肚子。

 

 

介紹完骨骼我們介紹一下網(wǎng)格,圖片中藍(lán)色的線條就是網(wǎng)格,一條一條的線非常形象。剛才講網(wǎng)格實現(xiàn)蒙皮和自由變形。為什么可以實現(xiàn)自由變形?因為有頂點(diǎn)、邊緣、三角區(qū)域三個概念。頂點(diǎn)就是藍(lán)色的點(diǎn)。三角區(qū)域就是三個點(diǎn)組成的三角區(qū)域。邊緣就是整個大框架的邊緣。有了這三個概念,只要我們移動***可以將三角區(qū)域紋理進(jìn)行變形,圖片就變形了。***張圖我們拖動藍(lán)色的頂點(diǎn),就可以拉長鼻子。蒙皮效果就是能夠讓骨骼運(yùn)動影響網(wǎng)格的方法,進(jìn)而影響圖片素材的運(yùn)動,運(yùn)動效果顯得更逼真。我們來看一個演示效果:


 

左邊動畫沒有使用蒙皮,右邊動畫使用了蒙皮,左邊耳朵和長矛是僵硬的,右邊耳朵和長茅抖動顯得更逼真,沒有蒙皮效果的骨骼動畫設(shè)計是不完整的。

做骨骼動畫,***步選擇對應(yīng)的編輯工具,這影響后面動畫實現(xiàn)和運(yùn)行庫的選擇?,F(xiàn)在市面上主要有兩款,***個是SPINE,國外付費(fèi)軟件,運(yùn)行庫和功能都很多,而且普及程度高,大部分設(shè)計公司都用的這個,因為考慮后續(xù)設(shè)計資源的緣故,我們選擇了SPINE。另一款是龍骨,我們國產(chǎn)軟件,免費(fèi),運(yùn)行庫和功能相對較少,但是作者在不斷完善中,功能也在向spine靠齊,而且關(guān)鍵的是可以直接與作者溝通。這里大家在學(xué)習(xí)的時候建議可以先用龍骨上手。后續(xù)再根據(jù)游戲的需求來選擇用哪個軟件。

SPINE支持的運(yùn)行庫非常多,官網(wǎng)上列了很多,我們這里挑了幾個來做對比,主要從性能、是否支持webgl、文件大小、文檔還有活躍度方面來做選擇。因為幾個底層庫實現(xiàn)都相同,性能上沒什么太大的差別;cocos2d的骨骼動畫組件由于沒人維護(hù),直接放棄了;最終我們結(jié)合項目特色,選擇了PIXI這款輕量的引擎。它的體積、文檔還有活躍度上都非常不錯,當(dāng)然PIXI也有他的缺點(diǎn),PIXI是一個較底層的游戲引擎,很多功能需要使用插件或者自己去實現(xiàn),因為我們要做的游戲主要是以播放動畫為主,再附帶一些界面交互,所以選擇了PIXI,這里大家在實際項目中可以列出自己關(guān)注的維度來進(jìn)行對比挑選適合項目的引擎。

介紹完了骨骼動畫的一些基礎(chǔ)知識點(diǎn),來看下我們QQ空間做的這款寵物游戲,這是一個養(yǎng)成類的游戲,主要功能包括喂食、偷糖果、換裝、組合動作。還可以和你聊天,講笑話,玩成語接龍,在空間主頁也會顯示這只寵物。大家可以下載***版的QQ空間手機(jī)版來體驗這款游戲。

接下來介紹項目實踐中幾個技術(shù)點(diǎn)實現(xiàn)。我們寵物游戲核心功能之一就是換裝扮,可以自由替換帽子、衣服、褲子、背部掛件,換裝扮對骨骼動畫來講就是換附件,附件有普通的圖片類型,還有蒙皮類型,普通圖片PIXI支持了,但是蒙皮類型的沒有,要實現(xiàn)蒙皮類附件的替換,最開始想到的方式,hack引擎從圖集讀取出來的附件信息,修改它的紋理指向換裝之后紋理。再構(gòu)造一個新的SPINE對象,這樣雖然能實現(xiàn)需求,但是畫面會有閃動。

為了實現(xiàn)更完善的方案,我們熟讀了一遍PIXI代碼,找到了更好的方式,pixi有一個使用canvas做紋理的接口,所以:把canvas代替png圖片繪制,如果有換裝,就覆蓋canvas以前位置的圖片。實現(xiàn)換裝有兩部分,***部分是在頁面打開初始化的時候,需要給寵物穿上現(xiàn)有的裝扮,首先將原始圖集轉(zhuǎn)成canvas,再將裝扮圖片插入canvas指定的位置,這個位置是在SPINE導(dǎo)出的配置文件里定義好的,然后再通過PIXI的接口把canvas轉(zhuǎn)成紋理,接著用這個新的紋理替換掉附件的舊紋理,再渲染就行了。第二部分是在裝扮商城里換裝,只需要覆蓋原來衣服在canvas上的位置,在刷新下紋理就可以實現(xiàn)無縫換裝了,代碼里是簡單示例,***步清理canvas上的舊衣服圖片,第二步把新的衣服圖片畫到canvas上面,***更新畫布。經(jīng)過這兩部分,就能***地實現(xiàn)換裝功能了。

第二個功能點(diǎn)分享GIF圖,游戲分享出去有GIF圖動起來轉(zhuǎn)化效果更好。我們實現(xiàn)GIF主流程有三個大步驟。***步H5截取每一幀圖片,然后傳給客戶端組裝成GIF圖同時壓縮,***上傳到后臺發(fā)布分享。合成GIF圖的也可以用純JS方案或者后臺方案,純JS方案需要引入第三方庫,而由于GIF圖太大我們要進(jìn)行壓縮,壓縮就涉及到很多像素對比運(yùn)算,效率很低,需要10秒左右。后臺方案,如果我們把圖片截好之后傳給后臺,這中間網(wǎng)絡(luò)傳輸耗時就會很大,所以我們選擇用客戶端幫助我們合并GIF圖的方案。

我們來看下H5截圖的邏輯,主要是從canvas中將每一幀的圖片截取出來,因為我們頁面上會播放這個動畫給用戶看,為了節(jié)省資源,決定利用這個已有播放動畫的canvas。最簡單的,播放動畫的時候截取每一幀的圖片,但是實現(xiàn)之后發(fā)現(xiàn)一些低端機(jī)型截出來的圖片不完整,播放起來就像演示一樣很卡頓,原因是這些低端機(jī)性能很差,導(dǎo)致截圖的時候會漏掉幀數(shù)。所以我們采取了多輪截圖方式,通過FPS和動畫時長計算出需要截取的圖片數(shù)量,將截取的圖片按照計算出來的key值進(jìn)行保存,這樣就能保證截取動畫的完整性。FPS我們在游戲中會有一份緩存,沒有的話會再跑一遍計算FPS。然后通過FPS和動畫時長可以計算出需要截取的張數(shù),然后在動畫播放過程中進(jìn)行截圖,截取的圖片會通過key值進(jìn)行保存,判斷截取的圖片數(shù)量達(dá)到預(yù)期后就結(jié)束截圖,通知客戶端進(jìn)行合并。

這是通過新的方式截取出來的gif圖,效果不錯。這個方案的優(yōu)勢在于利用了頁面中已有播放動畫的canvas來實現(xiàn),減少了額外的資源。在設(shè)計方案的同時考慮性能和業(yè)務(wù)場景,來制定更合適的方案。

接下來向大家分享一下開發(fā)過程當(dāng)中遇到的問題點(diǎn)。***個問題在調(diào)試素材的時候我們發(fā)現(xiàn)有些動作會展示錯位,它的肚子和衣服都會飄到天上去,我們發(fā)現(xiàn)這個問題發(fā)生時有共性,只有蒙皮類型的動畫才會出現(xiàn)這樣的問題。為什么會這樣?我們定位源碼,閱讀他們的源碼,找到了觸發(fā)原因,同一個插槽上面有多個附件就會觸發(fā)這個bug,PIXI引擎在定時器更新遍歷插槽時間軸的時候,在region切換到mesh類型的時候或者mesh切到region的時候,引擎沒有隱藏之前的附件,所以就會產(chǎn)生漂移。通過修改源碼解決了這個bug,***版的PIXI已經(jīng)修復(fù)了這個bug。

第二個問題發(fā)現(xiàn)部分機(jī)型播放蒙皮類動畫會有閃爍的問題,當(dāng)時離發(fā)布只有一天了,時間非常緊急。我們一方面查源碼定位這個問題,一方面查是不是素材導(dǎo)致了這個bug。在定位問題時,我們發(fā)現(xiàn)用官方的示例代碼在特定機(jī)器上也能重現(xiàn),確定了是引擎自身問題,我們當(dāng)時嘗試切換PIXI到舊版本,發(fā)現(xiàn)在某個低版本這個問題沒有,可以肯定是新版本PIXI某個代碼改動導(dǎo)致了這個bug,當(dāng)時時間緊迫,所以臨時用了舊版本PIXI解決問題。但仍要搞清楚新版本為什么有這個問題,我們對比新舊代碼,看到了是這行代碼的緣故,這行代碼到底做了什么事情呢?這個變量是控制是否使用系統(tǒng)的VAOS插件,只要用了系統(tǒng)的VAOS插件就會有問題。VAOS插件可以避免循環(huán)渲染中不必要的開銷,也會改進(jìn)我們做循環(huán)處理時的代碼寫法。但是它對性能的提升不大的,基本上可以忽略不計,主要作用可以讓我們處理循環(huán)渲染的時候做一些寫法上面寫起來更加優(yōu)雅,代碼上PIXI給我們做好了封裝,我們?nèi)株P(guān)閉就可以了。

我們小結(jié)一下剛剛講得這些內(nèi)容,兩個功能點(diǎn)實現(xiàn),實時換裝和技術(shù)點(diǎn)截圖。蒙皮錯位和閃爍bug,一方面我們熟讀源碼,第二是與作者交流。熟讀源碼讓我們更快定位到問題的癥結(jié)點(diǎn),與作者交流可以幫助我們找到***辦法解決問題。同時我們解決問題的時候,同時朝著不同的方向去努力的。如果當(dāng)時因為一些特殊的原因使用了臨時方案的話,之后要找到問題的本質(zhì),用***方案解決它,避免今后某個時間點(diǎn)背負(fù)這些技術(shù)債。

接下來交流我們在性能優(yōu)化上面做的幾件事情。當(dāng)時主要從CPU、GPU、內(nèi)存三個指標(biāo)上測量性能,剛開發(fā)完時我們CPU有40%,GPU占67%,內(nèi)存增量有100兆,這個數(shù)據(jù)光看起來就很差,實際測試對用戶影響導(dǎo)致手機(jī)耗電、發(fā)熱、卡頓和崩潰。

 

 

先來看下為什么CPU和GPU占用會這么高?看圖片中的人物,我將所有的骨骼和網(wǎng)格都顯示出來了,骨骼動畫每一幀都需要控制這些點(diǎn)的運(yùn)動,做了很多矩陣運(yùn)算,而且開啟了gpu加速,所以只要運(yùn)動,cpu和gpu的占用就會飆升,越精細(xì)的動作,它控制的骨骼和網(wǎng)格數(shù)量就越大,所以消耗也會越大

我們做了三個處理,***、減少每一幀運(yùn)動的骨骼及網(wǎng)格數(shù)量,根據(jù)實際情況權(quán)衡的,減少太多動作就會不精美。第二、我們通過減少不必要的運(yùn)動頻率,例如把待機(jī)動作改成隔幾秒動一次,減少持續(xù)性的消耗。第三APP切換到后臺時停止動畫,防止切換到后臺動畫一直播放導(dǎo)致APP崩潰。

做了這幾點(diǎn)以后,我們待機(jī)時CPU占用到12%,GPU占到34%,基本上跟客戶端的占用差不多了。

第二個性能優(yōu)化,減少內(nèi)存占用。內(nèi)存的占用主要來自紋理圖片、JS對象的占用,于是我們做了幾個測試,***個測試是將兩倍尺寸的紋理圖換成單倍圖,但是實際測試優(yōu)化效果并不大,和預(yù)期不符,經(jīng)過查證,原因是我們這個測試是用chrome的profile來測試的,profile只會檢測js對象和DOM占用的內(nèi)存,不會檢測GPU內(nèi)存,而紋理圖占用的是GPU內(nèi)存,所以這里檢測不出來,這也是我們從普通web開發(fā)轉(zhuǎn)游戲開發(fā)后的一個誤區(qū),沒有關(guān)注到GPU內(nèi)存的占用,后面會講到gpu內(nèi)存的優(yōu)化。這里先看第二個測試,將動作數(shù)據(jù)進(jìn)行精簡,對比發(fā)現(xiàn)精簡后的內(nèi)存占用大大減少,于是我們對動作數(shù)據(jù)進(jìn)行了拆分。要實現(xiàn)動作數(shù)據(jù)拆分,并且按需加載,只在用到某個動作的時候才加載這個動作數(shù)據(jù),我們暴露了PIXI的這個私有接口,這樣就能直接添加新的動作數(shù)據(jù)進(jìn)去。動作數(shù)據(jù)為什么占這么的內(nèi)存?我們寵物游戲的特色,用戶可以通過組合不同的動作來生成新的動作,所以它的動作數(shù)據(jù)很多。最開始我們完整的動作數(shù)據(jù)有70個,文件大小有3兆,轉(zhuǎn)化成JS對象以后占用的內(nèi)存更多,拆分后的初始動作從70多個減少到4個,文件大小從3M減到200K,拆分之后,JS占用的內(nèi)存從49M優(yōu)化到了18M,而且因為配置文件體積也變小了,頁面加載速度也提升了30%。

第三個性能問題,游戲里面有個排行榜,可以切換到好友寵物去偷糖果,測試中不停地切換好友,內(nèi)存會不停地往上漲,表現(xiàn)出來的問題就是webview進(jìn)程會崩潰。我們的好友數(shù)量一般都有上百個,多的有上千個,所以這個問題很明顯。

瀏覽器內(nèi)存分為這幾塊,JS、DOM、GPU內(nèi)存、編譯后的Code等。JS和DOM的內(nèi)存占用可以通過chrome的Timeline和Profiles來分析,其他的則可以通過chrome的任務(wù)管理器來看。開發(fā)調(diào)試時主要用chrome工具,上線前測試的時候需要在APP里面看實際環(huán)境的數(shù)據(jù),就要借助客戶端相關(guān)的測試工具。IOS的話用xcode,安卓是用的我們公司內(nèi)部自研的一個工具。經(jīng)過測試,切換12個好友后,JS內(nèi)存增長了18M,GPU內(nèi)存增長了90M,非常的嚴(yán)重。

***部分JS的內(nèi)存占用通過定位下來主要是附件、網(wǎng)格數(shù)據(jù)的增長。如果新建一個模型對象的話會有很多重復(fù)的附件數(shù)據(jù),因此針對同一種寵物,我們復(fù)用他的模型對象,切換好友就相當(dāng)于只是換裝扮。切換之后的SPINE對象以及初始紋理都能夠復(fù)用。JS的內(nèi)存增量從18M優(yōu)化到了5M。

我們再來看GPU內(nèi)存,由于前面復(fù)用了模型,模型的紋理也能復(fù)用,因此可以減少GPU內(nèi)存占用。在確定這些紋理不再使用后,可以手動執(zhí)行PIXI的dispose方法主動釋放紋理,GPU內(nèi)存占用從90兆優(yōu)化到了30兆,效果很明顯。***我們從排行榜切換出來,銷毀好友的寵物數(shù)據(jù),回收內(nèi)存。

我們總結(jié)一下這次的分享內(nèi)容,性能優(yōu)化上面針對CPU、GPU內(nèi)存主要有三個方面,***減少待機(jī)動畫的頻率。將待機(jī)動畫這種一直在播放的動畫減少頻率減少持續(xù)性壓力。第二點(diǎn)動作、素材文件做成按需加載,一方面減少內(nèi)存的占用,第二方面可以提高訪問的速度。第三紋理和模型盡可能的復(fù)用,減少內(nèi)存占用。另外使用臨時方案或者我們迫不得已使用臨時方案,也需要深究***方案,避免某個時點(diǎn)背負(fù)這些技術(shù)債務(wù)。閱讀源碼、與原作者交流能夠更好幫助我們。發(fā)布標(biāo)準(zhǔn)的制定,使用參照物對比。我們***測試階段的時候有找一些參照物的,比如說我們之前開發(fā)過普通的游戲,我們可以將這些普通游戲CPU、GPU占用,以及內(nèi)存增量做一個對比。非常感謝大家,我的分享就到這里。

責(zé)任編輯:Jane 來源: 51CTO
相關(guān)推薦

2017-02-07 11:35:26

Android動畫蠟燭動畫

2015-12-07 10:00:13

HTML5Loading動畫

2012-08-30 16:24:04

HTML5歐朋W3C

2013-05-28 15:35:47

html5多線程

2015-11-11 15:22:27

h5工具

2011-07-19 13:07:26

iOS4 HTML5 動畫

2015-10-08 08:48:44

HTML5canvas動畫

2014-07-04 09:52:57

HTML5

2012-11-07 09:43:58

IBMdw

2016-01-20 10:11:56

華麗CanvasHTML5

2012-03-29 09:18:47

HTML5WEB

2012-02-23 10:28:43

AppCanHTML5移動應(yīng)用

2015-06-10 10:18:27

WebAPP開發(fā)技巧

2014-07-22 10:58:33

HTML5jQuery

2015-01-13 11:19:19

2013-01-24 10:26:04

HTML5HTML 5HTML5的未來

2011-05-13 17:36:05

HTML

2013-10-21 15:24:49

html5游戲

2012-02-23 14:24:53

傲游3HTML5

2024-07-29 08:43:57

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號