手遊性能優化之深入理解Texture Compression

http://gad.qq.com/article/detail/7154875

一、引子

  手遊項目開發日常裏,經常有美術同學搞不清Photoshop製圖軟件與Unity3D遊戲引擎之間的圖片assets流轉邏輯,在工作輸出時經常出現如下疑問:

1、要JPG的,還是要PNG的?

2、JPG的要壓存爲多高質量的?

3、PNG的還要壓?引擎不是自動處理的麼?

4、爲毛非要正方形的?我這個圖實在是沒法兒做方的怎麼弄?

5、圖太大,要選哪個壓縮方式?有的怎麼選了也沒效果?有的又壓的太糊!

6、這個效果不行,開發沒有還原好啊!

  所以開發或者技美同學要經常解釋這些問題,這裏面的確有些內容比較難以說明白,一個是廠商比較多流派,另一個是有些知識點(技術歷史)需要釐清,本文的作用就在於此,但不會很全面。

  下文中出現Texture的地方均指代在unity3d場景下。

 

、不要混淆JPG/PNG等圖片壓縮格式與Texture Compression

JPG/PNG是變長編碼格式variable bit length,它有個特點:如下圖所示,顏色變化少頻率低的部分,編碼後佔的內存字節數就少。




  所以,編碼後長度變來變去帶來的壞處就是:無法準確的計算出原圖一個座標處的color對應的壓縮到了哪裏?除非你把整張圖片都解壓完畢,如下圖所示。




  這一致命弱點直接導致了GPU 裏的Texture Sample算法機制不可用,所以Unity3D引擎裏也不會直接使用JPG/PNG這種編碼格式來打包圖片assets資源。

  結論:JPG/PNG是用來在遊戲製作流程中間傳遞美術內容的,最終在遊戲引擎裏需要轉變成一種固定碼率的、可尋址的流式壓縮格式,以方便隨機尋址和採樣。

 

、PVRTC/ETC等Texture Compression格式,直接被GPU讀取到顯存,用時無需解壓

  是的,無需解壓!美術同學可能難以理解,JPG壓縮了之後不解壓你怎麼看?對,GPU就是這麼屌!下面舉個例子:

  假設一張4M的RGB三通道JPG圖片,經過ETC1壓縮後變爲1M,GPU 裏的Fragment渲染模塊根據當前的Render State決定去加載Texture Buffer裏對應的某一塊字節數據,然後經過實時的運算來還原出相應的顏色值,即採樣過程,這中間便省去了將整個圖片解壓還原出來的步驟,因爲GPU芯片很擅長這種固定的算法。

  好處顯而易見:1. 支持隨機採樣,不用把整張圖load進內存; 2. 即使整個load進內存,也不用解壓展開成4M;3.如果你嫌1M還是太大,還能在打包遊戲時用ZIP再壓縮一把;

 

、PVRTC 2bpp/4bpp, ETC1, ETC2,  DXT, ASTC 這些都是什麼鬼?

  是的,手機市場就是這麼亂。GPU芯片提供商有Imagination, ARM, NVIDIA, QualComm,各有各的芯片系統(SoC) IP,我們搞軟件開發的要細究起來恐怕會吐血身亡,畢竟是不同的行業。不管那麼多,結論有

1、Imagination是被Intel和Apple兩大頭持股的,iOS平臺得優選他家的PVRTC壓縮格式;

2、ETC1基本上是Android採用的公案,所以選它沒錯,但僅支持RGB三通道,如果還有A通道,得另行單獨壓一張圖;

3、ETC2雖然升級了,但目前的主流OpenGL ES 2.0規格尚不支持,不要多想了;

 

、淺析ETC1 --- 一個像素2個bits是怎麼做到的?

  ETC stands for Ericsson Texture Compression and is an open standard supported in OpenGL and OpenGL ES. The technique allows lossy compression of images at a ratio of 4:1 (depending on input format and compression method).

  ETC1 textures are supported in android and benefit from GPU hardware decompression.


    沒錯,它居然是Ericsson公司發明的壓縮專利,好在是完全公開的,並被OpenGL ES規範所支持。它基於這樣一個事實:人類的視覺系統對明度luminance的敏感度高於色度chrominance。運用這一逆天的道理就能得到逆天的壓縮方式,如下圖:



1、先對圖片進行分塊4*4;

2、每塊取出2個base colors(上下各一個,或者左右各一個),形成左圖;

3、每塊取出明度數據(逐像素的,那就是4*4=16個);

4、算法合成得到右邊的壓縮後的效果;

  所以,ETC1要做的就是把上面2和3中產生的base colors數據和luminance數據給整起來,一起壓縮咯!這真是蛋疼,用2個基色塊就能代表16個像素的顏色,你當玩家眼瞎啊!?

  原理不多說了,直接上圖:




1、4*4的像素塊分爲左右或者上下兩個部分,提取2個base colors,採用差分存儲,一個存爲R5G5B5,差值存爲dR3dG3dB3;

2、如果2個base colors相差太大,導致差值溢出,則直接存2個R4G4B4,比如左邊紅右邊綠的這種極端情況;

3、兩個標記位,綠色的那位表示是555差分存儲呢,還是444獨立存儲;

4、重點是這個table bits,代表這裏兩個base color對應的是明度表裏的index,正好3個bits,表裏也一共2^3=8項;

5、位置剛好夠用:16個RGB像素,編碼進4個bytes,平均下來每個像素只需2個bits;

  Texture被GPU加載到顯存緩衝區之後,怎麼尋址,怎麼採樣,具體細節就不深究了,那是硬件工程師的事情。總之,在這種框架下,ETC的缺點就是

a、不支持RGBA 4通道的圖片壓縮;

b、對顏色連續過渡變化的圖片壓縮後可能有點兒糊(所以美術同學自帶的像素眼會說你把他的圖搞糊了);

  好了,上面就是對項目中常見的材質壓縮問題的終極總結,有了這些知識點,回答前頭的日常問題應該心中有數了(結合項目具體情況取捨)。

 

參考資料:

https://software.intel.com/en-us/articles/accelerating-texture-compression-with-intel-streaming-simd-extensions

http://fileadmin.cs.lth.se/cs/Education/EDAN35/lectures/L8-texcomp.pdf

http://www.powervr.com/Downloads/Factsheets/PVRTextureCompression.pdf

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