Unity中打包Texture到AssetBundle反而比原資源jpg格式還要大,該怎麼減小空間?

將1000張的jpg圖片拖入Unity,格式設為Texture,並且進行不壓縮的方式打包成assetbundle格式。原本一共才50M的jpg,最後居然打包出來340M的assetbundle!!!翻了快7倍!!!

後來看了一下才發現是在jpg變成texture時60多k變成了340多k。可見打包的問題不大,主要都出在格式轉換上。

請問如何才能讓jpg轉為texture時不要大那麼多?

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

最早我是只創建一個texture,然後通過代碼控制,利用文件流讀取的方式等需要的時候再給texture賦值,這樣我的1000張jpg圖片都在項目的外面,項目內只有一個空的texture,可以省很多的空間。但是後來為了打包使用,就不得不把jpg圖片放到項目裡面了,於是每一張jpg都變成了一個texture。

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

之前看過一篇教程,說的就是減少圖片佔用內存,參考資料在這裡Unity3D–Texture圖片空間和內存佔用分析

但是為了效果好,我用的圖片1280*720是不能改變大小,24的位深度也不能改。。。

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

不要和我說打包的時候壓縮,為了後期的使用,打包的時候時不可以壓縮的。就算要壓縮,也是打包完以後再壓縮。

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

在我的理解中,我和Unity做的事是這樣的:我把jpg放到項目中-&>unity自動轉成顯卡認識的格式texture-&>unity把一堆的texture打包成assetbundle。

在另個項目中:Unity先讀到項目外的資源包(assetbundle)-&>unity讀到資源包里的texture(每次讀一個)-&>unity把讀到的texture貼到面片上。

這樣在真正要用圖片的那個項目中,Unity少做了一步格式轉換(這個很耗時間),但是內存就。。。

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

jpg的圖片是用pr從視屏里切下來的,那時候是考慮到圖片不能太大,效果又不能太差,折中了選擇jpg格式。

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

/(ㄒoㄒ)/~~為什麼每次都這樣,明明只想解決問題A,結果方案123可能會引起問題BCD .....((/- -)/小小的抱怨一下,你們繼續哈~


回答:

想用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個數的變換) --- 極大減少計算量

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

由於不做數學壓縮,所以這類圖片都可以被zip等演算法大幅度再次壓縮。

順便一提,這類演算法的編碼比較耗時,而且結果不唯一。以DXT1為例,我們有16個像素,現在要挑兩個顏色,以及他們連線上的2個中間色代替這16個像素,哪兩個顏色最合適呢?顯然計算量就上來了,選擇也很多。

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


@劉源 的答案已經覆蓋了原因。簡單來說就是AssetBundle里的格式是為了讓顯卡能用,jpg是為了讓空間更小。

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


樓上各位大神把原理都講得非常透了

另外不使用BuildAssetBundleOptions.UncompressedAssetBundle標記就會默認壓縮打包。。

這裡再補充一點如圖:

texture 的inspector窗口裡面有這麼一個選項,勾選後再發布或者對它進行AssetBundle打包後會自動生成mipmaps,這樣也會增大AssetBundle的體積。

如果這時題主解包你的AssetBundle,就可以看到多張大小不一樣的同一張圖片,這是u3d為你自動生成的mipmaps。

所以如果題主這張圖片的用在UI上面,不希望它在調低QualitySettings時變糊,那麼就把這個選項去掉吧~


jpeg是壓縮格式解碼後自然會大。關於這個一個朋友已經做了方案。基本思路是ab用uncompressed形式生成,文件本身用lazm壓縮,載入時解壓然後 create from file。這個方案她已經在公司項目上應用了,切實可行。


每個平台的格式不一樣,你可以在編輯器裡面點擊你的圖片,在圖片屬性面板修改圖片類型或對應平台Override圖片格式和大小。然後在下面的預覽窗口裡面可以看到佔用的大小。

如果非要使用jpg,可以把jpg放入StreamingAssets目錄,程序中動態載入使用(但是這樣就需要cpu解壓圖片然後上傳給gup使用,內存和性能都會差一些)。


不知道你是什麼平台 在不同的平台下用不一樣的格式。強制用2的N次冪的紋理,如果不是改成是,一定要改!改這個不會影響質量。


只說說AB方面的一些.

這裡你說AB不能壓縮,我猜想你是用這種方式來讀取AB的:

AssetBundle.CreateFromFile(fileName);

這種方式優點是可以從網上下載下來保存到本地沙盒,然後再讀取文件.(遊戲這邊叫熱更新)

缺點也很明顯,AB不能壓縮

但是有補救的方法,就是Unity製作完不壓縮的AB,自己寫方法來壓縮,然後下載下來在程序里自己寫方法來解壓縮,然後把解壓好的AB放在對應的沙盒目錄下

這是雨松MOMO的博客 Unity3D研究院之LZMA壓縮文件與解壓文件 我就是根據這篇文章來解決問題的,希望對你有幫助


選成texture格式 unity默認改成平台gpu支持的格式。jpg是對文件進行有損壓縮,所以會變大。如果你們之前用jpg效果滿意 繼續用jpg就好。不走unity那套就好


請問怎麼才可以把貼圖模型等打包成assetbundle格式的文件?望回答!!!


jpg如果打包在App里,那就直接放到StreamingAssets目錄下,用WWW載入。

如果需要從網路端載入,那麼也不需要打包成AssetBundle,直接作為靜態資源用WWW載入就好了。


直接存jpg為二進位文件,改它的後綴名為bytes,打包成AB,然後再在運行時讀這個文件,解成圖片。


推薦閱讀:

我是否該踏入遊戲行業?
如何評價Unity5中多人遊戲和網路模塊UNet?
想學習unity3d,哪位能給個學習路線圖?謝謝
獨自摸索unity近兩年了,沒跟過完整項目,想自己搭建一個通用框架,不知道如何下手,從哪入手?
貼圖、紋理、材質的區別是什麼?

TAG:遊戲開發 | Unity遊戲引擎 |