在 Android App Bundle 中指定紋理壓縮格式

「紋理」是可套用至 3D 模型表面的圖片。2D 轉譯器也會使用紋理來繪製合併圖片或背景等元素。本頁面說明遊戲中常用的紋理壓縮格式,以及在 Android App Bundle 中指定這些格式的方式。開始閱讀本指南之前,請先參閱「關於 Android App Bundle」和「Play Asset Delivery」說明文章。

背景

GPU 通常支援一組紋理壓縮格式。紋理壓縮格式 (簡稱 TCF) 是針對 GPU 最佳化的檔案格式。相較於在記憶體中使用 RGBA 值陣列,GPU 載入和算繪紋理的速度較快,所需的記憶體也較少。這項支援是在硬體層級提供:GPU 製造商會將元件嵌入可讀取、解壓縮及算繪受支援格式的顯示卡晶片。

以下是現代行動裝置硬體常見的紋理壓縮格式:

  • ASTC:用於取代前述格式的最新格式。這種格式支援各種區塊大小,因此相較於前述格式更有彈性。這種格式很適合用來最佳化遊戲的大小。
  • ETC2:支援所有搭載 OpenGL ES 3.0 以上版本的裝置。這包括幾乎所有現有的 Android 行動裝置。

約有以下百分比的 Android 裝置支援這些格式:

紋理壓縮格式 支援的 Google Play 裝置百分比
ASTC >80%
ETC2 >95%

搭載 Google Play 遊戲電腦版的電腦 GPU 也支援以下格式:

  • DDS 或 S3TC:有時稱為 BCn、DXTC 或 DXTn

以下為不再建議使用的舊版紋理壓縮格式:

  • ETC1:大部分裝置都支援這個格式。這個格式不支援透明度,但遊戲可針對 Alpha 元件使用第二個紋理檔案。
  • PVRTC:iOS 遊戲的常用格式,部分 Android 裝置也支援這個格式。

只有在遊戲支援的裝置包括非常舊的裝置或不支援 OpenGL ES 3.0 以上版本的特定 Android TV 裝置時,才需要支援 ETC1。

預設格式

由於可用格式很多,所提供的裝置支援程度不盡相同,因此您可能會不知道該使用哪些格式建構遊戲紋理。保險起見,您可以使用應用程式套件格式,為每個資產包選取預設的紋理壓縮格式。如果裝置不支援其他指定格式,系統就會安裝採用這個預設格式的資產。

除非您要指定非常舊的裝置硬體,否則 ETC2 是絕佳的預設格式選擇。建議您使用 OpenGL ES 3.0 保證支援的 ETC2 格式。這些格式也適用於 Vulkan 圖形 API。

ASTC 格式會定義各種壓縮區塊大小,您可以選擇採用較低的影像品質,換取較大的壓縮。視來源圖片材質的性質而定,您或許能為特定紋理選擇較小或更大的區塊大小,用來維持可接受的視覺品質。

如果遊戲支援 Google Play 遊戲電腦版,且使用 Vulkan,則應納入 S3TC 紋理。所有電腦 GPU 都支援 S3TC 格式。

建構應用程式套件

Google Play 會使用 Android App Bundle,針對每位使用者的裝置設定產生及提供經過最佳化的 APK,因此使用者只需下載執行遊戲所需的程式碼和資源。這些經過最佳化的 APK 包含一組紋理資產,並採用最適合裝置的壓縮格式。

如果您的遊戲並非採用 Unity,請使用 Gradle 建構應用程式套件。建議進階使用者使用 bundletool

如果遊戲採用 Unity,可以在 Unity 2021.3 以上版本中取得含 Play Asset Delivery 的應用程式套件支援。詳情請參閱 Unity 說明文件。您可以使用 Unity 外掛程式,以較低版本的 Unity 建構應用程式套件。

使用 Gradle

  1. 在專案的 build.gradle 檔案中,將 Android Gradle 外掛程式的版本更新為 4.1 以上版本 (例如 com.android.tools.build:gradle:4.1.0)。

  2. 決定要為遊戲指定的裝置類型組合,以及這類裝置支援的紋理壓縮格式 (如要進一步瞭解格式,請參閱「背景」一節)。

  3. 為您在前一步驟中指定的每種紋理壓縮格式建構不同版本的資產。這可能包括使用 TexturePacker 等軟體產生 Sprite 工作表,或是執行指令碼,將原始資產轉換為具有特定格式 (例如 astc-encoder) 的資產。

  4. 建立包含遊戲資產的資產包 (請參閱 C++ 或 Java 建構作業相關文章),供 Play Asset Delivery 使用。舉例來說,您可以為每個關卡分別建立一個資產包,或是為遊戲的各個部分建立資產包。

  5. 在資產包中,為您要支援的每種紋理壓縮格式新增目錄。請根據要用於目錄所含檔案的紋理壓縮格式,在紋理目錄名稱後方加上對應的支援後置字串

    建立名稱不含後置字串 (例如 common/src/main/assets/textures/) 的目錄,並在這個目錄中放置紋理資產的預設格式。這個預設格式應該要是大部分裝置支援的格式,例如 ETC1 或 ETC2。如果裝置不支援其他指定格式 (例如下表中的 PVRTC 和 ASTC),Google Play 商店會改為安裝這個目錄。

    設定前的目錄 設定後的目錄
    common asset pack:
    common/build.gradle
    common/src/main/assets/textures/...
    common asset pack:
    common/build.gradle
    common/src/main/assets/textures/...
    common/src/main/assets/textures#tcf_astc/...
    common/src/main/assets/textures#tcf_pvrtc/...
    level1 asset pack:
    level1/build.gradle
    level1/src/main/assets/textures/...
    level1 asset pack:
    level1/build.gradle
    level1/src/main/assets/textures/...
    level1/src/main/assets/textures#tcf_astc/...
    level1/src/main/assets/textures#tcf_pvrtc/...
    level2 asset pack:
    level2/build.gradle
    level2/src/main/assets/textures/...
    level2 asset pack:
    level2/build.gradle
    level2/src/main/assets/textures/...
    level2/src/main/assets/textures#tcf_astc/...
    level2/src/main/assets/textures#tcf_pvrtc/...
  6. 更新應用程式的 build.gradle 檔案,為每個紋理啟用資產包分割功能

    // In the app build.gradle file:
    android {
        ...
        bundle {
            texture {
                enableSplit true
            }
        }
    }
    
  7. 在 Android Studio 中,依序選取「Build」(建構) >「Generate Signed Bundle / APK」(產生已簽署套件/APK」),或透過指令列啟動 Gradle 工作來產生套件。

使用 Google Play Unity 外掛程式

取得 Play Asset Delivery 的 Unity 外掛程式 (或套件),使用指定紋理的資產包建立應用程式套件。

準備資產

如要準備用來建構應用程式套件的紋理資產,請按照下列步驟操作:

  1. 將場景和資產包裝至多個 Unity AssetBundle

  2. 決定要為遊戲指定的裝置類型組合,以及這類裝置支援的紋理壓縮格式 (如要進一步瞭解格式,請參閱「背景」一節)。

  3. 修改遊戲的建構指令碼來產生 AssetBundle 多次 (針對要支援的每個紋理格式分別產生一次)。請參考以下範例指令碼:

    using Google.Android.AppBundle.Editor;
    using UnityEditor;
    
    public class MyBundleBuilder
    {
       [MenuItem("Assets/Build AssetBundles TCF variants")]
       public static void BuildAssetBundles()
       {
           // Describe the AssetBundles to be built:
           var assetBundlesToBuild = new []
           {
               new AssetBundleBuild
               {
                   assetBundleName = "level1-textures",
                   assetNames = new[] {"level1/character-textures", "level1/background-textures"}
               },
               new AssetBundleBuild
               {
                   assetBundleName = "level2-textures",
                   assetNames = new[] {"level2/character-textures", "level2/background-textures"}
               }
           };
    
           // Describe where to output the asset bundles and in which formats:
           var outputPath = "Assets/AssetBundles";
           var defaultTextureFormat = MobileTextureSubtarget.ETC2;
           var additionalTextureFormats = new[] { MobileTextureSubtarget.ASTC, MobileTextureSubtarget.PVRTC }
           var allowClearDirectory = true;
    
           // Generate asset bundles:
           AssetBundleBuilder.BuildAssetBundles(
               outputPath,
               assetBundlesToBuild,
               BuildAssetBundleOptions.UncompressedAssetBundle,
               defaultTextureFormat,
               additionalTextureFormats,
               allowClearDirectory);
    
           // While in this example we're using the UI to configure the
           // AssetBundles, you can use the value returned by BuildAssetBundles
           // to configure the asset packs, if you want to build the bundle
           // entirely using the scripting API.
       }
    }
    
  4. 確認所有紋理資產都已輸出至目錄中,且該目錄的名稱包含正確的後置字串,例如 #tcf_astc

    確認名稱中沒有後置字串的目錄 (例如 Assets/AssetBundles/) 已輸出完畢。該目錄包含紋理資產的預設格式。這個預設格式應該要是大部分裝置支援的格式,例如 ETC2。如果裝置不支援其他指定格式 (例如前一步驟所含程式碼中的 ASTC),Google Play 商店會改為安裝這個目錄。

    Assets/AssetBundles.meta
    Assets/AssetBundles/AssetBundles
    Assets/AssetBundles/AssetBundles.manifest
    Assets/AssetBundles/AssetBundles.manifest.meta
    Assets/AssetBundles/AssetBundles.meta
    Assets/AssetBundles/samplescene
    Assets/AssetBundles/samplescene.manifest
    Assets/AssetBundles/samplescene.manifest.meta
    Assets/AssetBundles/samplescene.meta
    Assets/AssetBundles/texturesbundle
    Assets/AssetBundles/texturesbundle.manifest
    Assets/AssetBundles/texturesbundle.manifest.meta
    Assets/AssetBundles/texturesbundle.meta
    Assets/AssetBundles#tcf_astc.meta
    Assets/AssetBundles#tcf_astc/AssetBundles
    Assets/AssetBundles#tcf_astc/AssetBundles.manifest
    Assets/AssetBundles#tcf_astc/AssetBundles.manifest.meta
    Assets/AssetBundles#tcf_astc/AssetBundles.meta
    Assets/AssetBundles#tcf_astc/samplescene
    Assets/AssetBundles#tcf_astc/samplescene.manifest
    Assets/AssetBundles#tcf_astc/samplescene.manifest.meta
    Assets/AssetBundles#tcf_astc/samplescene.meta
    Assets/AssetBundles#tcf_astc/texturesbundle
    Assets/AssetBundles#tcf_astc/texturesbundle.manifest
    Assets/AssetBundles#tcf_astc/texturesbundle.manifest.meta
    Assets/AssetBundles#tcf_astc/texturesbundle.meta
    
  5. 依序選取「Google」>「Android」>「Assets Delivery」。

  6. 按一下「Add Folder」(新增資料夾),新增包含預設資產套件的資料夾。如果裝置不支援您定義的其他格式,系統就會在裝置上安裝這些套件。

    請務必為 AssetBundle 設定「Delivery mode」(提供模式)。

    Unity AssetBundle Delivery 預設格式

  7. 按一下「Add Folder」(新增資料夾) 來新增資料夾,當中包含專為其他格式 (例如 ASTC) 建構的 AssetBundle。視需要重複執行這個步驟。

    請務必為每個 AssetBundle 設定「Delivery mode」(提供模式)。

    Unity AssetBundle Delivery ASTC 格式

建構

依序選取「Google」>「Build Android App Bundle」,啟動遊戲的 Unity 建構作業。這也會將 AssetBundle 包裝為多個資產包,其中每個 AssetBundle 名稱都會轉換為單一資產包。

(進階) 使用 bundletool

如要進一步瞭解 bundletool,請參閱「使用 bundletool 建構應用程式套件」一節。

如要建立應用程式套件,請按照下列步驟操作:

  1. 下載 bundletool 從 GitHub 存放區中移除

  2. 決定要為遊戲指定的裝置類型組合,以及這類裝置支援的紋理壓縮格式 (如要進一步瞭解格式,請參閱「背景」一節)。

  3. 為您在前一步驟中指定的每種紋理壓縮格式建構不同版本的資產。這可能包括使用 TexturePacker 等軟體產生 Sprite 工作表,或是執行指令碼,將原始資產轉換為具有特定格式 (例如 astc-encoder) 的資產。

  4. 建立包含遊戲資產的資產包 (請參閱 C++ 或 Java 建構作業相關文章),供 Play Asset Delivery 使用。舉例來說,您可以為每個關卡分別建立一個資產包,或是為遊戲的各個部分建立資產包。

  5. 在不同資產包中,根據要用於目錄所含檔案的紋理壓縮格式,在紋理目錄名稱後方加上對應的支援後置字串

    建立名稱不含後置字串 (例如 common/src/main/assets/textures/) 的目錄,並在這個目錄中放置紋理資產的預設格式。這個預設格式應該要是大部分裝置支援的格式,例如 ETC1 或 ETC2。如果裝置不支援其他指定格式 (例如下表中的 PVRTC 和 ASTC),Google Play 商店會改為安裝這個目錄。

    設定前的目錄 設定後的目錄
    common asset pack:
    common/build.gradle
    common/src/main/assets/textures/...
    common asset pack:
    common/build.gradle
    common/src/main/assets/textures/...
    common/src/main/assets/textures#tcf_astc/...
    common/src/main/assets/textures#tcf_pvrtc/...
    level1 asset pack:
    level1/build.gradle
    level1/src/main/assets/textures/...
    level1 asset pack:
    level1/build.gradle
    level1/src/main/assets/textures/...
    level1/src/main/assets/textures#tcf_astc/...
    level1/src/main/assets/textures#tcf_pvrtc/...
    level2 asset pack:
    level2/build.gradle
    level2/src/main/assets/textures/...
    level2 asset pack:
    level2/build.gradle
    level2/src/main/assets/textures/...
    level2/src/main/assets/textures#tcf_astc/...
    level2/src/main/assets/textures#tcf_pvrtc/...
  6. 應用程式套件中繼資料檔案 (BundleConfig.json) 中新增 TCF 維度,並針對 value 欄位使用 TEXTURE_COMPRESSION_FORMAT

    {
      ...
      "optimizations": {
        "splitsConfig": {
          "splitDimension": [
          ...
          {
             "value": "TEXTURE_COMPRESSION_FORMAT",
             "negate": false,
             "suffixStripping": {
               "enabled": true,
               "defaultSuffix": ""
              }
          }],
        }
      }
    }
    

    在產生資產包時,將 suffixStripping.enabled 設為 true,移除目錄名稱中的後置字串,例如 #tcf_astc。這樣一來,遊戲就可以讀取知名目錄名稱 (例如 level1/assets/textures) 中的檔案。某些遊戲引擎可以偵測檔案格式,因此無論安裝時採用的紋理資產格式為何,都不會對遊戲造成影響。

    suffixStripping.defaultSuffix 會指定預設目錄後置字串,用在 bundletool 為搭載 Android 5.0 (API 級別 21) 以下版本的裝置產生獨立 APK 時。在上方的範例表格中,系統會在這些裝置上安裝預設版本的紋理資產,而這也是大多數情況下的指定行為。

  7. 建構應用程式套件:

    bundletool build-bundle --config=BUILD_CONFIG.json \
      --modules=level1.zip,level2.zip,common.zip,base.zip --output=MY_BUNDLE.aab
    

確認應用程式套件的內容

如果還沒試過 下載 bundletool 從 GitHub 存放區擷取

透過這項工具建構 APK 並進行檢查,確認輸出應用程式套件的內容:

bundletool build-apks --output=APKS.apks --bundle=MY_BUNDLE.aab
zipinfo APKS.apks

輸出應該會類似以下的內容:

toc.pb
splits/base-master.apk
splits/base-armeabi_v7a.apk
splits/…
asset-slices/level1-astc.apk
asset-slices/level1-other_tcf.apk
asset-slices/level1-pvrtc.apk

這些名稱表示已正確套用 TCF 指定目標。您可以解壓縮關卡 APK (例如 asset-slices/level1-astc.apk) 的內容,確認是否「只有一個」名為 textures 的目錄。

測試應用程式套件

連結裝置並安裝適用的資產包:

bundletool install-apks --apks=APKS.apks

這項指令只會安裝符合裝置規格的資產包。這些規格包括 ABI、螢幕密度、語言,以及最合適的紋理壓縮格式。這項作業會模擬 Google Play 商店針對您發布的遊戲執行的動作。

如要確認安裝的資產包正確無誤,請執行下列任一操作:

  • 使用 bundletool extract-apks 指令,將系統為裝置安裝的 APK 輸出至目錄,然後檢查這個目錄。

    1. 擷取裝置規格:

      bundletool get-device-spec --output=MY_DEVICE_SPEC.json
      
    2. 根據這個裝置規格執行 bundletool extract-apks

      bundletool extract-apks --apks=APKS.apks --device-spec=MY_DEVICE_SPEC.json \
          --output-dir out
      
    3. out 目錄中列出檔案,並確認系統已安裝適當的資產包。資產包名稱的後方會加上紋理格式名稱 (例如 level1-astc.apk)。

  • 在遊戲中新增記錄陳述式,以便在載入紋理時輸出紋理格式。

  • 產生一組測試紋理,例如將特定格式的紋理改成單一明亮顏色。接著執行遊戲,確認該組測試紋理是否有正確顯示。

如果應用程式包含 on-demandfast-follow 資產包,請使用資產提供作業的本機測試解決方案

支援的紋理目錄名稱後置字串

Google Play 可理解紋理目錄名稱中使用的下列後置字串:

  • #tcf_astc:適用於自動調整可擴充紋理壓縮 (ASTC)
  • #tcf_atc:適用於 ATI 紋理壓縮 (ATC)
  • #tcf_dxt1:適用於 S3 DXT1 紋理壓縮 (DXT1)
  • #tcf_latc:適用於 Luminance-Alpha 紋理壓縮 (LATC)
  • #tcf_paletted:適用於一般區塊化紋理壓縮
  • #tcf_pvrtc:適用於 PowerVR 紋理壓縮 (PVRTC)
  • #tcf_etc1:適用於 Ericsson 紋理壓縮 (ETC1)
  • #tcf_etc2:適用於 Ericsson 紋理壓縮 2 (ETC2)
  • #tcf_s3tc:適用於 S3 紋理壓縮 (S3TC)
  • #tcf_3dc:適用於 ATI 3Dc 紋理壓縮 (3Dc)

Google Play 提供規則

Google Play 會檢查裝置使用的 OpenGL 擴充功能字串和裝置支援的 OpenGL 版本,並根據這項資訊,判斷要從 Android App Bundle 提供給裝置的正確紋理格式為何。

Google Play 會依照下表中所列的順序,提供裝置支援的第一個格式

如果裝置不支援應用程式套件中的任何紋理格式,Google Play 就會提供以預設格式包裝的紋理格式。除非您要指定特定裝置硬體,否則建議您使用 ETC1 和 ETC2 做為預設格式。如要瞭解如何將資產包裝成預設格式,請參閱「使用 bundletool」或「使用 Google Play Unity 外掛程式」章節。

如果資產並未以預設格式包裝,Google Play 會將應用程式標示為不適用於裝置。在這個情況下,使用者無法下載應用程式。

格式 (在 tcf_xxxx 中指定) 支援使用以下 OpenGL 擴充功能字串的裝置
astc GL_KHR_texture_compression_astc_ldr
pvrtc GL_IMG_texture_compression_pvrtc
s3tc GL_EXT_texture_compression_s3tc
dxt1 GL_EXT_texture_compression_dxt1
latc GL_EXT_texture_compression_latc
atc GL_AMD_compressed_ATC_texture
3dc GL_AMD_compressed_3DC_texture
etc2 不適用。裝置必須支援 OpenGL ES 3.0 以上版本。
etc1 GL_OES_compressed_ETC1_RGB8_texture
paletted GL_OES_compressed_paletted_texture