Unity 之 解决包体过大问题记录和纹理相关知识点整理

  • 一,发现问题:
  • 二,分析问题:
  • 三,解决问题
  • 3.1 问题分析
  • 3.2 解决方案一
  • 3.3 解决方案二
  • 四,相关知识:
  • 4.1 纹理导入:
  • 4.2 正确设置:
  • 4.3 纹理类型:
  • 4.4 特定于平台的覆盖的纹理压缩格式


一,发现问题:

最近在做一个类似于《保卫萝卜》这种每个关卡需要更换一个背景地图的游戏,大概做了六十关。也就是说有六十张比较大的背景图在工程中。

包体大小:

  • 在IOS下打包ipa大小200M。
  • 在Windows下打包apk大小170M。

查看打包日志:

unity 包体优化 unity ios包体过大_unity

打开方式: … --> Open Editor Log --> 搜索“Build Report”

unity 包体优化 unity ios包体过大_unity_02

由上面日志可以看出,包体主要大小占用为:Textures 214.7M 占用包的91.5%;

查看工程中所有贴图所在文件夹大小,一共不到40M。
按照上面资源占比查看第一个图在Unity工程中的大小确实是8.4M,而在文件夹中看却只有340KB。

锁定问题:在Unity中的图片大小和在文件夹中的图片大小不一致。


二,分析问题:

为什么在文件夹中显示为几百kb的图片,到Unity工程中变为几兆?

经过各种折腾,最终确定是因为图片尺寸和在工程中设置的格式导致的。

先看结论:

  • 贴图导入unity后会自动设置成压缩格式,它会先判断贴图是否有透明通道。
  • Android:不带透明通道压缩成ETC1,带透明通道压缩成ETC2,不被4整除的回退到RGBA32
  • IOS: 不带透明通道压缩成RGB PVRTC,带透明通道压缩成RGBA PVRTC ,不是2的整数次幂回退到RGBA32

Texture图片拖入的时候,如下图所示; unity会默认设置ToNerest,这样会自动保证Android平台下图片被4整除,IOS平台下图片是2的整除次幂,所以默认情况下图片都可以得到最好的压缩。

unity 包体优化 unity ios包体过大_ios_03

还有中情况就是将Fromat格式修改为 RGB(A) Compressed ASTC nxn block,详细对比和使用在3.3解决方案二中进行说明

unity 包体优化 unity ios包体过大_ios_04


三,解决问题

3.1 问题分析

游戏背景图使用的是Sprite做的,所以贴图类型使用的是:Sprite(2D and UI),如下图:此时贴图大小就是2.6M。

unity 包体优化 unity ios包体过大_unity 包体优化_05

而类型是Default 并勾选ToNearest时,大小就和在文件夹中的图片大小差不多了,都是300多KB:

unity 包体优化 unity ios包体过大_unity_06


细心的你应该发现了,当Texture Type 选择 Sprite(2D and UI) 时,下面会有行类似下面这样的警告:

Android:

Only textures with wideth/height being multiple of 4 can be compressed to DXT1 format
只有宽度/高度为4倍的纹理才可以压缩为DXT1格式

IOS:

Only POT textures can be compressed to PVRTC format
只有POT纹理可以压缩到PVRTC格式

其实当时要不是全部选中批量修改的话,估计也会注意到这个警告,并且能看到文件大小问题;这样就不会等到打包的时候,再回头来推是什么原因导致包体变大了。【还是不够细心啊…】


3.2 解决方案一

使用 3D物体+材质球 的方式替换 Sprite 做为背景,这样就不用改变Texture类型了。

若只希望使用Sprite(2D and UI)类型,可以参考4.2中导入规则修改下,可以有效减少贴图占比大小。

修改后

  • ipa从近200M降到了87.7M

unity 包体优化 unity ios包体过大_android_07

  • Apk从169M降到了65.1M

3.3 解决方案二

ASTC是在OpenGL ES3.0出现后在2012年中产生的一种业界领先的纹理压缩格式,它的压缩分块从4x4到12x12最终可以压缩到每个像素占用1bit以下,压缩比例有多种可选。ASTC格式支持RGBA,且适用于2的幂次方长宽等比尺寸和无尺寸要求的NPOT(非2的幂次方)纹理。

将移动端的Fromat选项根据需求设置为:

  • RGB(A) Compressed ASTC 4x4 block
  • RGB(A) Compressed ASTC 5x5 block
  • RGB(A) Compressed ASTC 6x6 block
  • RGB(A) Compressed ASTC 8x8 block
  • RGB(A) Compressed ASTC 10x10 block
  • RGB(A) Compressed ASTC 12x12 block

unity 包体优化 unity ios包体过大_android_08


此截图为网页翻译,可能存在不准确情况,原文有详细的测试数据。设置方式:

unity 包体优化 unity ios包体过大_unity 包体优化_09

unity 包体优化 unity ios包体过大_ios_10

适配机型

  1. iOS
    苹果从A8处理器开始支持 ASTC,iPhone6及iPad mini 4以上iOS设备支持,2014年的iPhone 5s及iPad mini 3以前的设备不支持。
  2. 安卓
    安卓主流压缩格式正在从ETC2转向ASTC。
    Unity官方对安卓ASTC格式支持的说明

四,相关知识:

4.1 纹理导入:

  • Unity 支持读取以下文件格式
    BMP,EXR,GIF,HDR,IFF,JPG,PICT,PNG,PSD,TGA,TIFF
    Unity 可导入多层PSD文件,导入时自动展平,但图层在资源本身中维护。
  • 纹理尺寸大小
    理想情况下,纹理尺寸大小应该是每边为2的整数次幂(如:2,4,8,16像素(px)等等)。
    Unity 允许使用NOPT(非2的幂)纹理大小;但是,NPOT纹理大小通常需要多一点内存【我遇到的问题】,并且GPU的采样速度可能更慢。因此,我们尽量让美术出的图使用2的幂大小,以便于提高性能节省内存。
    如果平台或GPU不支持NPOT纹理带下,Unity会对纹理进行缩放和填充已达到下一个2的幂的大小。
    纹理导入后可将Advanced选项选择Not Power of 2,在导入时放大NPOT纹理资源

unity 包体优化 unity ios包体过大_新星计划_11

4.2 正确设置:

纹理会占用大部分内存,因此,导入设置非常重要。通常,请遵循以下规则 :

  • 减小 Max Size :使用能生成视觉上可接受的结果的最低设置。这种非破坏性方式,可以快速降低纹理内存。
    使用 2 的幂 (POT) :Unity 要求移动端纹理压缩格式(PVRCT 或 ETC)采用 POT 纹理尺寸。
  • 制作纹理图集 :将多个纹理放置到单个纹理中,可以减少绘制调用和加快渲染速度。使用 Unity 精灵图集 或第三方 Texture Packer 可以制作纹理图集。
  • 关闭 Read/Write Enabled 选项 :如果启用,此选项在 CPU 和 GPU 可寻址内存中都会创建副本,纹理会占用双倍内存。大多数情况下,应保持此选项为禁用状态。如果要在运行时生成纹理,请通过 Texture2D.Apply 强制执行,并且传入设置为 true 的 makeNoLongerReadable。
  • 禁用不必要的 Mip Map :对于在屏幕上大小保持不变的纹理(如 2D 精灵和 UI 图形),Mip Map 不是必需的,对于与摄像机的距离会变化的 3D 模型,请保留 Mip Map为启用状态。

4.3 纹理类型:

以下是纹理检视面板 (Texture Inspector) 窗口中可用于在 Unity 中配置各种纹理类型的属性

类型名称

解释说明

Default

Default 是用于所有纹理的最常用设置。此选项可用于访问大多数导入纹理的属性。

Normal Map

Normal map 是可将颜色通道转换为适合实时法线贴图的格式。

Editor GUI and Legacy

当我们要在 HUD 或 GUI 控件上使用纹理,选择此项。

Sprite (2D and UI)

当我们要在2D游戏中或者作为UI使用时,选择此项使用此纹理作为精灵。

Cursor

Cursor 是用于将纹理用作自定义游标的格式。

Cookie

当我们需要场景光源的剪影时,选择此项。

Lightmap

Lightmap 是要将纹理用作光照贴图的格式。

Single Channel

当我们需要纹理单通道时,选择此项。


4.4 特定于平台的覆盖的纹理压缩格式

虽然Unity支持上面4.1说的很多种图像格式作为导入纹理的源文件,但在各种平台和设备上都会进行专门格式压缩,这些格式针对快速纹理才有进行了优化,进而各个平台也有自己不同的专有格式。

默认情况下,Unity编辑器会自动将纹理转为核实的格式,已匹配你当前选择平台。大多数平台上,可选择许多不同的受支持的纹理压缩格式。Unity为每个平台设置了一些默认格式,但在某些情况下,我么可能希望覆盖默认值并为某些纹理想选择不同的压缩格式。

要为每个平台应用自定义设置,可是在贴图的导入配置上,选择特定于平台的覆盖 (Platform --> specific overrides)面板覆盖特定平台的默认设置。如下图:覆盖IOS平台

unity 包体优化 unity ios包体过大_unity_12

所有支持的纹理压缩格式

下表显示了每个平台上可用的纹理压缩格式选项以及生成的压缩文件大小(基于 256 像素平方图像)。选择纹理压缩格式需要在文件大小和质量之间取得平衡;质量越高,文件越大。在下面的描述中,假定游戏纹理的最终文件大小为 256 x 256 像素。

纹理压缩格式

描述

大小(256x256 像素纹理)

平台支持

RGB Compressed DXT1

压缩无符号标准化整数 RGB 纹理。

32KB(4 位/像素)

Windows、Linux、macOS、PS4、XBox One、Android(Nvidia Tegra 和 Intel Bay Trail)、WebGL。

RGB Crunched DXT1

与 RGB Compressed DXT1 类似,但使用 Crunch 压缩方式进行压缩。有关 Crunch 压缩的更多信息,请参阅上面的注意事项。

可变,取决于纹理中内容的复杂程度。

Windows、Linux、macOS、PS4、XBox One、Android(Nvidia Tegra 和 Intel Bay Trail)、WebGL。

RGBA Compressed DXT5

压缩无符号标准化整数 RGBA 纹理。

8 位/像素。 64KB(8 位/像素)

Windows、Linux、macOS、PS4、XBox One、Android(Nvidia Tegra 和 Intel Bay Trail)、WebGL。

RGBA Crunched DXT5

与 RGBA Compressed DXT5 类似,但使用 Crunch 压缩方式进行压缩。有关 Crunch 压缩的更多信息,请参阅上面的注意事项。

可变,取决于纹理中内容的复杂程度。

Windows、Linux、macOS、PS4、XBox One、Android(Nvidia Tegra 和 Intel Bay Trail)、WebGL。

RGB Compressed BC6H

压缩无符号浮点/高动态范围 (HDR) RGB 纹理。

64KB(8 位/像素)

Windows Direct3D 11:OpenGL 4、Linux。

RGB(A) Compressed BC7

高质量压缩无符号标准化整数 RGB 或 RGBA 纹理。

64KB(8 位/像素)

Windows Direct3D 11:OpenGL 4、Linux

RGB Compressed ETC

压缩 RGB 纹理。这是适用于 Android 项目的不带 Alpha 通道的纹理的默认纹理压缩格式。

32KB(4 位/像素)

Android、iOS、tvOS。

RGB Crunched ETC

与 RGB Compressed ETC 类似,但使用 Crunch 压缩方式进行压缩。有关 Crunch 压缩的更多信息,请参阅上面的注意事项。

可变,取决于纹理中内容的复杂程度。

Android、iOS、tvOS。

RGB Compressed ETC2

压缩 RGB 纹理。

32KB(4 位/像素)

Android (OpenGL ES 3.0)

RGBA Compressed ETC2

压缩 RGBA 纹理。这是适用于 Android 项目的带有 Alpha 通道的纹理的默认纹理压缩格式。

64KB(8 位/像素)

Android (OpenGL ES 3.0)、iOS (OpenGL ES 3.0)、tvOS (OpenGL ES 3.0)

RGBA Crunched ETC2

与 RGBA Compressed ETC2 类似,但使用 Crunch 压缩方式进行压缩。有关 Crunch 压缩的更多信息,请参阅上面的注意事项。

可变,取决于纹理中内容的复杂程度。

Android (OpenGL ES 3.0)、iOS (OpenGL ES 3.0)、tvOS (OpenGL ES 3.0)

RGB Compressed PVRTC 2 位

高压缩 RGB 纹理。质量低,但较小,因此提高了性能。

16KB(2 位/像素)

Android (PowerVR)、iOS、tvOS。

RGBA Compressed PVRTC 2 位

高压缩 RGBA 纹理。质量低,但较小,因此提高了性能。

16KB(2 位/像素)

Android (PowerVR)、iOS、tvOS。

RGB Compressed PVRTC 4 位

压缩 RGB 纹理。高质量纹理,尤其是颜色数据,但可能需要很长时间压缩。

32KB(4 位/像素)

Android (PowerVR)、iOS、tvOS。

RGBA Compressed PVRTC 4 位

压缩 RGB 纹理。高质量纹理,尤其是颜色数据,但可能需要很长时间压缩。

32KB(4 位/像素)

Android (PowerVR)、iOS、tvOS。

RGB Compressed ATC

压缩 RGB 纹理。

32KB(4 位/像素)

Android (Qualcomm - Adreno)、iOS、tvOS。

RGBA Compressed ATC

压缩 RGBA 纹理。

64KB(8 位/像素)

Android (Qualcomm - Adreno)、iOS、tvOS。

RGB 16 位

65,000 种颜色,没有 Alpha。使用比压缩格式更多的内存,但可能更适合没有渐变的 UI 或清晰纹理。

128KB(16 位/像素)

所有平台。

RGB 24 位

真实色彩,但没有 Alpha。

192KB(24 位/像素)

所有平台

Alpha 8

高质量 Alpha 通道,但没有任何颜色。

64KB(8 位/像素)

所有平台。

RGBA 16 位

低质量真实色彩。这是具有 Alpha 通道的纹理的默认压缩格式。

128KB(16 位/像素)

所有平台。

RGBA 32 位

真实色彩,并有 Alpha。这是具有 Alpha 通道的纹理的最高质量压缩格式。

256KB(32 位/像素)

所有平台。

RGB(A) Compressed ASTC

可变块大小压缩RGB或RGBA纹理。

12x12:0.89 位/像素(256x256 纹理的大小为 7.56KB)10x10:1.28 位/像素(256x256 纹理的大小为 10.56KB)8x8:2 位/像素(256x256 纹理的大小为 16KB);

6x6:3.56 位/像素(256x256 纹理的大小为 28.89KB)

5x5:5.12 位/像素(256x256 纹理的大小为 42.25KB)

4x4:8 位/像素(256x256 纹理的大小为 64KB)

tvOS(所有)、iOS (A8)、Android(PowerVR 6XT、Mali T600 系列、Adreno 400 系列、Tegra K1)。

RGB(A) Compressed ASTC HDR

可变块大小压缩无符号浮点/高动态范围 (HDR) RGB 或 RGBA 纹理。

12x12:0.89 位/像素(256x256 纹理的大小为 7744 字节)

10x10:1.28 位/像素(256x256 纹理的大小为 10816 字节)

8x8:2 位/像素(256x256 纹理的大小为 16KB);

6x6:3.56 位/像素(256x256 纹理的大小为 29584 字节)

5x5:5.12 位/像素(256x256 纹理的大小为 43264 字节)

4x4:8 位/像素(256x256 纹理的大小为 64KB)

Android (Mali T700系列,Adreno 500系列)。. 注意:在不支持ASTC HDR的设备上,纹理在运行时未压缩到RGB9e5,失去alpha通道。

PS:关于 Android 的注意事项

  • 一般情况下,ETC2 压缩是 Android 最高效的选项,可提供最佳的质量与文件大小平衡。
  • 要在纹理中存储 Alpha 通道,请使用 RGBA16 位压缩,这是所有硬件供应商都支持的格式。

官方文档:各平台的推荐、默认和支持的纹理压缩格式