cocos紋理理解


原文https://blog.csdn.net/u010223072/article/details/78287294

理論要點

要點一: 
文件格式與像素格式的區別:文件格式是圖像為了存儲信息而使用的對信息的特殊編碼方式,大都經過了壓縮,它存儲在磁盤或內存中,但是並不能被GPU所識別(jpg,png…),這些圖片格式當被游戲讀入后,還需要經過CPU解壓成像素格式,如:RGBA8888,再傳送到GPU端進行使用。 
而像素格式是能被GPU所識別的,能被快速尋址並采樣。

要點二: 
圖片本身大小和其所占內存大小是兩碼事。這就好比一個zip壓縮包使用時要解壓還原數據,這個zip文件就好比圖片本身,而解壓后的文件就好比圖片所占內存大小。紋理本身大小主要看我們選用什么樣的壓縮格式和壓縮比,而所占內存大小就只由兩個因素決定:1,圖片的像素點個數(分辨率) 2,單位像素占用的字節數(像素格式)。即紋理內存大小 = 紋理長度 * 紋理寬度 * 單位像素占用的字節數,如:一張1136x640的RGBA8888的png圖片占用的內存為 1136x640x4 = 2.8M左右。 
注:cocos引擎中,對於大的背景圖我們一般使用jpg文件格式,jpg壓縮比更大,是有損壓縮,而像素格式使用16位的RGB565格式。但是它占內存大小就不是我們使用的RGB565 16位格式了,cocos會自動把它轉換為RGBA8888 32位格式解析。最終決定圖片占用內存的是它的像素格式和尺寸,與其擴展名無關。png8、png32、jpg、pvr只要其像素格式都是rgba8888,那么最終圖片占用的內存是一樣的。

要點三: 
在cocos中,談談不同紋理實際加載過程中內存變化,先以一張1024*1024 本身大小500k的jpg/png圖片為例: 
1,讀取圖片文件(500k) 
2,把jpg/png數據最終都是按RGBA8888(默認)格式解析(4mb) 
3,釋放500k的圖片內存 
4,上傳給OpenGL紋理數據(4mb) 
5,釋放4mb內存 
注意,這個過程不是必然的順序執行,釋放內存實際是由系統決定的,會很快,但是不一定是立即執行。 所以內存會瞬間飆升到8.5mb左右,然后減少5mb,穩定到4mb左右,這么一個過程變化。這就是我們常說的“間歇性內存飆高”。

而pvr格式顯卡直接支持,加載速度自然要快,不需要開辟臨時內存來讀取pvr圖片,節約了解析圖片數據到紋理這一步的消耗(第2步)。也就是說讀取同樣像素格式的pvr資源(一般用pvr.ccz壓縮格式)消耗4mb,將pvr圖片數據提交給顯卡消耗4mb。然后釋放文件數據4mb。這么看似乎跟Png從內存占用上相比也沒什么優勢。但是如果像素格式用的是RGBA4444那就有很大優勢了,內存少一半。而前面的那種自身不管用什么格式,最終cocos都會把它們的格式統一默認轉換為32位的RGBA8888再上傳GPU。 
注釋: 
1,pvr.ccz其實就是pvr圖片zip打包下,程序讀的時候要先解壓出pvr資源,然后再讀取pvr。不過由於壓縮下可以極大的減小圖片體積,所以雖然多了解壓過程也不會有特別多的cpu消耗,一般我們都是推薦選擇pvr.ccz的。 
2,當加載jpg、png這樣的紋理時,在短時候內,它會消耗約兩倍於(jpg3倍,多jpg到png轉換過程)它本身內存占用的內存大小。這個告訴我們這樣的紋理最好不要一幀內連續加載,最好分散到多幀去完成,因為每幀cocos都會自動回收一次內存,對於這些中間創建的紋理內存會自動釋放,從而避免一幀里內存不至於飆太高。 
3,按照紋理size從大到小的順序加載紋理,由於加載紋理時額外的內存消耗問題,所以,采用按紋理size從大到小的方式來加載紋理是一個最佳實踐。假設,你有一個占內存16MB的紋理和四個占用內存4MB的紋理。如果你首先加載4MB的紋理,這個程序將會使用16MB的內存,而當它加載第四張紋理的時候,短時間內會飆到20MB。這時,你要加載16MB的那個紋理了,內存會馬上飆到48MB(4*4 + 16*2),然后再降到32MB(4*4 + 16)。但是,反過來,你先加載16MB的紋理,然后短時候內飆到32MB。然后又降到16MB。這時候,你再依次加載剩下的4個4MB的,這時,最多會彪到(4*3 + 4*2 + 16=36)MB。在這兩種情況下,內存的峰值使用相差12MB,要知道,可能就是這12MB會斷送你的游戲進程的小命。

如何減小資源占磁盤大小

1,jpg壓縮比最高,質量較好,但是不支持半透明(一般用於背景圖)。 
2、png8同樣圖片會比jpg略大一些,使用ImageAlpha進行轉換,視覺上幾乎看不出差別。 
注: 這兩種圖片格式都可以極大的減少圖片體積(減少70%~80%),但是無助於減少內存。

如何減小資源占內存大小

1,盡量使用顏色深度為16bit的圖片。cocos上通過cc.Texture2D.setDefaultAlphaPixelFormat(cc.Texture2D.PIXEL_FORMAT_RGBA4444)改變默認像素格式,但如果圖片本身的顏色深度是32位,轉換成RGBA4444后,則可能會使圖片失真,看起來就很模糊。這個可以通過TexturePacker工具中開啟抖動算法得到改善(模糊處顏色混合處理)。特別是在擁有Retina顯示的像素密度下,你幾乎看不出16位與32位的紋理之間的差別。

2,碎圖打大圖時,使用NPOT紋理,NOPT是“non power of two”的縮寫,譯作“不是2的冪”。如果紋理圖集(texture atlas)使用NPOT的紋理,它將有一個具大的優勢:它允許TexturePacker更好地壓縮紋理。因此,我們會更少地浪費紋理圖集的空白區域。而且,這樣的紋理在加載的時候,會少使用1%到49%左右的內存。

3,使用pvr格式紋理。因為jpg是沒有透明色的,一個像素最多3字節,而png一個像素4字節,jpg紋理應該占用內存更小才對,但是cocos最終把紋理都會轉換成rgba8888格式,所以無論是jpg還是png,一個像素占用的都是4字節。正因cocos2d對其他紋理支持不夠好,pvr才會顯得那么高效。pvr也不是萬金油。pvr圖像是專門為ios設備上面的powerVR圖形芯片指定的圖形容器,可以直接加載到顯卡上,而不需經過中間的轉化。雖然android設備下可以使用pvr格式,但是不能使用pvrtc4(一個像素只占4bit),希望通過pvr像ios設備上一樣真正減少游戲內存是不太可行的。

4,android上最省內存紋理當然是ETC(一個像素占4bit),不過ETC1沒有alpha通道,需要我們額外通過一些簡單shader實現(同樣大小的遮罩圖做顏色混合)。不過現在最新的ETC2可以直接支持alpha通道了,而且效果更好,但是需要opengles3.0支持,考慮到2.0設備的市場占有率,一般使用ETC1。

實際項目中紋理格式選擇

人生之所以糾結,在於許多事情你可以選擇。上面的紋理格式,同一種情況下,可能多種都適合,那如何選擇呢!我們還是根據具體情況而定: 
1、場景、背景、全屏圖片 
2D手機游戲中,多半都有這樣的圖片,以作為背景,特別在一些SLG,橫版過關游戲中。這種圖片對ALPHA沒有要求,並且,在同一時間,只會出現一張(如果是多張拼接,也不會超過屏幕尺寸太多),內存不會成為關鍵點。所以,在這種情況下,我們大膽選擇JPG就可以了。

2、場景的前景,裝飾物,可移動對象(npc,moster,…) 
這種要看規模,如果規模較小,類型不多。 或者類型雖然多,但同一時間出現在場景中的類型不多,那我們可以選擇壓縮PNG8的方式,它支持ALPHA通道,文件又小。如果同屏可能出現多種這種,則需要考慮在IOS上使用PVRTC,在ANDROID上使用ETC1+ALPHA_MASK。實際上,為了好維護,一般都是統一用pvr.ccz打包。

3、UI 
UI的背景圖,可以優先考慮使用壓縮PNG8,如果達不到精度要求,則使用PNG32。而對於UI的小元素,可以考慮使用壓縮PNG8. 
對於UI的圖標,一般是不帶ALPHA的PVRTC/ETC + 一張公共的ALPHA掩碼圖,通過雙層混合來實現圓邊效果。 因為圖標同屏出現可能較大。 如果圖標能夠控制在一定范圍內,由於圖標是48X48等大小,一張1024x1024的大圖,可以放400個圖標。 換用JPG,也有4MB的開銷,如果這個是可以接受的,也可以使用JPG+ALPHA_MASK的方式。

寫到這里才發現,其實只需要下面一句話就可以搞定。 
這類圖片會不會同時出現多個,同時出現時,內存開銷是否無法接受, 如果確實無法接受,則使用GPU紋理,否則,優先考慮JPG,JPG+ALPHA,或者PNG8。就是說,首先要減小安裝包大小,如果內存有無法接受的情況,才需要用GPU紋理進行優化。

經驗總結

游戲內存優化我們一般可以從這么3個方面入手:引擎自身提供的優化選項,引擎底層框架,語言上層(內存泄漏)。 
下面是一些常用手段: 
首先看紋理優化,為了優化紋理內存使用,必須知道什么因素對紋理內存使用的影響最大。主要有3個因素會影響紋理內存,即紋理格式(壓縮還是非壓縮)、顏色深度和大小。我們可以使用PVR格式紋理減少內存使用。推薦紋理格式為pvr.ccz。紋理使用的每種顏色位數越多,圖像質量越好,但是越耗內存。所以我們可以使用顏色深度為RGB4444的紋理代替RGB8888,這樣內存消耗會降低一半。此外超大的紋理也會導致內存相關問題。所以最好使用中等大小的紋理。 
音頻優化,3個因素會影響音頻文件的內存使用,即音頻文件數據格式、比特率及采樣率。推薦使用MP3數據格式的音頻文件,因為Android平台和iOS平台均支持MP3格式,此外MP3格式經過壓縮和硬件加速。背景音樂文件大小應該低於800KB,最簡單的方法就是減少背景音樂時間然后重復播放。音頻文件采樣率大約在96-128kbps為佳,比特率44kHz就夠了。 
字體和粒子優化,在此有兩條小提示:使用BMFont字體顯示游戲分數時,請盡可能使用最少數量的文字。例如只想要顯示單位數的數字,你可以移除所有字母。至於粒子,可以通過減少粒子數來降低內存使用。

提示與技巧: 
1、一幀一幀載入游戲資源 
2、減少繪制調用,打包大圖 
3、載入紋理時按照從大到小的順序 
4、避免高峰內存使用 
5、使用載入屏幕預載入游戲資源 
6、需要時釋放空閑資源 
7、收到內存警告后釋放緩存資源 
8、使用紋理打包器優化紋理大小、格式、顏色深度等 
9、使用JPG格式要謹慎! 
10、請使用RGB4444顏色深度16位紋理 
11、請使用NPOT紋理,不要使用POT紋理 
12、避免載入超大紋理 
13、推薦1024*1024 NPOT pvr.ccz紋理集,而不要采用RAW PNG紋理


免責聲明!

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



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