我正在为 Unity 2019.3.13f1 编写一个自定义着色器,它只是一个简单的 UI 渐变。该着色器不(需要)对模板缓冲区执行任何操作,因此我将模板设置为始终静态传递:
Stencil
{
Ref 0
Comp Equal
Pass Keep
}
但是这样做会引发警告
材质 SomeGradient 没有 _Stencil 属性
所以我添加了一个 _Stencil 属性(尽管它永远不会被使用,而且我也不希望其他人能够从编辑器更改模板缓冲区)
[HideInInspector] _Stencil("Stencil ID", Float) = 0
Stencil
{
Ref [_Stencil]
}
这会消除警告,但会引发新警告:
材质 SomeGradient 没有 _StencilOp 属性
现在重复前面的步骤,它将继续这样做,直到我最终得到一堆我不想公开的属性,并且也不想更改,只是为了摆脱一些警告
[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]
}
这使我的着色器代码显着膨胀,而无需添加任何功能(在没有属性的情况下静态设置它)。查看 Unity 的
UI-Default
着色器,他们还显式添加了这些属性(以及 _ColorMask
,否则也会引发警告)。
引发警告的代码来自
\2019.3.13f1\Editor\Data\Resources\PackageManager\BuiltInPackages\com.unity.ugui\Runtime\UI\Core\StencilMaterial.cs
方法 Material Add
,该方法似乎是在将材质添加到图像组件的材质属性时由 Unity 在内部调用的。
/// <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
}
完全删除
Stencil{}
通行证仍然会引发警告。
我查看了 Stencil 的 documentation,但我似乎找不到他们想要显式添加此属性的原因,在文档示例中他们也没有显式添加属性。那么有一个我错过的充分理由吗?
我还发现令人困惑的是,当您创建一个新的无光照着色器(创建>着色器>无光照着色器)时,它不会抛出这些警告,尽管也没有显式添加模板属性
Properties
{
_MainTex ("Texture", 2D) = "white" {}
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
//Rest of shader code
}
}
为什么这似乎是一个例外?
Stencil 不是着色器中使用的属性,而是 Unity 对绘制状态进行编程的指示。
在着色器中拥有这些属性会影响 DepthStencil 状态的创建方式。
对于 UI 着色器,Stencil 用于各种功能,例如屏蔽滚动矩形之外的 UI 等。没有这个会导致奇怪的行为。例如。 UI 元素在带有遮罩的滚动矩形外部可见。
为了使所有 UI 元素能够很好地协同工作,我发现最好的方法是从默认 UI 着色器派生任何 UI 着色器。