天天看點

【轉】JPG打包壓縮後比原來尺寸還大

作者:劉源

著作權歸作者所有。

想用jpg的話,直接使用WWW加載jpg檔案本身。加載好之後,WWW.texture 就是你要的貼圖。

————————————————————————————————————

題主之前就是這個方法,後來為什麼要改呢。對于題主的這種情況,即使與目前工作流不符,我也會認為有必要單寫流程。優化項目時,由于記憶體、安裝包大小的原因改資源結構是常有的事,有時候甚至要寫專用的導出工具。

另外,AssetBundle開壓縮不一定是壞事,個人目前實際項目中,Android上實測開壓縮更快;而PC和IOS都是不壓縮更快... 目前認為Android裝置讀寫存儲過慢。

擴充閱讀:為什麼Unity不支援jpg

為了滿足實時渲染的需要,Unity會将你的圖檔預先編碼為特定的顯示卡格式,常見的格式有DXT、ETC、PVRTC等。這些格式一般資料非常整齊,顯示卡會直接在顯存中保持壓縮格式,實時讀取像素。對于各個目标平台,Unity有相應的支援格式清單可以手動選擇(各平台不一樣)。

這種編碼速度挺慢的。首次打開一個工程時,Unity主要就是在做各種圖檔的編碼,從jpg、psd等原始格式轉換為顯示卡格式。大工程可達半個小時甚至更久。

常用的顯示卡壓縮格式一般為4bps,就是0.5位元組每像素。另外這些顯示卡壓縮格式,一般未經過數學壓縮,可以被zip等壓縮算法再次壓縮。

* 1280*720 RGB原始圖檔(RGB24):2.63M

* DXT1/ETC壓縮: 0.43M (另外,PVRTC隻支援1024這種2的幂尺寸的)

* AssetBundle開壓縮模式(Unity使用LZMA算法,類似zip):上面數字的70%(照片)到25%(UI圖集)。

jpg由于計算量大,是以不是一種顯示卡能支援的編碼格式。Unity中,WWW可以加載jpg等格式的原始檔案,獲得RGB24這類未壓縮的貼圖。Unity幫你進行了jpg解碼,但是不負責重新編碼。

1. jpg算法 - 顯示卡不支援的算法

很遺憾,jpg并不是一種顯示卡支援的格式。

顯示卡壓縮主要是為了解決顯存限制的問題。顯存是非常有限的,一張 2k*2k的圖檔不壓縮的情況下高達12M,512M的顯存隻能放42張,是以壓縮格式總是在顯存中直接存儲而不會解壓的。顯示卡支援的格式,必須解碼快,非常快,能夠硬體直接從壓縮格式中任意讀像素。

jpg有很高的壓縮比,1:20左右不會有明顯的品質損失,你還可以往1:50甚至更高壓。但是他的計算量過大。jpg的設計目标是實時整體解壓縮,而不是實時随機通路。一方面jpg使用8x8的資料塊作為編碼單元,資料塊過大;另一方面jpg使用了塊變換編碼,然後還對數字進行了壓縮,擠掉了所有水分。讀取單個像素都需要解壓、反變換64個資料。

由于數字進行了壓縮,zip對jpg是沒有效果的。

jpg圖檔被等分成8x8的塊,每塊的64個像素首先變換到頻率域(離散餘弦變換),然後降低高頻品質甚至丢棄一些過小的資料(稱為量化),最後将剩下的資料壓縮成一個串。精髓就在于,圖檔的主要資訊來自于低頻資料,高頻資料精度下降一些一般看不出來。jpg這條路子也是目前視訊編碼的基石之一。

解碼任何一個像素時,都需要讀取對應塊的全部資料流,解壓縮到頻率域,然後再反編碼到64個像素,這樣才能讀出一個像素。可以想象其計算量。

2. 顯示卡支援的壓縮格式

DXT、ETC、PVRTC的算法可以認為是步步進化的。這篇文章介紹了更早的蠻荒時代(DreamCast那個時代)的實時解壓算法,有興趣可以看看。

我們以最簡單的 DXT1 為例。DXT1認為不透明圖檔可用 4x4的小塊糊弄一下人的眼睛,每個4x4小塊隻有2個顔色,以及他們的兩個中間色.... 一共就4個顔色!還特麼有倆個是插值的,不知道你們感覺怎麼樣。解碼非常直接,讀号,兩個顔色插值,結束。

這個簡單的算法獲得了極大的成功,随後被微軟買了,變成DirectX的禦用格式。而且後面的算法都是這類思想:

* 資料塊小

* 不做塊變換,隻用簡單的插值、加減(jpg是64個數的變換) --- 極大減少計算量

* 不做數學壓縮,是以定長,可以直接尋址 --- 再次減少計算量,以及資料依賴性

最後,jpeg和顯示卡壓縮算法都是有損壓縮。就畫質來說,jpeg遠遠勝出。jpeg在1:10時幾乎看不出與原圖的差異,1:20時仍有極好的效果;而顯示卡貼圖壓縮1:6左右就有明顯畫面損失。實際觀察,美術一般能接受寫實模型紋理的壓縮,同時一般難以接受UI壓縮的效果,特别是銳利的斜線和弧線,條狀物,或者半透明漸變都容易出現瑕疵。對于題主的情況,看起來很像背景圖之類的,确實可以考慮使用jpeg。

的答案已經覆寫了原因。簡單來說就是AssetBundle裡的格式是為了讓顯示卡能用,jpg是為了讓空間更小。

補充一點,最近的情況其實在改變,D3D12支援用jpeg作為紋理格式,雖然(應該)還沒有驅動支援了這一點。GPU,尤其是移動GPU,是可以硬體解碼jpeg的,但沒回饋給programmable pipeline的texture sampler。把這條路打通就能直接都jpeg。

------------------------------------------------------------------

總結:

JPG 優點:檔案小,磁盤占用少。

缺點:1,壓縮算法太複雜,解壓費時,不被GPU硬體解壓支援;2,解壓時(後)占用記憶體比其它格式(ETC,PVRTC)記憶體占用大。

ETC格式或PVRTC格式雖然檔案大一些,多占用了一些存儲空間,但其解壓是被GPU直接支援的硬體瞬間解壓,而且解壓後占用記憶體也比JPG小得多。

綜合來看,不應該使用JPG格式。

繼續閱讀