Import postprocessing for 16-bit textures

We have a large number of textures we would like to post-process before compression. For this purpose, we’ve written an AssetPostprocessor class that does what we want by grabbing all the pixels for each mip step in OnPostprocessTexture, fiddling with them, and then writing them back. This works fine for uncompressed truecolor textures or compressed PVRTC/ETC textures and we get the results we want.

However, when we try to do the same for textures we want to be 16-bit truecolor, everything goes south. Apparently, Unity converts the source RGBA32 texture to RGBA4444 before it gets sent to OnPostprocessTexture. This means that GetPixels/SetPixels refuse to operate on the texture. This seems to be a deviation from the usual case, where the uncompressed source RGBA32 texture is sent to OnPostprocessTexture, and compression happens only after we’re done postprocessing it, which is the behavior we want in this case as well.

We attempted to work around the issue by forcing the texture to RGBA32 in OnPostprocessTexture, but this appears to partially break Unity’s import pipeline, resulting in Unity not knowing whether the resulting texture is compressed or not, and seems to create significant issues when switching a project between Android and iOS.

How do we solve this issue? Why does Unity arbitrarily reduce textures to RGBA4444 before postprocessing? How do we make it, well, not do that, or otherwise work around this without breaking the import pipeline?

OnPostprocessTexture, as the name suggests, operates on the texture after it has been imported. So after the source file has been read, converted to target bits per pixel resolution and compressed. For ARGB32, RGB24 and Alpha8 you can still use SetPixels/GetPixels, which operate on the imported, converted to target bpp data, and whatever you set will be compressed afterwards.

In other words it is correct that if you request 16 bpp as an import setting, post-import the imported data is 16 bpp.

Why SetPixels doesn’t work on 16 bpp textures is a different beast, and the answer is probably “because no one ever requested it”. Would that solve your case?

A workaround might be to import the original texture in 32 bpp, but have the post-processor spit out the modified texture as a new asset, which could then be normally imported as 16 bpp with no extra processing. Unfortunately making assets depend on other assets upon import is shady business, as you can’t force in which order they will be imported. Also it won’t play nice with the cache server.