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

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

背景

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

以下是常見的紋理壓縮格式:

  • DDS 或 S3TC:有時稱為 DXTC 或 DXTn。OpenGL 支援這種格式的三種形式。
  • ETC1:大部分的裝置都支援這個格式。這個格式不支援透明度,但遊戲可針對 Alpha 元件使用第二個紋理檔案。
  • ETC2:支援 GLES3 的裝置皆支援這個格式。
  • PVRTC:iOS 遊戲的常用格式,部分 Android 裝置也支援這個格式。
  • ASTC:用於取代前述格式的最新格式。這種格式支援各種區塊大小,因此相較於前述格式更有彈性。這種格式很適合用來最佳化遊戲的大小。

下列百分比的 Android 裝置支援下列格式:

紋理壓縮格式 支援的 Google Play 裝置百分比1
ETC1 99%
ETC2 87%
ASTC 77%
ATC 35%
PVRTC 11%
DXT1 0.7%

1 計算這些百分比時,使用的是 2020 年 9 月透過有效 Google Play 裝置收集到的資料

預設格式

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

除非您要指定特定裝置硬體,否則建議您使用 ETC1 和 ETC2 做為預設格式,因為大部分裝置都支援這些格式。如果您的遊戲指定 OpenGL ES 3.0 以上版本,而您選擇 OpenGL ES 3.0 版保證支援的其中一種 ETC2 格式,那麼您可以選擇 ETC2 做為預設格式。

建構應用程式套件

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

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

如果您的遊戲採用 Unity,您可以使用 Unity 外掛程式建構應用程式套件。

使用 Gradle

  1. 將專案 build.gradle 檔案中 Android Gradle 外掛程式的版本更新為 4.1 初期測試 10 以上版本 (例如 com.android.tools.build:gradle:4.1.0-alpha10)。

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

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

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

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

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

    設定前的目錄 設定後的目錄
    common 資產包
    common/build.gradle
    common/src/main/assets/textures/...
    common 資產包
    common/build.gradle
    common/src/main/assets/textures/...
    common/src/main/assets/textures#tcf_astc/...
    common/src/main/assets/textures#tcf_pvrtc/...
    level1 資產包
    level1/build.gradle
    level1/src/main/assets/textures/...
    level1 資產包
    level1/build.gradle
    level1/src/main/assets/textures/...
    level1/src/main/assets/textures#tcf_astc/...
    level1/src/main/assets/textures#tcf_pvrtc/...
    level2 資產包
    level2/build.gradle
    level2/src/main/assets/textures/...
    level2 資產包
    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」>「Create Android App Bundle」(建立 Android App Bundle),啟動遊戲的 Unity 建構作業。這樣做也會將 AssetBundles 包裝為多個資產包,其中每個 Asset Bundle 名稱都會轉換為單一資產包。

(進階) 使用 bundletool

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

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

  1. 從 GitHub 存放區下載 bundletool

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

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

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

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

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

    設定前的目錄 設定後的目錄
    common 資產包
    common/build.gradle
    common/src/main/assets/textures/...
    common 資產包
    common/build.gradle
    common/src/main/assets/textures/...
    common/src/main/assets/textures#tcf_astc/...
    common/src/main/assets/textures#tcf_pvrtc/...
    level1 資產包
    level1/build.gradle
    level1/src/main/assets/textures/...
    level1 資產包
    level1/build.gradle
    level1/src/main/assets/textures/...
    level1/src/main/assets/textures#tcf_astc/...
    level1/src/main/assets/textures#tcf_pvrtc/...
    level2 資產包
    level2/build.gradle
    level2/src/main/assets/textures/...
    level2 資產包
    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
    

確認應用程式套件的內容

如果您尚未從 GitHub 存放區下載 bundletool,請先完成這項操作。

透過這項工具建構 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