cocos紋理理解

2021-08-25 14:08:48 字數 4209 閱讀 2156

原文

要點一: 

檔案格式與畫素格式的區別:檔案格式是影象為了儲存資訊而使用的對資訊的特殊編碼方式,大都經過了壓縮,它儲存在磁碟或記憶體中,但是並不能被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其實就是pvrzip打包下,程式讀的時候要先解壓出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紋理進行優化。

提示與技巧: 

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紋理

cocos2dx 紋理快取的理解

在cocos2dx中顯示一張,需要首先把它從檔案讀取到記憶體,再根據檔案格式進行解碼,轉換為gpu可以識別的格式,這塊可以被gpu識別的 記憶體中的影象資料,被稱為紋理。為了節省記憶體空間,減少大量瑣碎的小檔案的讀取引發的多次i o操作,將多個紋理拼成為乙個大的紋理圖,成為紋理圖集。就像是給別人看你...

CSS 原理理解

網頁製作最初,html規定了 normal document stream 標準文件流 來規範元素在網頁中的顯示法則 標準文件流中元素分兩種 塊內元素,行內元素。行內元素的特點 span標籤 豎直margin中的塌陷現象,上下緊密排列的元素的外邊距並不是兩個元素外邊距之和,而是選取那個最大的外邊距作...

Spring IOC原理理解

ioc,inversion of control,控制倒轉。這是spring的核心,貫穿始終。所謂ioc,對於spring框架來說,就是由spring來負責控制物件的生命週期和物件間的關係。di,dependency injection,依賴注入。在系統執行中,動態的向某個物件提供它所需要的其他物件...