Shader Export Size Optimization

Does anyone know a way to reduce the size of the shaders in exported resource files? Here’s an example from our project:

314.6 kb 51.3% Assets/Shared Assets/Avatar/Joel/Body/Joel Body Fbx.fbx
85.4 kb 13.9% Assets/Shared Assets/Avatar/Joel/Body/JoBo_Eyes_dyeA.psd
83.8 kb 13.7% Assets/Shared Assets/Shaders/SpecularDyemap.shader
42.7 kb 7.0% Assets/Shared Assets/Avatar/Joel/Body/JoBo_Eyes.psd
28.4 kb 4.6% Assets/Shared Assets/Shaders/Avatar Skin.shader
11.4 kb 1.9% Assets/Shared Assets/Avatar/Joel/Body/Joel Body.prefab
10.7 kb 1.8% Assets/Shared Assets/Avatar/Joel/Body/JoBo_Face_fCol.psd
10.7 kb 1.8% Assets/Shared Assets/Avatar/Joel/Body/JoBo_Body_fCol.psd
0.4 kb 0.1% Assets/Shared Assets/Avatar/Joel/Body/JoBo_Face.mat
0.4 kb 0.1% Assets/Shared Assets/Avatar/Joel/Body/JoBo_Body.mat
0.4 kb 0.1% Assets/Shared Assets/Avatar/Joel/Body/JoBo_Eyes.mat
0.2 kb 0.0% Assets/Shared Assets/Avatar/Joel/Body/JoBo_EyeWhites.mat
0.1 kb 0.0% Assets/Shared Assets/Avatar/Joel/Body/JoBo_MouthBack.mat
0.1 kb 0.0% Assets/Shared Assets/Avatar/Joel/Body/JoBo_Eyebrows.mat
0.1 kb 0.0% Assets/Shared Assets/Avatar/Joel/Body/JoBo_Teeth.mat

Those shaders are larger than I’d expect. Are they the binaries for all the targets that unity can render on? If that is the case, is there any way to reduce the size of the shaders?

Does anyone have any tips for reducing the filesize here?

Thanks,
Mortoc

well the shader lab hides a lot of complexity when you use the normal multiplication etc.
Those stuff ends as multiple lines and multiple fallbacks, because the engine has different distinct render behaviors.

So the more you use “automagic” shaderlab functionality, the larger the potential output shader will be but the better it runs on the different systems as well.
The same goes for cg code that will lead to GLSL and HLSL code for usage on the corresponding APIs
Especially bump - specular and similar weight heavy due to the needed fallback to run on crippled stuff like ATI or Intel that are missing stuff in different generations NVIDIA already had with the GeForce 5200 years earlier for example.

If you have to care about 28kb for a shader thought the question would be what you attempt to get. Higher visuals normally are used by users with higher end machines and likely a 5mbit+ broadband. So definitely nothing to care. Especially as normal textures already use more space when in a normal size for todays games (512x512++)

But perhaps I miss an elemental point.

Are you sure about that? I would think that’s a useless conversion as Cg already is cross-platform (and cross-API)…

Shaders are compiled text files. You can see the compiled text in Unity 2.1 shader inspector. As they are text files, they compress really really well (e.g. I’d imagine a 80 kilobyte shader would compress to a kilobyte or even less).

Largest shaders are the ones who are pixel lit and support shadows. In that case, each Cg shader inside gets compiled into 172 actual hardware shaders. So if you have a vertex shader and a pixel shader, well, that’s 217*2=68 actual shaders.

(17 is the combination count to support all light types and all shadow types, 2 is for D3D9+OpenGL, another 2 is for vertex+pixel shader).

If you have a pixel lit shader that does not support shadows (multicompile_builtin_noshadows), then each Cg shader is “only” 6*2 combinations.

However, like I said, the result is shader assembly in text format. Most of those combinations are quite similar as well. So that compresses really really well.

It’s not because of fallbacks. It’s because of “combinatorial shader explosion”, where to handle any thing that is different you need a different shader. This was one area where fixed function pipeline really shines - you can combine stuff arbitrarily, and it just works. With shaders, any single bit that you want to do differently requires a new shader. So when you want a shader to support directional lights and spot lights and point lights and point lights with no attenuation, and directional lights with cookies, and all the shadow options - well, see my answer above.

Ah ok. I was confused when I was reading the console output, I thought those values were the compressed sizes. That example compiles to 150k, and I assume the shader parts are a very very small part of the final size.

Thanks!