Nhắm mục tiêu định dạng nén kết cấu trong Android App Bundle

Hoạ tiết (texture) là hình ảnh có thể được áp dụng cho bề mặt của mô hình 3D. Kết cấu cũng được trình kết xuất 2D sử dụng để vẽ các phần tử như sprite hoặc nền. Trang này mô tả các định dạng nén kết cấu phổ biến dùng trong trò chơi cũng như cách nhắm đến các định dạng đó trong Android App Bundle. Hãy đọc bài nội dung Giới thiệu về Android App BundlePlay Asset Delivery trước khi bắt đầu hướng dẫn này.

Nền

GPU thường hỗ trợ một tập hợp định dạng nén kết cấu. Định dạng nén kết cấu (hay texture compression format – TCF) là một định dạng tệp được tối ưu hoá cho GPU. GPU tải và kết xuất kết cấu nhanh hơn và dùng ít bộ nhớ hơn so với khi sử dụng một mảng các giá trị RGBA trong bộ nhớ. Việc hỗ trợ này được thực hiện ở cấp độ phần cứng: nhà sản xuất GPU nhúng các thành phần vào vi mạch thẻ đồ hoạ mà đọc, giải nén và kết xuất các định dạng được hỗ trợ.

Sau đây là các định dạng nén kết cấu phổ biến trên phần cứng di động hiện đại:

  • ASTC: Định dạng mới đây được thiết kế để thay thế các định dạng trước đây. Linh hoạt hơn so với các định dạng trước đây do hỗ trợ nhiều kích thước chặn. Việc sử dụng định dạng này là một cách hay để tối ưu hoá kích thước trò chơi.
  • ETC2: Được tất cả thiết bị hỗ trợ OpenGL ES 3.0 trở lên hỗ trợ, tức là bao gồm hầu hết thiết bị di động Android đang hoạt động.

Những định dạng này được hỗ trợ theo tỷ lệ phần trăm gần đúng sau đây của thiết bị Android:

Định dạng nén kết cấu Tỷ lệ phần trăm thiết bị có hỗ trợ trên Google Play
ASTC >80%
ETC2 >95%

GPU máy tính chạy Google Play Games dành cho máy tính cũng hỗ trợ định dạng sau:

  • DDS hoặc S3TC: Đôi khi được gọi là BCn, DXTC hoặc DXTn.

Sau đây là các định dạng nén kết cấu cũ không còn được đề xuất nữa:

  • ETC1: Được hỗ trợ trên hầu hết thiết bị. Định dạng này không hỗ trợ độ trong suốt, nhưng trò chơi có thể sử dụng tệp cấu trúc thứ hai cho thành phần alpha.
  • PVRTC: Phổ biến với các trò chơi iOS và cũng được hỗ trợ trên một số thiết bị Android.

Tính năng hỗ trợ ETC1 chỉ được yêu cầu đối với những trò chơi mà hỗ trợ các thiết bị rất cũ hoặc một số thiết bị Android TV không hỗ trợ OpenGL ES 3.0 trở lên.

Một định dạng mặc định

Với rất nhiều định dạng có sẵn (mức hỗ trợ tuỳ theo thiết bị), có thể bạn sẽ không biết nên sử dụng định dạng nào khi xây dựng kết cấu trò chơi. Như một biện pháp bảo vệ, định dạng gói ứng dụng hỗ trợ bạn chọn một định dạng nén kết cấu mặc định cho mỗi gói tài sản. Nếu thiết bị không hỗ trợ định dạng được chỉ định khác thì những tài sản sử dụng định dạng mặc định này sẽ được cài đặt.

Trừ trường hợp bạn nhắm đến phần cứng thiết bị quá cũ, ETC2 là lựa chọn phù hợp cho định dạng mặc định. Bạn nên sử dụng các định dạng ETC2 được đảm bảo hỗ trợ trong OpenGL ES 3.0. Những định dạng này cũng có trong API đồ hoạ Vulkan.

Định dạng ASTC xác định nhiều kích thước khối nén, cho phép bạn lựa chọn chất lượng hình ảnh giảm nhưng lại có độ nén lớn hơn. Tuỳ thuộc vào bản chất của tài liệu hình ảnh nguồn, đối với một kết cấu nhất định, bạn có thể chọn kích thước khối nhỏ hơn hoặc lớn hơn để duy trì chất lượng hình ảnh ở mức chấp nhận được.

Nếu trò chơi của bạn hỗ trợ Google Play Games cho máy tính và sử dụng Vulkan thì bạn nên thêm kết cấu S3TC. Tất cả GPU máy tính đều hỗ trợ định dạng S3TC.

Tạo gói ứng dụng

Google Play sử dụng Android App Bundle để tạo và phân phát tệp APK được tối ưu hoá cho cấu hình thiết bị của mỗi người dùng. Vì vậy, người dùng chỉ tải mã và tài nguyên họ cần để chạy trò chơi của bạn. Các tệp APK được tối ưu hoá này bao gồm một tập hợp nội dung kết cấu duy nhất, được định dạng bằng định dạng nén tối ưu cho thiết bị.

Nếu trò chơi của bạn không có trong Unity, hãy sử dụng Gradle để tạo một gói ứng dụng. Người dùng nâng cao có thể sử dụng bundletool.

Nếu trò chơi của bạn nằm trong Unity thì Unity 2021.3 trở lên sẽ hỗ trợ gói ứng dụng sử dụng Play Asset Delivery. Để biết thêm thông tin, hãy xem Tài liệu về Unity. Bạn có thể sử dụng trình bổ trợ Unity để tạo gói ứng dụng có các phiên bản Unity thấp hơn.

Sử dụng Gradle

  1. Cập nhật phiên bản trình bổ trợ Android cho Gradle trong tệp build.gradle của dự án lên phiên bản 4.1 trở lên (ví dụ: com.android.tools.build:gradle:4.1.0).

  2. Xác định tập hợp các loại thiết bị mà bạn muốn nhắm đến cho trò chơi của mình cũng như các định dạng nén kết cấu mà chúng hỗ trợ (để biết thêm thông tin về các định dạng, hãy xem nội dung Nền).

  3. Tạo các phiên bản tài sản cho mỗi định dạng nén kết cấu từ bước trước. Quá trình này có thể liên quan đến việc tạo tấm sprite bằng phần mềm như TexturePacker hoặc chạy tập lệnh chuyển đổi tài sản thô thành tài sản có định dạng cụ thể (ví dụ: astc-encoder).

  4. Tạo gói tài sản (xem Bản dựng cho C++ hoặc Java) chứa các tài sản trò chơi và sử dụng Play Asset Delivery. Ví dụ: bạn có thể tạo một gói tài sản cho mỗi cấp hoặc nhiều gói tài sản cho các phần của trò chơi.

  5. Bên trong gói tài sản, hãy thêm các thư mục cho mỗi định dạng nén kết cấu mà bạn muốn hỗ trợ. Thêm hậu tố được hỗ trợ vào tên thư mục kết cấu tương ứng với định dạng nén kết cấu dùng cho các tệp chứa.

    Tạo một thư mục không có hậu tố trong tên (ví dụ: common/src/main/assets/textures/). Trong thư mục này, hãy đặt định dạng mặc định cho tài sản kết cấu. Hầu hết thiết bị đều hỗ trợ định dạng mặc định này (ví dụ: ETC1 hoặc ETC2). Nếu một thiết bị không hỗ trợ các định dạng được chỉ định khác (ví dụ: PVRTC và ASTC trong bảng dưới đây), thì Cửa hàng Google Play sẽ cài đặt thư mục này.

    Thư mục trước Thư mục sau
    gói tài sản common:
    common/build.gradle
    common/src/main/assets/textures/...
    gói tài sản common:
    common/build.gradle
    common/src/main/assets/textures/...
    common/src/main/assets/textures#tcf_astc/...
    common/src/main/assets/textures#tcf_pvrtc/...
    gói tài sản level1:
    level1/build.gradle
    level1/src/main/assets/textures/...
    gói tài sản level1:
    level1/build.gradle
    level1/src/main/assets/textures/...
    level1/src/main/assets/textures#tcf_astc/...
    level1/src/main/assets/textures#tcf_pvrtc/...
    gói tài sản level2:
    level2/build.gradle
    level2/src/main/assets/textures/...
    gói tài sản level2:
    level2/build.gradle
    level2/src/main/assets/textures/...
    level2/src/main/assets/textures#tcf_astc/...
    level2/src/main/assets/textures#tcf_pvrtc/...
  6. Cập nhật tệp build.gradle của ứng dụng để bật tính năng phân chia gói tài sản theo cấu trúc.

    // In the app build.gradle file:
    android {
        ...
        bundle {
            texture {
                enableSplit true
            }
        }
    }
    
  7. Trong Android Studio, hãy chọn Build (Tạo) > Generate Signed Bundle / APK (Tạo gói/tệp APK đã ký) hoặc chạy thao tác Gradle qua dòng lệnh để tạo gói.

Sử dụng trình bổ trợ Unity của Google Play

Tải trình bổ trợ Unity (hoặc gói) của Play Asset Delivery để tạo một gói ứng dụng có gói tài sản được nhắm mục tiêu theo kết cấu.

Chuẩn bị tài sản

Để chuẩn bị tài sản kết cấu cho quá trình tạo gói ứng dụng, hãy làm như sau:

  1. Kết hợp cảnh (scene) và tài sản (asset) của bạn thành nhiều gói AssetBundle.

  2. Xác định tập hợp các loại thiết bị mà bạn muốn nhắm đến cho trò chơi của mình cũng như các định dạng nén kết cấu mà chúng hỗ trợ (để biết thêm thông tin về các định dạng, hãy xem nội dung Nền).

  3. Sửa đổi tập lệnh xây dựng của trò chơi để tạo AssetBundles nhiều lần, một lần cho mỗi định dạng kết cấu mà bạn muốn hỗ trợ. Xem tập lệnh ví dụ sau:

    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. Xác minh rằng mỗi tài sản kết cấu sẽ được xuất ra trong một thư mục có đúng hậu tố trong tên (ví dụ: #tcf_astc).

    Kiểm tra để đảm bảo rằng một thư mục không có hậu tố trong tên là đầu ra (ví dụ: Assets/AssetBundles/). Thư mục này chứa định dạng mặc định của tài sản kết cấu. Hầu hết thiết bị đều hỗ trợ định dạng mặc định này (ví dụ: ETC2). Nếu thiết bị không hỗ trợ các định dạng được chỉ định khác (ví dụ: ASTC trong mã ở bước trước), thì Cửa hàng Google Play sẽ cài đặt thư mục này.

    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. Chọn Google > Android > Assets Delivery.

  6. Nhấp vào Add Folder (Thêm thư mục) để thêm thư mục chứa các gói tài sản mặc định. Các gói này được cài đặt trên những thiết bị không hỗ trợ các định dạng khác mà bạn xác định.

    Hãy nhớ đặt Delivery mode (Chế độ phân phối) cho AssetBundle.

    Định dạng AssetBundle Delivery mặc định của Unity

  7. Nhấp vào Add Folder (Thêm thư mục) để thêm một thư mục chứa AssetBundles được tạo cho một định dạng khác (ví dụ: ASTC). Lặp lại nếu cần.

    Hãy nhớ đặt Delivery mode (Chế độ phân phối) cho mỗi AssetBundle.

    Định dạng ASTC Delivery Bundle của Unity

Tạo

Chọn Google > Build Android App Bundle (Tạo Android App Bundle) để khởi động bản dựng Unity của trò chơi. Phương thức này cũng gói AssetBundles thành nhiều gói tài sản. Mỗi tên AssetBundle sẽ được chuyển đổi thành một gói tài sản.

(Nâng cao) Sử dụng bundletool

Để biết thêm thông tin về bundletool, hãy xem nội dung Tạo gói ứng dụng bằng bundletool.

Để tạo gói ứng dụng, hãy làm như sau:

  1. Tải bundletool xuống qua kho lưu trữ GitHub.

  2. Xác định tập hợp các loại thiết bị mà bạn muốn nhắm đến cho trò chơi của mình cũng như các định dạng nén kết cấu mà chúng hỗ trợ (để biết thêm thông tin về các định dạng, hãy xem nội dung Nền).

  3. Tạo các phiên bản tài sản cho mỗi định dạng nén kết cấu từ bước trước. Quá trình này có thể liên quan đến việc tạo tấm sprite bằng phần mềm như TexturePacker hoặc chạy tập lệnh chuyển đổi tài sản thô thành tài sản có định dạng cụ thể (ví dụ: astc-encoder).

  4. Tạo gói tài sản (xem Bản dựng cho C++ hoặc Java) chứa các tài sản trò chơi và sử dụng Play Asset Delivery. Ví dụ: bạn có thể tạo một gói tài sản cho mỗi cấp hoặc nhiều gói tài sản cho các phần của trò chơi.

  5. Trong nhiều gói tài sản, hãy thêm hậu tố được hỗ trợ vào tên thư mục kết cấu tương ứng với định dạng nén kết cấu dùng cho các tệp chứa.

    Tạo một thư mục không có hậu tố trong tên (ví dụ: common/src/main/assets/textures/). Trong thư mục này, hãy đặt định dạng mặc định cho tài sản kết cấu. Hầu hết thiết bị đều hỗ trợ định dạng mặc định này (ví dụ: ETC1 hoặc ETC2). Nếu một thiết bị không hỗ trợ các định dạng được chỉ định khác (ví dụ: PVRTC và ASTC trong bảng dưới đây), thì Cửa hàng Google Play sẽ cài đặt thư mục này.

    Thư mục trước Thư mục sau
    gói tài sản common:
    common/build.gradle
    common/src/main/assets/textures/...
    gói tài sản common:
    common/build.gradle
    common/src/main/assets/textures/...
    common/src/main/assets/textures#tcf_astc/...
    common/src/main/assets/textures#tcf_pvrtc/...
    gói tài sản level1:
    level1/build.gradle
    level1/src/main/assets/textures/...
    gói tài sản level1:
    level1/build.gradle
    level1/src/main/assets/textures/...
    level1/src/main/assets/textures#tcf_astc/...
    level1/src/main/assets/textures#tcf_pvrtc/...
    gói tài sản level2:
    level2/build.gradle
    level2/src/main/assets/textures/...
    gói tài sản level2:
    level2/build.gradle
    level2/src/main/assets/textures/...
    level2/src/main/assets/textures#tcf_astc/...
    level2/src/main/assets/textures#tcf_pvrtc/...
  6. Thêm thứ nguyên TCF vào tệp siêu dữ liệu của gói ứng dụng (BundleConfig.json). Sử dụng TEXTURE_COMPRESSION_FORMAT cho trường value:

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

    Đặt suffixStripping.enabled thành true để xoá hậu tố (ví dụ: #tcf_astc) khỏi tên thư mục khi tạo gói tài sản. Thao tác này cho phép trò chơi của bạn đọc các tệp từ một tên thư mục đã biết (chẳng hạn như level1/assets/textures). Một số công cụ phát triển trò chơi có thể phát hiện định dạng của tệp, nhờ đó, trò chơi của bạn có thể bỏ qua định dạng của tài sản kết cấu được cài đặt.

    suffixStripping.defaultSuffix chỉ định hậu tố thư mục mặc định khi bundletool tạo một tệp APK độc lập cho các thiết bị chạy Android 5.0 (API cấp 21) trở xuống. Trong bảng ví dụ trước đó, phiên bản mặc định của tài sản kết cấu được cài đặt trên các thiết bị này; đây là hành vi mong muốn trong hầu hết trường hợp.

  7. Tạo gói ứng dụng:

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

Xác minh nội dung của gói ứng dụng

Nếu bạn chưa có tệp, hãy tải bundletool xuống qua kho lưu trữ GitHub.

Xác minh nội dung của gói ứng dụng đầu ra bằng cách tạo các tệp APK từ gói ứng dụng đó và kiểm tra:

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

Kết quả sẽ tương tự như kết quả sau:

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

Những tên này cho biết tiêu chí nhắm mục tiêu TCF được áp dụng đúng cách. Nếu giải nén nội dung của tệp APK cấp độ (ví dụ: asset-slices/level1-astc.apk), bạn có thể xác minh rằng chỉ một thư mục có tên là textures hiện diện.

Kiểm thử gói ứng dụng

Kết nối thiết bị và cài đặt các gói tài sản thích hợp:

bundletool install-apks --apks=APKS.apks

Lệnh này chỉ cài đặt những gói tài sản đáp ứng thông số kỹ thuật của thiết bị. Những thông số kỹ thuật này bao gồm ABI, mật độ màn hình, ngôn ngữ và định dạng nén kết cấu phù hợp nhất. Hoạt động này mô phỏng những hoạt động do Cửa hàng Google Play thực hiện cho trò chơi bạn đã phát hành.

Để xác minh rằng bạn đã cài đặt chính xác các gói tài sản, hãy làm theo các bước sau đây:

  • Sử dụng lệnh bundletool extract-apks để xuất tệp APK được cài đặt cho thiết bị vào một thư mục rồi kiểm tra thư mục này.

    1. Trích xuất thông số kỹ thuật của thiết bị:

      bundletool get-device-spec --output=MY_DEVICE_SPEC.json
      
    2. Chạy bundletool extract-apks bằng thông số kỹ thuật của thiết bị sau:

      bundletool extract-apks --apks=APKS.apks --device-spec=MY_DEVICE_SPEC.json \
          --output-dir out
      
    3. Liệt kê các tệp trong thư mục out và xác minh rằng bạn đã cài đặt các gói tài sản phù hợp. Tên gói tài sản được thêm vào sau tên định dạng kết cấu (ví dụ: level1-astc.apk).

  • Thêm câu lệnh nhật ký trong trò chơi để tạo ra định dạng kết cấu khi tải một kết cấu.

  • Tạo một tập hợp kết cấu kiểm thử (ví dụ: thay thế kết cấu bằng một màu sáng duy nhất cho một định dạng nhất định). Chạy trò chơi và xác minh rằng tập hợp này hiện diện.

Nếu ứng dụng của bạn chứa on-demand hoặc fast-follow gói tài sản, hãy sử dụng giải pháp kiểm thử cục bộ để phân phối tài sản.

Hậu tố được hỗ trợ cho tên thư mục kết cấu

Google Play hiểu các hậu tố sau đâu khi sử dụng trong tên thư mục kết cấu:

  • #tcf_astc dùng để nén kết cấu thích ứng (ASTC)
  • #tcf_atc để nén kết cấu ATI (ATC)
  • #tcf_dxt1 để nén kết cấu S3 DXT1 (DXT1)
  • #tcf_latc để nén kết cấu Luminance-Alpha (LATC)
  • #tcf_paletted để nén kết cấu theo bảng màu chung
  • #tcf_pvrtc để nén kết cấu PowerVR (PVRTC)
  • #tcf_etc1 để nén kết cấu Ericsson (ETC1)
  • #tcf_etc2 để nén kết cấu Ericsson 2 (ETC2)
  • #tcf_s3tc để nén kết cấu S3 (S3TC)
  • #tcf_3dc để nén kết cấu ATI 3Dc (3Dc)

Quy tắc phân phát của Google Play

Google Play sẽ kiểm tra các chuỗi tiện ích OpenGL mà thiết bị sử dụng cũng như phiên bản OpenGL mà thiết bị hỗ trợ. Google Play sử dụng thông tin này để xác định đúng định dạng kết cấu để phân phối đến thiết bị qua Android App Bundle.

Google Play phân phối định dạng đầu tiên (theo thứ tự được liệt kê trong bảng sau) mà thiết bị hỗ trợ.

Nếu thiết bị không hỗ trợ bất kỳ định dạng kết cấu nào trong App Bundle, Google Play sẽ phân phối các định dạng kết cấu được đóng gói ở định dạng mặc định. (Trừ phi bạn đang đến một mục tiêu phần cứng thiết bị cụ thể, ETC1 hoặc ETC2 là lựa chọn tốt cho một định dạng mặc định.) Để biết thông tin về cách gói tài sản ở định dạng mặc định, hãy xem bài nội dung Sử dụng bundletool hoặc Sử dụng trình bổ trợ Unity của Google Play.

Nếu tài sản chưa được đóng gói ở định dạng mặc định, thì Google Play sẽ đánh dấu ứng dụng là không cung cấp cho thiết bị. Trong trường hợp này, người dùng không thể tải ứng dụng xuống.

Định dạng (được chỉ định trong tcf_xxxx) Được hỗ trợ trên các thiết bị có chuỗi tiện ích 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 Không áp dụng được. Thiết bị phải hỗ trợ OpenGL ES phiên bản 3.0 trở lên.
etc1 GL_OES_compressed_ETC1_RGB8_texture
paletted GL_OES_compressed_paletted_texture