Build does not contain all (multi-compile) shader variants

Hi,

I have a shader graph with multiple boolean keywords, and some material in included scenes which use this shader graph. The keywords are set to “multi-compile” in shader graph. However, if I switch the boolean keyword in build, the variant gets not activated. I would assume that I don’t need materials with all variants in included scenes if I use multi-compile in shader graph?

So is this a bug, or do I miss something?

Hi @Qleenie,

Couple of question before we file this as a bug.

  • Does it work in the Editor when in Play mode?
  • Are they Local or Global (Overridable) keywords?
  • Do you switch them on or off, locally or globally?

Yes, it works in Play mode. Funnily, I just tested, and on restart of Editor, the bool switches on the material did NOT work in Scene view. Than I started in play mode, and there the switches (toggled by script), worked fine, but shader got newly compiled. After stopping, it worked also in Scene view…

Keywords are local, I set them from script like this:

 var shader = material.shader;
 LocalKeyword keyword = shader.keywordSpace.FindKeyword(name);
 if (keyword != null)
 {
     material.EnableKeyword(name);
     material.SetKeyword(keyword, on);
 }

So the default value is false. Then you enable it locally from a Script?

You only need to call either of the two methods EnableKeyword(name) or SetKeyword(keyword, state). But I don’t think this is the problem.

Another question, how do you set the reference to the Material?

References are set by the Unity Hair package (which is still in experimental mode afaik); maybe this is the issue?

One other thing I noticed is that before I tried the above, I was referencing two different materials (both from hair script), one with the keywords enabled, and one not. Even than it did not work in build.

Maybe I should do an extra dummy reference?

I wonder if it may be possible that you’re setting a keyword on a material reference that isn’t the one you see (no longer assigned).

If you try something like

void OnMouseUpAsButton()
{
    GetComponent<Renderer>().sharedMaterial.EnableKeyword("name");
}

The object requires a Collider for this work. Does that work in the Build?

I don’t think that’s the issue, it worked before in older builds, also the gameobjects and the material get’s never destroyed or unloaded.
Only after updating the shader, and with this triggering a re-compilation, the compilation in build seems incomplete.

in fact, after I triggered the compilation manually in play mode, and now building again, I can see the extra compilation of the shader happening as it should!

So there must be some sort of issue in the editor, maybe it’s really the way the hair package is doing the referencing?

Can your Shader Variant stripping option be excluding those variants?

you mean the managed stripping level? No, it’s set to “minimal”.

Also as an update: After manually triggering recompile in Editor, and then building, it now works in build. Very likely until next time I update the shader.

Another update: I was already referencing the material also via a normal Script reference (as “public Material material”). So the referencing by the hair package can’t be the issue either. The only thing different to let’s say “classical” usage of Material is that it’s not referenced by any MeshRenderer in the scene.

Is it necessary to have a reference from a MeshRenderer in order to trigger the multi-compilation? Would be strange if it is IMO.

Any reference of a Material instance, from a MonoBehaviour or ScriptableObject or any other should make that Shader compile its variants at build.
If it doesn’t, it’s a bug.
Which version of Unity are you using?

It’s 2023.2.20; we are stuck with this version, as some regressions in Unity 6 are being rejected by QA.