Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”.
This article has participated in the “Digitalstar Project” and won a creative gift package to challenge the creative incentive money.
First, find the problem:
I’ve been working on a game like Guard Radish where every level requires a new background map. I’ve done about 60 levels. That means there are 60 large background images in the works.
Inclusion size:
- Package IPA size 200M under IOS.
- Package apK size 170M under Windows.
To view the packaging log:
Opening method:… –> Open Editor Log –> Search for “Build Report”
From the above log, it can be seen that the main size of the package is: Textures 214.7m, which occupies 91.5% of the package;
Check the folder size of all textures in the project, the total size is less than 40M. The size of the first image is indeed 8.4m in Unity, but only 340KB in the folder.
Locking problem: The image size in Unity is not the same as the image size in the folder. = =
Ii. Analysis of problems:
Why do images that are hundreds of KB in folders become megabytes in Unity projects?
After various twists and turns, it was finally determined to be caused by the size of the picture and the format set in the project.
First, the conclusion:
- Once a texture is imported into Unity, it is automatically set to a compressed format, and it determines whether the texture has a transparent channel.
- Android: ETC1 without transparent channels, ETC2 with transparent channels, not divisible by 4 back to RGBA32
- IOS: compressed to RGB PVRTC without transparent channels, compressed to RGBA PVRTC with transparent channels, not an integer power of 2 back to RGBA32
==Texture when the image is dragged in, it looks like the one below; Unity sets ToNerest by default, which automatically ensures that on Android images are divisible by 4 and on IOS images are divisible by 2, so images are best compressed by default. = =
Third, solve problems
The game background is Sprite, so the texture type is: Sprite(2D and UI), as shown below: at this point the texture size is 2.6m.
If you have type Default and check ToNearest, you will have about the same size as the image in your folder, both of which are over 300 KB:
If you’re careful, you’ll notice that when Texture Type is set to Sprite(2D and UI), there will be a warning line like the following:
Android:
Only textures with wideth/height being multiple of 4 can be compressed to DXT1 format
Only textures with 4x width/height can be compressed to DXT1 format
IOS:
Only POT textures can be compressed to PVRTC format
Only POT textures can be compressed into PVRTC format
In fact, if not all selected batch modification, it is estimated that you will also notice this warning, and can see the file size problem; That way, you don’t have to wait until it’s time to pack and then go back and figure out what caused the bag to get bigger. 【 Still not careful enough…】
Solution:
Replace the Sprite background with a 3D object and Texture ball so you don’t have to change the Texture type.
If you only want to use Sprite(2D and UI), you can refer to the import rules in 4.2 to modify the texture ratio.
The modified
- The ipa dropped from nearly 200M to 87.7M
- Apk decreased from 169M to 65.1M
Iv. Relevant knowledge:
4.1 Texture Import:
-
BMP, EXR, GIF, HDR, IFF, JPG, PICT, PNG, PSD, TGA, TIFF Unity can import multi-layer PSD files, which will automatically flatten when importing, but the layers are maintained within the resource itself.
-
Ideally, the texture size should be an integer power of 2 on each side (e.g., 2, 4, 8, 16 pixels (px), etc.).
Unity allows texture sizes using NOPT (non-power of 2); However, NPOT texture sizes generally require a bit more memory (the problem I encountered), and the GPU sampling speed can be slower. Therefore, we try to use a power of 2 in our art diagrams to improve performance and save memory.
If the platform or GPU does not support an NPOT texture strip, Unity will scale and fill the texture up to the next power of 2.
After importing the texture, you can set the Advanced option to Not Power of 2 and enlarge the NPOT texture resource during importing
4.2 Correct Settings:
Textures take up most of the memory, so importing Settings is very important. In general, follow these rules:
- Reduce Max Size: Use the lowest setting that produces visually acceptable results. In this non-destructive way, texture memory can be quickly reduced.
Use power of 2 (POT) : Unity requires mobile texture compression format (PVRCT or ETC) to adopt POT texture size.
- Make texture atlas: Placing multiple textures into a single texture can reduce drawing calls and speed up rendering. Texture atlas can be created using the Unity Sprite Atlas or a third-party Texture Packer.
- Turn off the Read/Write Enabled option: If Enabled, this option creates duplicates in both CPU and GPU addressable memory, and textures take up double memory. In most cases, you should leave this option disabled. If you want to generate a texture at run time, force it through Texture2d.apply and pass in makeNoLongerReadable set to true.
- Disable unnecessary Mip Maps: Mip maps are not required for textures that remain the same size on the screen (such as 2D sprites and UI graphics), and for 3D models that vary in distance from the camera, leave Mip Map enabled.
4.3 Texture type:
Here are the properties in the Texture Inspector window that you can use to configure various Texture types in Unity
Type the name | explain |
---|---|
Default | Default is the most common setting for all textures. This option can be used to access the properties of most imported textures. |
Normal Map | A Normal map is a format that converts color channels to a format suitable for real-time Normal mapping. |
Editor GUI and Legacy | Select this option when we want to use textures on HUD or GUI controls. |
Sprite (2D and UI) | Select this option to use this texture as a Sprite when we want to use it in 2D games or as a UI. |
Cursor | Cursor is a format for using textures as custom cursors. |
Cookie | Select this option when we need a silhouette of the scene light source. |
Lightmap | A Lightmap is the format for using a texture as a Lightmap. |
Single Channel | Select this option when we need to texture a single channel. |
4.4 Platform-specific overlay texture compression format
While Unity supports many of the image formats described in 4.1 above as source files for importing textures, it compresses them on all platforms and devices in specialized formats that are optimized for fast textures, and each platform has its own proprietary format.
By default, the Unity editor will automatically convert the texture to a verified format that matches your current platform of choice. On most platforms, there are many different supported texture compression formats to choose from. Unity sets some default formats for each platform, but in some cases we may want to override the defaults and choose a different compression format for certain textures.
To apply custom Settings for each Platform, select the platform-specific override panel to override the platform-specific default Settings for the map import configuration. The following figure shows the coverage on IOS platforms
All supported texture compression formats
The following table shows the texture compression format options available on each platform as well as the generated compression file size (based on a 256 pixel square image). Choosing a texture compression format requires a balance between file size and quality; The higher the quality, the larger the file. In the description below, assume that the final file size of the game texture is 256 x 256 pixels.
Texture compression format | describe | Size (256×256 pixel texture) | Platform support |
---|---|---|---|
RGB Compressed DXT1 | Compressed unsigned normalized integer RGB textures. | 32KB (4 bits/pixel) | Windows, Linux, macOS, PS4, XBox One, Android (Nvidia Tegra and Intel Bay Trail), WebGL. |
RGB Crunched DXT1 | Similar to RGB Compressed DXT1, but using Crunch compression for compression. For more information on Crunch compression, see the notes above. | Variable, depending on the complexity of the content in the texture. | Windows, Linux, macOS, PS4, XBox One, Android (Nvidia Tegra and Intel Bay Trail), WebGL. |
RGBA Compressed DXT5 | Compressed unsigned normalized integer RGBA textures. | 8 bits per pixel. 64KB (8 bits/pixel) | Windows, Linux, macOS, PS4, XBox One, Android (Nvidia Tegra and Intel Bay Trail), WebGL. |
RGBA Crunched DXT5 | Similar to RGBA Compressed DXT5, but using Crunch compression. For more information on Crunch compression, see the notes above. | Variable, depending on the complexity of the content in the texture. | Windows, Linux, macOS, PS4, XBox One, Android (Nvidia Tegra and Intel Bay Trail), WebGL. |
RGB Compressed BC6H | Compressed unsigned floating point/high dynamic range (HDR) RGB textures. | 64KB (8 bits/pixel) | Windows Direct3D 11: OpenGL 4, Linux |
RGB(A) Compressed BC7 | High quality compressed unsigned normalized integer RGB or RGBA textures. | 64KB (8 bits/pixel) | Windows Direct3D 11: OpenGL 4, Linux |
RGB Compressed ETC | Compress RGB textures. This is the default texture compression format for textures without Alpha channels for Android projects. | 32KB (4 bits/pixel) | Android, iOS, tvOS. |
RGB Crunched ETC | Similar to RGB Compressed ETC, but Crunch compression is used for compression. For more information on Crunch compression, see the notes above. | Variable, depending on the complexity of the content in the texture. | Android, iOS, tvOS. |
RGB Compressed ETC2 | Compress RGB textures. | 32KB (4 bits/pixel) | Android (OpenGL ES 3.0) |
RGBA Compressed ETC2 | Compress RGBA textures. This is the default texture compression format for Android projects with Alpha channels. | 64KB (8 bits/pixel) | Android (OpenGL ES 3.0), iOS (OpenGL ES 3.0), tvOS (OpenGL ES 3.0) |
RGBA Crunched ETC2 | Similar to RGBA Compressed ETC2, but using Crunch compression. For more information on Crunch compression, see the notes above. | Variable, depending on the complexity of the content in the texture. | Android (OpenGL ES 3.0), iOS (OpenGL ES 3.0), tvOS (OpenGL ES 3.0) |
RGB Compressed PVRTC 2 bits | High compression RGB texture. The quality is lower, but smaller, thus improving performance. | 16KB (2 bits/pixel) | Android (PowerVR), iOS, tvOS |
RGBA Compressed PVRTC 2 bits | High compression RGBA texture. The quality is lower, but smaller, thus improving performance. | 16KB (2 bits/pixel) | Android (PowerVR), iOS, tvOS |
RGB Compressed PVRTC 4 bits | Compress RGB textures. High quality textures, especially color data, but can take a long time to compress. | 32KB (4 bits/pixel) | Android (PowerVR), iOS, tvOS |
RGBA Compressed PVRTC 4 bits | Compress RGB textures. High quality textures, especially color data, but can take a long time to compress. | 32KB (4 bits/pixel) | Android (PowerVR), iOS, tvOS |
RGB Compressed ATC | Compress RGB textures. | 32KB (4 bits/pixel) | Android (Qualcomm – Adreno), iOS, tvOS. |
RGBA Compressed ATC | Compress RGBA textures. | 64KB (8 bits/pixel) | Android (Qualcomm – Adreno), iOS, tvOS. |
RGB 16 | 65,000 colors, no Alpha. Uses more memory than compressed formats, but may be better for UI without gradients or clear textures. | 128KB (16 bits/pixel) | All platforms. |
24 bit RGB | True colors, but no Alpha. | 192KB (24 bits/pixel) | All platforms |
Alpha 8 | High quality Alpha channel, but without any color. | 64KB (8 bits/pixel) | All platforms. |
RGBA 16 | Low quality true color. This is the default compression format for textures with Alpha channels. | 128KB (16 bits/pixel) | All platforms. |
RGBA 32-bit | True colors and Alpha. This is the highest quality compression format for textures with Alpha channels. | 256KB (32 bits/pixel) | All platforms. |
PS: A note about Android
- In general, ETC2 compression is Android’s most efficient option, providing the best quality and file size balance.
- To store Alpha channels in textures, use RGBA 16-bit compression, which is supported by all hardware vendors.