因为一个疏忽差点被老板开除,Unity解决包体过大的问题记录

3,694 阅读10分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

本文已参与「掘力星计划」,赢取创作大礼包,挑战创作激励金。

一,发现问题:

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

包体大小:

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

查看打包日志:

构建报告

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

由上面日志可以看出,包体主要大小占用为: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的整除次幂,所以默认情况下图片都可以得到最好的压缩。==

图片格式


三,解决问题

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

示例1

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

示例2


细心的你应该发现了,当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格式

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


解决方案:

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

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

修改后

  • ipa从近200M降到了87.7M

ipa大小

  • Apk从169M降到了65.1M apk大小对比

四,相关知识:

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纹理资源

纹理导入

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 中配置各种纹理类型的属性

类型名称解释说明
DefaultDefault 是用于所有纹理的最常用设置。此选项可用于访问大多数导入纹理的属性。
Normal MapNormal map 是可将颜色通道转换为适合实时法线贴图的格式。
Editor GUI and Legacy当我们要在 HUD 或 GUI 控件上使用纹理,选择此项。
Sprite (2D and UI)当我们要在2D游戏中或者作为UI使用时,选择此项使用此纹理作为精灵。
CursorCursor 是用于将纹理用作自定义游标的格式。
Cookie当我们需要场景光源的剪影时,选择此项。
LightmapLightmap 是要将纹理用作光照贴图的格式。
Single Channel当我们需要纹理单通道时,选择此项。

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

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

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

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

选择平台

所有支持的纹理压缩格式

下表显示了每个平台上可用的纹理压缩格式选项以及生成的压缩文件大小(基于 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 位/像素)所有平台。

PS:关于 Android 的注意事项

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