Remy
Remy

Reputation: 5173

Unity shader warning when not adding _Stencil properties

I'm writing a custom shader for Unity 2019.3.13f1 that is just a simple UI gradient. This shader does not (need to) do anything with the stencil buffer, so I set the Stencil to always pass statically:

Stencil
{
    Ref 0
    Comp Equal
    Pass Keep
}

However doing this will throw the warning

Material SomeGradient doesn't have _Stencil property

So I add a _Stencil property (despite it never going to be used, and I don't want others to be able to change the stencil buffer from the editor either)

[HideInInspector] _Stencil("Stencil ID", Float) = 0

Stencil
{
    Ref [_Stencil]
}

This gets rid of the warning, but will throw a new warning:

Material SomeGradient doesn't have _StencilOp property

Now repeating the previous step it will keep doing this untill I eventually end up with a bunch of properties I don't want exposed, and never want to change either, just to get rid of some warnings

[HideInInspector] _Stencil("Stencil ID", Float) = 0
[HideInInspector] _StencilOp("Stencil Operation", Float) = 0
[HideInInspector] _StencilComp("Stencil Comparison", Float) = 8
[HideInInspector] _StencilReadMask("Stencil Read Mask", Float) = 255
[HideInInspector] _StencilWriteMask("Stencil Write Mask", Float) = 255

Stencil{
    Ref [_Stencil]
    Pass[_StencilOp]
    Comp[_StencilComp]
    ReadMask[_StencilReadMask]
    WriteMask[_StencilWriteMask]
}

This bloats my shader code significantly, without adding anything to functionality (over statically setting it without properties). Looking at Unity's UI-Default shader they have also added these properties properties explicitly (along with _ColorMask which also throws a warning elsewise).

The code throwing the warning comes from the \2019.3.13f1\Editor\Data\Resources\PackageManager\BuiltInPackages\com.unity.ugui\Runtime\UI\Core\StencilMaterial.cs method Material Add, which seems to get called internally by Unity when adding a Material to the Material property of an Image component.

 /// <summary>
 /// Add a new material using the specified base and stencil ID.
 /// </summary>
 public static Material Add(Material baseMat, int stencilID, StencilOp operation, CompareFunction compareFunction)
 {
     if ((stencilID <= 0 && colorWriteMask == ColorWriteMask.All) || baseMat == null)
         return baseMat;

     if (!baseMat.HasProperty("_Stencil"))
     {
         Debug.LogWarning("Material " + baseMat.name + " doesn't have _Stencil property", baseMat);
         return baseMat;
     }
     if (!baseMat.HasProperty("_StencilOp"))
     {
         Debug.LogWarning("Material " + baseMat.name + " doesn't have _StencilOp property", baseMat);
         return baseMat;
     }
     if (!baseMat.HasProperty("_StencilComp"))
     {
         Debug.LogWarning("Material " + baseMat.name + " doesn't have _StencilComp property", baseMat);
         return baseMat;
     }
     if (!baseMat.HasProperty("_StencilReadMask"))
     {
         Debug.LogWarning("Material " + baseMat.name + " doesn't have _StencilReadMask property", baseMat);
         return baseMat;
     }
     if (!baseMat.HasProperty("_StencilWriteMask"))
     {
         Debug.LogWarning("Material " + baseMat.name + " doesn't have _StencilWriteMask property", baseMat);
         return baseMat;
     }
     if (!baseMat.HasProperty("_ColorMask"))
     {
         Debug.LogWarning("Material " + baseMat.name + " doesn't have _ColorMask property", baseMat);
         return baseMat;
     }
    //Rest of code
}

Removing the Stencil{} pass in its entirety will also still throw the warning.

I looked at the documentation for Stencil, but I can't seem to find a reason why they want this explicitly added, in the docs examples they don't add the properties explicitly either. So is there a good reason for it that I missed?


What I also find baffling is that when you create a new Unlit shader (Create>Shader>Unlit Shader) it doesn't throw these warnings, despite not having the stencil properties added explicitly either

Properties
{
    _MainTex ("Texture", 2D) = "white" {}
}
SubShader
{
    Tags { "RenderType"="Opaque" }
    LOD 100

    Pass
    {
     //Rest of shader code
    }
}

Why does this seem to be an exception to the rule?

Upvotes: 5

Views: 11563

Answers (1)

Jayanth Gurijala
Jayanth Gurijala

Reputation: 1

Stencil is not a property used in shader but an indication to Unity on programming the Draw state.

Having these properties in the shader effects how DepthStencil state is created.

For a UI shader, Stencil is used for various features like masking UI which goes outside a scroll rect etc. Not having this would result in weird behaviour. Eg. UI elements visible outside a scroll rect with a mask.

For all the UI elements to work well together, I found the best way is to derive any shader for UI from the default UI shader.

Upvotes: 0

Related Questions