Search Unity

Does Unity Standard Shader pack textures?

Discussion in 'Shaders' started by TimCabbage, Nov 3, 2017.

  1. TimCabbage

    TimCabbage

    Joined:
    Feb 13, 2011
    Posts:
    66
    My current opaque setup:

    Albedo: RGBA
    Metallic: RGBA
    Normals: RGB
    Occlusion: RGBA
    Emission: RGBA

    Would it be possible to instruct Unity to count channels and use the minimum amount of textures?
    We need Albedo RGB, Metallic value and smoothness value, RGB from normals, R from Occlusion,
    So we would need
    RGBA in albedo for color + emission
    RGB for normals
    RGB in metallicvalue, smoothness and occlusion

    Instead of 4 RGBA and 1 RGB textures we get 1 RGBA and 2 RGB textures.

    Is Unity doing this "behind the scenes" and if not, can we make Unity do this somehow?
     
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    No.

    Yes. But first ...

    Why are these two RGBA textures? Occlusion only uses the G channel, and Emission only uses the RGB channels. Neither need or use the alpha. If you want, you can put the Occlusion into the green channel of the Metallic texture already.

    Similarly the Albedo only needs alpha if it's being used for a transparent material, or you're using the alpha for smoothness (in which case the Metallic doesn't need alpha).

    That already brings it down to one RGBA texture, and 3 RGB textures. Or, really 2 DXT5 (compressed RGBA) textures and 2 DXT1 (compressed RGB) texture since Unity compresses normals into a DXT5 by default. In some ways the original content format doesn't matter as much as the final compressed assets. A DXT5 is twice the size of a DXT1 in memory so that alpha matters even more than you think. For example putting the emission into the alpha of the albedo means you only get a grey scale value for the emission texture, but is the same in GPU memory size as using two separate RGB (DXT1) textures.

    In Unity (and many other game engines!) the normal map is stored in a DXT5 texture. This is because the alpha of the DXT5 is much higher quality than the RGB, and the compression artifacts from using DXT1 (which is the same RGB as DTX5) are quite noticeable for normal maps. So instead the red channel from the normal map is stored in the alpha of the DXT5, and the green channel is stored in the green channel. The red and blue of the DXT5 are left blank as the blue channel of the normal map can be reconstructed in the shader from just the red and green. The result is much better shading quality.

    Some engines, and some shader assets on the store for Unity, pack extra information in those "empty" channels. This potentially degrades the normal quality some again, but it may be worth it to you. Common things to pack into the normal are the smoothness and occlusion. Just remember if you're going to do this you'll need to pack the texture manually, and not use the normal map texture import setting. You also can't use Unity's built in UnpackNormal() function.


    So, back to how to actually do this. You'll likely want to use a Surface shader so you can define what texture and channel each element comes from. As for doing the texture packing, it's possible to do it with a custom material inspector, but it'd be much easier to just do it manually, or use an in editor tool of some kind.
    https://docs.unity3d.com/Manual/SL-SurfaceShaders.html
     
    BrettNexefy and hopeful like this.
  3. TimCabbage

    TimCabbage

    Joined:
    Feb 13, 2011
    Posts:
    66
    Wow, that is a great answer!

    I was planning on doing exactly that.

    Thank You Very Much :)