Cocos2d-X的紋理(2)



原文章地址:http://www.geekfaner.com/cocos2d-x/ReadCocos2dxSourceCode16.html

課程概述

“Cocos2d-X的紋理(2)”課程概述

    紋理影響着應用程序包的大小、內存佔用量、內存帶寬,從而影響遊戲性能、用戶體驗以及電耗等,本節將介紹如何對紋理已經優化。

課程筆記

壓縮紋理

    在(Cocos2d-X的紋理(1))一節中,我們講到了將png、jpg、bmp圖片生成Image,將圖片的data和type等存入Image,再由Image生成texture,其中jpg等也算是壓縮圖片。但是這些壓縮圖片通過GL命令glTexImage2D傳入GPU的時候,也需要轉換成GPU所認識的format和type,然後傳輸到GPU,在GPU內存中存爲對應的GPU格式。所以這些壓縮圖片不算壓縮紋理,這些圖片僅減小了應用程序包,並沒有對GPU內存優化帶來幫助。

    壓縮紋理是指在CPU端已經壓縮好,並且被GL命令所能識別,傳輸到GPU端可以直接可以從壓縮紋理中進行採樣渲染。這樣要求壓縮紋理具備4個特點:1、解壓速度快:使得渲染系統可以直接從壓縮紋理中讀取數據;2、隨機讀取:採樣的時候是根據紋理座標去紋理中進行採樣,傳統壓縮技術是使用可變壓縮比例,讀取某個像素點需要解壓很大一部分相關像素,壓縮紋理採用固定壓縮比例,訪問像素是可以根據索引讀取一小塊內容,精準定位;3、不用太在意壓縮質量,使用很高的壓縮率,因爲以大局爲重;4、不用在意編碼速度,因爲將普通紋理壓縮成壓縮紋理是在遊戲開發中進行。壓縮紋理的傳輸使用GL命令glCompressTexImage2D。

    壓縮紋理的隨機讀取的原理是:按照壓縮比例將紋理分成多個像素塊,對每個像素塊進行壓縮,每個像素塊的像素信息存儲在一個像素集合中,對這個像素集合製作一個索引圖。採樣的時候,將紋理座標轉換爲塊索引值,以及該像素點在像素塊中的偏移,根據塊索引值定位到像素塊,再在像素塊中根據偏移抓取到像素點的信息。像素塊的信息還可以根據實際情況進行緩存。

    不同的GPU支持不同的壓縮紋理格式,Apple公司因爲使用PowerVR的GPU,所以對pvr壓縮紋理格式百分之百支持,Android手機則對khronos支持的ETC格式比較支持。具體支持的壓縮紋理格式,可以通過Cocos2d-X提供的API進行check(底層也是調用了OpenGL ES的API進行GL Extension檢查)。在OpenGL ES3.0之後,提供了壓縮紋理標準。

    PVRTC2開始支持NPOT的紋理,支持2bpp和4bpp和壓縮比例,支持Alpha通道。

    ETC是一種有損壓縮紋理格式,支持4bpp的壓縮比例,不支持Alpha通道,針對Alpha通道,可以通過以下2個方式解決:1、將Alpha通道轉化爲灰度圖,關聯到原始紋理,使得紋理高度擴大一倍,在fragment shader中多做一次alpha採樣即可(在Cocos2d-X需要實現一個自定義的shader),但是有限制,因爲紋理高度是有最大值,針對高度在最大值一半以上的紋理不可使用這個辦法;2、單獨生成一張紋理,利用多重紋理的原理,將兩個紋理同時綁定到GL。

紋理緩存管理

    雖然壓縮紋理已經對遊戲進行了優化,但是在遊戲過程中使用了大量的紋理,所以我們還需要從紋理的生命週期進行進一步優化。在Cocos2d-X中提出了紋理緩存的概念。紋理緩存的目的是使在當前場景需要使用的紋理保存在內存中,且同一個紋理只需要加載一次(在場景開始的時候進行加載,在(Cocos2d-X的渲染系統(5))一節中,我們介紹了glTexImage2D用來加載圖片,可以採取每幀加載一張的方式,調用的就是TextureCache的addImageAsync函數)。TextureCache是單例。

    在通過sprite的create方法(傳入參數爲一個圖片)創建sprite的時候,調用TextureCache的addImage方法,如果該圖片已經在TextureCache存在,那麼就直接返回對應的texture,如果不存在,就實例化一個Image,再實例化一個TexImage(引用計數爲1),將TexImage和圖片名稱(也可以用自定義值)存儲在TextureCache的一個unordered_map成員變量中。然後通過sprite的initWithTexture方法將texture賦值給sprite的成員變量,引用計數爲2。如果沒有TextureCache,當創建texture的那一幀結束的時候,引用計數減1,在sprite消失的時候,texture引用計數減1,當創建texture的那一幀結束,且所有相關的sprite都消失,texture就消失了。且texture不容易被其他類使用。如果使用TextureCache,那麼創建的時候引用計數爲1,被元素使用加1,元素消失減1。引用計數爲1的時候,說明沒有被使用,可以通過removeUnusedTextures的方法刪除不用的texture,減少內存。如果確定不用,可以使用removeTexture方法release。removeAllTextures對所有texture進行release。sprite的createWithTexture不會將texture 加入TextureCache

    紋理緩存只是提供了這些方法,還需要是開發者在上層通過引用計數來對紋理進行控制。緩存機制用於處理資源的創建、緩存、刪除、共享,上層的引用計數機制用來管理多個場景之間資源過度和共享。

比如:在一個場景中,使用TextureCache控制該場景中所有的texture(1、2、3),在場景結束的時候,所有的元素都消失,所有的texture引用計數都爲1,如果使用removeAllTextures,那麼所有的texture都被刪除,假如下一個場景,還會用到(2、3、4)的texture,那麼就造成浪費。可以引入了上層引用計數機制。在進入一個場景的時候,對這個場景中所用到的資源引用計數加1,對上一個場景用到的資源引用計數減1,刪除引用計數爲0的資源,將引用計數爲1的資源進行加載。大的遊戲不可能在場景開始的時候加載所有資源,那麼就要根據遊戲的進度進行逐步加載。

紋理恢復機制

    VolatileTextureMgr記錄應用程序正在使用的紋理信息,包括路徑、數據等紋理信息,如果遊戲重啓等,OpenGL ES context被重新創建,可以通過VolatileTextureMgr進行紋理恢復。VolatileTextureMgr會佔用一些內存。

紋理所佔內存大小

    比如100*100的圖片,格式爲RGBA8888,那麼佔得內存大小爲100*100*32/8=4W byte。需要考慮多級紋理。

    更好的優化紋理,需要硬件層面進行提升(加載、內存、特殊壓縮紋理格式的支持),軟件方面(提前加載紋理、減少不用紋理的內存佔用、將小紋理合併成大紋理以減少繪製次數、使用多級紋理、使用多重紋理減少繪製次數、使用alpha預乘),資源方面(使用適當的紋理格式、使用壓縮紋理、設置正確的defalutAlphaPixelFormat)


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章