At present, the difficulty with too many variants and abysmal construct instances can occur due to two causes:
- you even have too many shader variants wanted on your scene, as a result of e.g. completely different high quality settings spanning by too many choices (fairly unlikely, and principally unsolvable in a method aside from optimizing these choices),
- you are unfortunate sufficient to make use of a inventory Unity shader code, both by
#together with
a few of their code or utilizing Shader Graph.
Whereas the quantity of permutations for an honest vary of high quality settings and so forth. will be certainly excessive (be aware that that is normally a multiplicative course of), this specific downside
normally occurs as a result of Unity Editor would not acknowledge the key phrases really (un)utilized in your scene and would not strip them correctly from the construct. An instance offending code from Advanced Lit
appears to be like like this:
#pragma multi_compile _ _MAIN_LIGHT_SHADOWS _MAIN_LIGHT_SHADOWS_CASCADE _MAIN_LIGHT_SHADOWS_SCREEN
#pragma multi_compile _ _ADDITIONAL_LIGHTS_VERTEX _ADDITIONAL_LIGHTS
#pragma multi_compile_fragment _ _ADDITIONAL_LIGHT_SHADOWS
#pragma multi_compile_fragment _ _REFLECTION_PROBE_BLENDING
#pragma multi_compile_fragment _ _REFLECTION_PROBE_BOX_PROJECTION
#pragma multi_compile_fragment _ _SHADOWS_SOFT
#pragma multi_compile _ _MIXED_LIGHTING_SUBTRACTIVE
#pragma multi_compile_fragment _ _SCREEN_SPACE_OCCLUSION
#pragma multi_compile_fragment _ _DBUFFER_MRT1 _DBUFFER_MRT2 _DBUFFER_MRT3
#pragma multi_compile_fragment _ _LIGHT_LAYERS
#pragma multi_compile_fragment _ _LIGHT_COOKIES
#pragma multi_compile _ _FORWARD_PLUS
#pragma multi_compile_fragment _ _WRITE_RENDERING_LAYERS
As one can simply calculate, that by itself offers a multiplier of two^10 * 3 * 4 * 4, i.e. 49152 (roughly 50k), to the quantity of wanted variants, if the key phrases aren’t stripped earlier than the construct. For a motive (but) unknown to me, the precise stripping would not occur for them (no matter what the official put up of Unity shader workforce stated right here), even when the key phrase is certainly all the time on or all the time off within the scene/URP settings.
Essentially the most environment friendly resolution can be to both use a plugin/asset that permits to deal with this (and even write a stripper plugin oneself) mechanically (e.g. through IPreprocessShaders
or comparable). Nonetheless, should you’re OK with fixing the issue by hand, the precise resolution is sort of easy:
- decide the precise key phrases relevant to your shader in your scene, and which ones are fastened, and which ain’t (e.g., if you do not have SSAO enabled and do not need to allow it – or you probably have it enabled, and need to all the time have it like that),
- attempt to scale back the quantity of the particular multi-keywords (variants) to an affordable quantity, considering their multiplicative nature (i.e. a single key phrase and on/off multi offers *2 variants and construct time), and keep in mind that you will have to have about 10-100 variants anyway, even with the aforementioned key phrase utterly fastened, relying in your scene & construct, and which you could have troubles compiling greater than 100k variants whatever the construct machine specs,
- take away/remark out the
multi_compile
traces with key phrases that you do not need to have enabled in any respect; take away/remark out the variants you don’t need/want and/or change the#pragma multi_compile
(ormulti_compile_fragment
and so forth.) with#pragma shader_feature
and so forth. (see the docs for more information) - ???
- revenue.
In my case e.g., it might appear to be this after the edits:
// -------------------------------------
// Common Pipeline key phrases
#pragma multi_compile _ _MAIN_LIGHT_SHADOWS _MAIN_LIGHT_SHADOWS_CASCADE /* _MAIN_LIGHT_SHADOWS_SCREEN */
#pragma multi_compile /* _ _ADDITIONAL_LIGHTS_VERTEX */ _ADDITIONAL_LIGHTS
#pragma multi_compile_fragment /* _ */ _ADDITIONAL_LIGHT_SHADOWS
// #pragma multi_compile_fragment _ _REFLECTION_PROBE_BLENDING
// #pragma multi_compile_fragment _ _REFLECTION_PROBE_BOX_PROJECTION
#pragma multi_compile_fragment /* _ */ _SHADOWS_SOFT
// #pragma multi_compile _ _MIXED_LIGHTING_SUBTRACTIVE
#pragma multi_compile_fragment /* _ */ _SCREEN_SPACE_OCCLUSION
// #pragma multi_compile_fragment _ _DBUFFER_MRT1 _DBUFFER_MRT2 _DBUFFER_MRT3
// #pragma multi_compile_fragment _ _LIGHT_LAYERS
// #pragma multi_compile_fragment _ _LIGHT_COOKIES
// #pragma multi_compile _ _FORWARD_PLUS
// #pragma multi_compile_fragment _ _WRITE_RENDERING_LAYERS
(be aware that in case of the inventory Lit
/Advanced Lit
shader, you may have to do that in two locations, as soon as for ShaderModel 2.0 block and as soon as for ShaderModel 4.5 block)
which gave me 24 variants for each Vulkan and OpenGL Core as a substitute of 196608 variants for Vulkan and 24576 variants for OpenGL Core with out the guide stripping, for a Advanced Lit
-based shader.
For those who’re unfortunate sufficient to be utilizing Shader Graph, it is only a bit extra difficult: you may need to, after every SG change, manually export your SG to a “regular” shader utilizing “View Generated Shader”, after which do the above steps manually. It is theoretically attainable to “drive” a SG shader to be generated otherwise, through injecting customized processing of go.key phrases
(saved in PassDescriptor go
) when GenerateShaderPass
technique is named from Generator()
c-tor in UnityEditor.ShaderGraph.Generator.cs
. They’re sourced from KeywordCollection Ahead
and so forth. in e.g. UniversalLitSubTarget.cs
. Arduous to say how worthwhile it’s to go this fashion (be aware that SG bundle is tightly coupled with URP bundle which is tightly coupled with Unity model by itself…) vs simply guide (or semi-automatic) preprocessing of shaders as a substitute.
(additionally, be aware that even Unity devs thought-about present multi_compile
/ shader_feature
#pragma
system damaged and problematic a few years earlier than this concern lastly hit us large, though for slightly-yet-not-completely-different causes)