Search Unity

Shader keywords and material instances

Discussion in 'Shaders' started by briank, Feb 6, 2019.

  1. briank

    briank

    Joined:
    Mar 25, 2017
    Posts:
    74
    I have a "base" material that my script duplicates into two instances via

    Code (CSharp):
    1. var newMat1 = Instantiate(BaseMaterial);
    2. var newMat2 = Instantiate(BaseMaterial);
    Then each new instance has different types of shader keywords Enabled/Disabled on them...
    Code (CSharp):
    1. newMat1.EnableKeyword("Keyword0");
    2. newMat1.DisableKeyword("Keyword1");
    3.  
    4. newMat2.DisableKeyword("Keyword0");
    5. newMat2.EnableKeyword("Keyword1");
    When I read back the keywords from the material instances in the script, everything looks like it has been setup correctly.

    However, at render time, it seems that my changes to the material keywords are not being applied. I have objects in the scene that are being rendered with both materials and every draw call uses the same set of keywords regardless of the material.

    I thought the keywords are per-material instance, but it seems like that's not the case?
     
  2. briank

    briank

    Joined:
    Mar 25, 2017
    Posts:
    74
    Adding to this, I'm using Graphics.DrawMesh and MaterialPropertyBlock to issue draw calls that actually use these materials, and I end up re-using the same MaterialPropertyBlock instance for all draw calls.

    One thing I haven't tried is using a separate MaterialPropertyBlock instance per-material as well. I figure it shouldn't matter, since the property blocks don't have anything to do with keywords, but maybe this is some undocumented side effect here...

    Any other suggestions welcome.
     
  3. briank

    briank

    Joined:
    Mar 25, 2017
    Posts:
    74
    Nvm, the issue ended up being how I was defining the keywords in the shader; I was using something like:

    #pragma multi_compile Keyword0
    #pragma multi_compile Keyword1

    What I needed was to add the ability to generate shader variants without the keyword, so...

    #pragma multi_compile __ Keyword0
    #pragma multi_compile __ Keyword1

    Or, it turns out just using #pragma shader_feature KeywordX works as well.
     
  4. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,348
    If those two keywords are exclusive, ie: only one will should be set at a time, you should use:

    #pragma multi_compile Keyword0 Keyword1

    or

    #pragma shader_feature Keyword0 Keyword1

    Otherwise using two lines means you're compiling 4 different shader variants for only 2 different wanted states. Or optionally only use one keyword and have the default behavior be the other one.


    But yes, multi_compile is weird in that defining only a single keyword like:
    #pragma multi_compile Keyword0

    is identical to:
    #define Keyword0 1

    In other words it doesn't actually create multiple variants from that keyword. I think it still eats one of the 256 total variant keywords you can use, which the other option does not. You have to use an underscore to say "compile variants without this keyword and with".

    #pragma shader_feature on the other hand works the same with or without an underscore and will do both. Note that using shader_feature will tell the build systems to automatically strip unused variants from a build, unused defined as "no assets are using it", so if it's something that's only swapped to programatically it won't work at runtime unless you use a shader variant collection to force it's inclusion in the build.
     
    Alic and FM-Productions like this.