CocosCreator ScrollView性能優化


本文基於CocosCreator2.1.2版本

原文鏈接:https://blog.csdn.net/zzx023/article/details/99851564

 

CocosCreator的ScrollView組件是游戲開發中的常用組件,我們經常在一些商城界面、排行榜界面、任務列表、背包系統等模塊中會使用到它,同時它也是開銷非常大的地方。當我們的需要顯示的條目比較多時,單純簡單的去使用的話,性能很不好。CocosCreator只是實現了最基本的ScrollView,但相應的優化還需要我們根據項目的情況來進行針對性的優化。

 

當數據量比較大時,我們很容易碰到兩個問題:

DrawCall的數量比較高,渲染性能比較低
整個scrollview的節點數太多,導致隱藏或顯示界面時的onEnable和Disable開銷比較大

 


比如下面的這個界面(demo中的ScrollView1場景)

 

 


ScrollView當中有20個Cell,總共的DrawCall達到了790,單個Cell大概有50個節點,總共就有差不多1000個節點,這時我們的開銷會變得非常的大。

 

接下來我們進行一些常規的優化:

首先我們要做的就是合並渲染批次,降低DrawCall,提升渲染性能, 使用自動圖集或使用TexturePacker對碎圖進行打包處理,這樣的話可以讓多個Sprite渲染的紋理都是同一張圖集圖片,這樣的話就可以合並這些sprite的渲染批次,減少DrawCall以及CPU的運算開銷。

 


這里我使用了AutoAtlas來實現,關於AutoAtlas的使用可以參考文檔:Auto-atlas Asset
讓我們來看下效果:

 

 

 

 

同樣是20個cell,DrawCall降低到了556,相比較之前有了比較明顯的降低。

不過這還不夠,如果你是在Google的Chrome瀏覽器上進行調試的話,推薦你可以使用spector.js這個插件,通過這個插件你可以看到每個DrawCall對於紋理的處理情況。
對於原生開發的話,我們可以使用XCode中的GPU analysis功能

 

 

開啟dynamicAtlas功能,開啟這個功能你可以在main.js中的window.boot()方法內加入下面的兩行代碼即可:


 

 

 

 

 

 

 

開啟之后我們可以看到DrawCall大幅下降,部分DrawCall已經合並

 

接下來是對於Label的處理。

Label的處理跟前面我們的優化方案選擇有關系。

如果我們使用了自動圖集或TexturePacker對碎圖進行合並的話,我們可以選擇Label使用bmfont字體,而不是使用系統字體。同時我們將bmfont使用到的紋理資也一起合並到圖集資源中

 

 

 

 

 

可以看到我們的DrawCall又進一步的降低了,目前運行的效果是330個DrawCall

 

 

 

 

 


如果我們前面使用的是dynamicAtlas的功能,那么我們可以選擇Label使用系統字體,同時我們將Label的CacheMode屬性更改為BITMAP

 

 

 

 


這個模式下會將Label的紋理當作一個Sprite紋理,並且參與到dynamicAtlas中去。這樣就可以跟sprite的紋理進行合批處理

 

 

 

 


從這兩個方案可以看出來,都是想辦法對DrawCall進行合並批處理,只是使用dynamicAtlas的話更加的智能,同時也可以更好的適應復雜的節點結構。但需要注意的是,dynamicAtlas會有額外的CPU計算以及動態紋理的繪制開銷,因此需要根據項目的情況去選擇使用。

 

通過cell的位置進行計算,讓顯示范圍外節點的opacity為0,即不顯示,減少dc

在可視范圍外的節點,本身我們就不可見,所以就不需要它再進行繪制,平白增加Drawcall。我們可以將這些可視范圍外節點的opacity屬性設置為0,從而避免繪制,可以有效的降低DrawCall

 

update (dt) {
  var viewRect = cc.rect(- this.view.width / 2, - this.content.y - this.view.height, this.view.width, this.view.height);
  for (let i = 0; i < this.content.children.length; i++) {
    const node = this.content.children[i];
    if (viewRect.intersects(node.getBoundingBox())) {
      node.opacity = 255;
    }
    else {
      node.opacity = 0;
    }
  }
}

 


這里我是將判斷邏輯放在了Update函數中,你也可以將這段方法放到ScrollView的滑動回調中去,這樣的話不用每幀都計算,只在需要的時候才會去進行計算,節約一些CPU的開銷。最終效果我們可以看到,在啟用dynamicAtlas的方案上,DrawCall可以降低到68,相比較最原始的790個DrawCall,效果顯著。

 

 

 

 

 

通過對資源的處理,減少cell中使用mask組件的數量,盡量不使用mask組件


由於mask組件需要在 stencil 和 content 前后都添加修改 gl 狀態的 render command,因此使用mask會打斷我們的DrawCall批處理。因此對於一些特殊的顯示,例如圓角的icon等,如果條件允許,盡量不要使用mask組件來進行處理,而是通過對資源進行處理達到同樣的效果。


目前mask組件、spine組件、dragonBone組件都會打斷批處理,在節點結構上我們要避免被打斷的情況發生。

 

 

 


在這個demo當中,每一個icon都有一個使用了mask組件的子節點。我們去除它,效果如下:

 

最終就只有18個DrawCall,基本上是很極限的DrawCall優化了。畢竟ScrollView本身就有一個mask組件,這個組件我們無法避免,必須要使用。

 

對cell節點進行復用,減少節點數,這一塊改動比較大. 前面我們都是對DrawCall的優化,但實際的節點數量還是很多。當顯示或隱藏這個界面時,大量的節點會帶來大量的enable和disable的開銷。因此我們通過復用節點,根據滑動情況,實時更新cell位置以及顯示內容,從而減少節點的數量。


可以參考CocosCreator官方示例中的ListView示例,原理如下:

具體代碼可以參考demo工程中的ScrollView3場景的實現,最終效果如下:

 

 

 

 

 

 

 

 

20個Cell的ScrollView,實際上只是7個Cell節點在不停的復用顯示,從而表現出來的。與之前的效果以及DrawCall相同,但實際使用的節點數大大降低,大約有300個節點,相比較之前的1000個節點大幅降低。

以上就是ScrollView在性能優化當中的一些常用手段。當然也有一些非常用的手段,這些通常只適用於特殊的項目需求,在這里就不一一介紹了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM