Hello Habrovchane!
This is my first, but I hope not the last post on Habr, so do not judge strictly.
I would like to share the development that we have successfully implemented in our Heyworks and use on the project Pocket Troops (Expendables). The problem faced by all developers, not only working with NGUI and Unity3d, but also with other engines and packages, is the search for the golden mean between the quality and weight of gaming interfaces (however, this is not only an interface concerns). In this article I will try to help kill two birds with one bullet.
First of all, I want to say a very big thank you to Comrade
Leopotam for the idea that he gave us in the discussion on the
article , so this is all his fault. We developed the idea, wrote a replacement for NGUI shaders, as well as some utilities that simplify life. I will not measure how many bytes we won in the size of the build, how many nanoseconds we lost, using more complex shaders, just to say that all the work done was worth it - winning as art is visible to the naked eye. Also note that despite the fact that the article is tied to NGUI, the approach described here can be successfully used with any, not only UI, textures. You only need to write the appropriate shaders. But I hurry events, because I wanted to start from another.
')
Atlas in our project a lot. This I mean, the choice between visual quality and size in the build was quite sharp for us, especially on the verge of 100mb for iOS :)
Here, for example, the main atlas containing all skill icons and general graphics.

There is also a store atlas, with store icons, and two enhancements atlas, with enhancement icons. Total 4 atlas 2048x2048. And this is not the limit, as the art department has pleased us recently ...
What doubts can not be exactly - atlases must be pressed. And here the first problem pops up - the PVRTC confidently supports only iOS, some androids are holding it, but some don't, so be prepared for memory flights if all of a sudden some device does not understand PVRTC and starts working with uncompressed texture. Actually, at first we had to put up with this state of affairs. In addition to problems with compression support, PVRTC provides visual artifacts on gradients and transitions to transparency. Although for this we had a small hack. We take the texture, open it in Photoshop, impose a new layer filled with gray on top, impose noise on it (Add Noise 12.5%), set the blending method - soft light, subtle transparency of the layer (usually 20-40%), and apply the mask alpha textures so that noise is not applied on transparent areas. (You can read more and with pictures
in the article of another Heyworks employee ) But this did not eliminate noise 100%, especially artifacts were seen at the transition to transparency. It was necessary to allocate especially "noisy" sprites to uncompressed atlases. In short, spinning as they could.
So we came, or rather jumped sharply, to what we have now. And about this in more detail.
The essence of the method proposed by
Leopotam is to separate the alpha channel from the atlas texture, and apply compression to the RGB texture. This, first of all, saves us from noise, and also allows us on ETC to use ETC compression, which was not available for textures with alpha channel.
But what to do with alpha? The first option suggests itself - using Alpha8 textures (though there are rumors that not all iOS devices work adequately with it, but it seems like it was a long time ago and not true). The second option - if we have from 1 to 4 atlases in the project, we can use a separate texture, from
r, g, b, a channels of which will be taken information about the transparency of the sprites of each individual atlas (if there are less than three atlases, this texture will be RGB) .
Having arranged the alpha channels of our four atlases in one texture, we get this kind of psychedel.

However, having measured the total size of the resulting textures, we notice that we lose a little. Not scary, because a noticeable improvement in the quality warms the soul. But we do not stop at this. First, take the texture with alpha channels and make it 16-bit. This bit is enough to transfer the necessary information, and no one will notice the visual difference. Secondly, it has been experimentally clarified, and confirmed by the art department, that if the alpha texture is used in size two times smaller than the corresponding atlas (that is, 1k for 2k atlas), the difference in the eye is not noticeable, but the gain in volume is 4 times!
A reasonable question - what to do if atlases is five or more? There are also resources for this. After all, we have reduced the alpha texture by 4 times, which means we will be able to decompose in squares only 4x4 = 16 atlases! Of course, doing such a titanic work by hand every time you want to change one of the atlases is a thankless task. To do this, I wrote a script that collects alpha channels from atlases, decomposes them in alpha texture, and adjusts the materials — the alpha channel selection mask and the offset of the texture coordinates for each individual material. But there is one subtlety related to how NGUI works with atlases. After all, when an atlas changes, for example, a new sprite is added to it, NGUI, while shuffling sprites, does not work with the original textures, but with their copies baked in satin. But after all, atlases are labeled as RGB, which means that if NGUI reads sprites from atlas, we will lose all the information about transparency. Here it is necessary either to get into the NGUI, which I really would not want, or to do what we did. And we did two methods. The first one is called before changing something in the atlas. He marks all the atlases in his list as RGBA, so that the NGUI works adequately. The second method, “pulls out” alpha channels from atlases, lays them out into a separate texture, adjusts both it and atlas materials as needed, and returns the atlases back to RGB.
Yes, a little about the materials, or rather the shaders. We took the NGUI shader, and rewrote it a bit so that it read alpha not from the alpha channel of the texture of the atlas, but from the alpha texture selected using the mask of a specific channel.

Here we have suffered another subtlety of working with NGUI. The fact is that for the drawing of the seemingly one and the same UI, several modifications of the same shader are used. When you use ClippingPanel - the way of cutting the UI inside it just sets the modification of the shader that will be substituted. And this is SoftClip or AlphaClip (the shader modifications are named accordingly), and therefore these shaders should also be corrected. We did not take into account this moment in the first experiments and got non-working scrolling lists. In addition, in the newer version of NGUI, everything works differently, the shaders are numbered according to a principle that I haven’t studied yet.
So what is this all about?
- Now our UI looks like it was not pressed by PVRTC and ETC compression, compression artifacts are eliminated as much as possible.
- The size of the build has decreased significantly even compared to the version with compressed atlases, I’m not sure what would happen if we didn't press them
- The process of working with atlases has become a bit more complicated, but I believe that the day will come and we will come to full automation
- I am sure that the extra operations in the shader have added calculation cycles to the video card, but so far no one has seen the difference
Under the
link I ask to love and favor:
- Scripts, processing atlases and collecting alpha-texture
- All shaders mentioned in the article
- Asset for setting up the system - you need to put atlas materials that you want to process into it.
With this whole system, we are constantly working, testing, modifying, so that all changes will constantly fall into the bit package (don’t thank, we don’t feel sorry). The scripts are of course not production quality, some constants need to be tightened up for themselves, in particular, the path to the alpha texture, but I do not think that there will be difficulties with this.
I really hope that this material will be very useful to anyone. Waiting for comments, suggestions for improvement, constructive criticism.
Thank!