Split Alpha channel for Android and iOS
According to a survey (Unity Texture compression and optimization) about various different texture formats in Unity, ETC1
and Split Alpha channel provides the best build size and memory footprint. As mentioned here, Unity currently does not support SplitAlpha on iOS and there was a bug that makes it not work on UI in older versions.
USplitAlpha
is a library that helps you apply Split Alpha texture to both Android and iOS easily. On Android it uses ETC1 RGB4bit
both main texture and alpha texture. On iOS is uses PVRTC RGB4bit
.
The inspiration for this library is drawn from https://github.com/keijiro/unity-alphamask and Unity、Mobile端末向けの画一的なテクスチャ圧縮方法
To apply USplitAlpha into your project, there are 3 main steps:
- Create Split Alpha textures from the original textures
- Create materials that uses Split Alpha
- Apply materials to
UI Image
,UI Raw Image
orSprite
.
Step 1: Create Split Alpha textures from the original textures
- Preconditions:
- The texture that you wish to create alpha channel for must have width and height being power of two and multiple of 4. Note that the texture does NOT have to be squared.
- The texture must also be
png
. If you have apsd
, please convert it topng
first. - The texture must not be packed by Unity SpritePacker, i.e. no packing tag
- In the
Project
view, right-click on the texture. SelectUSplitAlpha>Apply
. This will generate an alpha channel texture and put it in a folder called_alpha
in the same folder as the original texture After that, both the original texture and the alpha texture import settings will be changed to usingETC1 RGB4bit
andPVRTC RGB4bit
on Android and iOS, respectively.
Step 2: Create Material that uses Split Alpha
- Create a new material
- Set the material's shader to one of the shaders in
Plugins/USplitAlpha/Shaders
. For instance, useSplitAlpha/Sprites/Default
shader if you want to apply to Sprites. - The material's shader will have 2 texture fields:
Sprite Texture
andExternal Alpha
(the names might vary slightly according to shaders). Set the original texture toSprite Texture
and the alpha mask textureExternal Alpha
Step 3: Apply material to UI Image, UI Raw Image or Sprite
- Apply the material created in step 2 to the appropriate elements. For
UI Image
andUI Raw Image
, useSplitAlpha/UI/Default
. ForSprites
, useSplitAlpha/Sprites/Default
. For mobile particles, useSplitAlpha/Mobile/Particles/Additive
orSplitAlpha/Mobile/Particles/Multiply
orSplitAlpha/Mobile/Particles/Alpha Blended
- Set the correct sprite. For
RawImage
you don't have to set anything. ForUI Image
andSprite
, you have to choose a sprite inside the original texture. Most of the time, you would want to create the material from an Atlas so that you can batch multipleUI Image
andSprites
to save draw call.
Bonus 1: Batch create split alpha texture
You can actually select several textures and/or folders then choose USplitAlpha>Apply
. This will create split alpha textures for all of the png
files in all subfolders recursively.
Bonus 2: Revert split alpha textures
You can actually select several textures and/or folders then choose USplitAlpha>Revert
to revert the textures to their original settings without split alpha. All of the split alpha textures will be removed and folders _alpha
as well if they are empty.
Bonus 3: Create texture Atlas
I use the plugin SimpleSpritePacker
to create texture atlas from NPOT sprites. You can also use other external tools such as TexturePacker to create atlases.
Bonus 4: Loading from AssetBundle
You can simply put all the textures and materials in AssetBundle and load them from server. Only thing to note is after you load the material, you will have to re-set the shader of the material like so:
material.shader = Shader.Find (material.shader.name);
Bonus 5: Loading atlas from AssetBundle
You cannot put Atlas packed by Unity's SpritePacker and load it back, that's why we have to use manual Atlas. Then, loading sprites by name from an Atlas loaded from AssetBundle is trivial You can use a solution such as UBootstrap.SpriteCollection to do it.
- Select one or more Textures in the Project view
- Right click and select
USplitAlpha > Create ... Materials
- You can create 3 basic particle materials: Additive, Alpha Blended and Multiply or SpriteDefault, or UIDefault
You can find all examples in the scene Assets/Tests/Test
Test A with alpha
uses a material with a single sprite textureTest B with alpha UI RawImage
uses a material with a raw textureTest B with alpha UI
uses the same material asTest B with alpha UI RawImage
Batchable UI Image 1
,..2
, etc. usesItemAtlasUI
material created fromItemAtlas
. This allows to use the same material for many UI Images and allow them to batchBatchableSprite 1
,..2
, etc. is similar toBatchable UI Image 1
, except that the shader is replaced bySplitAlpha/Sprites/Default
Currently, there are 5 Split Alpha shaders corresponding to 5 original shaders:
UI/Default
:SplitAlpha/UI/Default
Sprites/Default
:SplitAlpha/Sprites/Default
Mobile/Particles/Additive
:SplitAlpha/Mobile/Particles/Additive
Mobile/Particles/Multiply
:SplitAlpha/Mobile/Particles/Multiply
Mobile/Particles/Alpha Blended
:SplitAlpha/Mobile/Particles/Alpha Blended
The code for the ogiginal shaders was taken from Unity then modified to support Split Alpha. Extending SplitAlpha support to other shaders is straightforward.
Obviously, the workflow so far is a little laborious. You have to create split alpha textures by hand, create materials by hand, apply material to UI elements by hand. There are so many improvements that can be made to automate all of these tasks better. In fact, all of these improvements have been implemented and applied to production but I cannot share the code.
Improvement 1: Put hard-coded configurable parameters in global settings
Currently, the compression quality is hard-coded. We should put all configurable parameters in a single ScriptableObject.
Improvement 2: Make it work with Unity SpritePacker
This is quite straightforward. When you create split alpha texture, you have to copy all settings from the original texture TextureImporter
, except for the packing tag. You will add a prefix or suffix to the original packing tag instead. Then you have to change PackerPolicy
by creating a custom PackerPolicy
, so that the generated Atlas will use ETC1 RGB4bit
or PVRTC RGB4bit
compression.
Improvement 3: Automatic material creation
This is how you implement:
- Create a lookup table to replace normal shader by a split alpha one. For instance,
UI/Default
will be replaced bySplitAlpha/UI/Default
, and so on. - Create Helper Component (MonoBehaviour) for different visual elements, such as
UIRawImageSplitAlpha
,UIImageSplitAlpha
,SpriteRendererSplitAlpha
,MeshRendererSplitAlpha
and so on. - Helper Components will operate in 2 modes: Editor mode and Play Mode.
- In Editor Mode, Helper Component will create a dummy material, set the correct shader by searching for matching shader in the lookup table in step 1. Then Helper Component will set the original texture and alpha texture correspondingly. Finally, Helper Component will set the dummy material so that the element is displying correctly in Edit Mode.
- In Play Mode, Helper Component will create shared static material instead of dummy material. This is done so that multiple component using the same original texture will also share the same Split Alpha material. One thing to note is that sprites that are packed with Unity's SpritePacker using packing tag can also work.
Now you can simply assign sprites to different visual elements, then set all of those sprites to use the same packing tag and voila, all your visual elements can batch and use Split Alpha. However, this approach can NOT work with AssetBundle.
Improvement 4: Add Helper Component to GameObject automatically
There is still one manual step that you have to do in Improvement 1, that is adding the correct MonoBehaviour to the correct GameObject. We can automate this step like so:
- Create a tool that allows you to select several objects, prefabs, or scenes, recursively.
- Make an Apply function that search for certain Components in those GameObjects, Prefabs, or Scenes. The Components can be
UIImage
,UIRawImage
,SpriteRenderer
,MeshRenderer
or other custom renderer. - Add the corresponding
UIImageSplitAlpha
,UIRawImageSplitAlpha
,SpriteRendererSplitAlpha
,MeshRendererSplitAlpha
or other custom components.
Also add a Revert function to revert the change easily.
Improvement 5: Create Split Alpha material automatically
Create a tool so that users only have to set the main texture, the alpha texture will be filled in automatically by searching in _alpha
folder. This is DONE.
Improvement 6: Reduce the size of Alpha mask
If the alpha mask of a texture is very simple, for instance, it's mostly white pixels or smooth gradation, then it can be downsized to 1/4 or 1/16 of the area of original texture. Then it can be used by expanding it with a bilinear filter.
To include USplitAlpha into your project, you can copy Assets/Plugins/USplitAlpha
to your project folder. Alternatively, you can use npm
method of package management described here.
0.0.5
- Add create materials from selected textures
0.0.4
- Add Apply function for Material
0.0.3
- Add
SplitAlphaReplacer
for Material
0.0.2
- Create namespace
USplitAlpha
- Improve readme
0.0.1
- Initial commit