Material property drawer(MPD) 材质属性绘制器
3.0.8. | MPD Toggle.
在 ShaderLab 中,我们不能使用布尔类型属性,而是使用 Toggle 来实现相同的功能。 这个绘制器将允许使用着色器中的条件从一种状态切换到另一种状态。 要运行它,我们必须首先在括号之间添加单词 Toggle,然后声明我们的属性,并考虑到它必须是 Float 类型。 它的默认值必须是整数,要么是零,要么是一,为什么? 因为零代表“关”,一代表“开”。
其语法如下:
[Toggle] _PropertyName ("Display Name", Float) = 0
正如我们所看到的,我们将 Toggle 添加到括号中,然后声明属性,然后声明显示名称,后跟 Float 数据类型,最后将属性初始化为“Off”,因为我们在其默认值中添加了零。
使用此绘制器时必须考虑的一点是,如果我们想在代码中实现它,则必须使用#pragma shader_feature。 这属于着色器变体,其功能是根据其所处的状态(启用或禁用)生成不同的条件。 为了理解它的实现,我们将进行以下操作:
Shader "InspectorPath/shaderName"
{
Properties
{
_Color ("Color", Color) = (1, 1, 1, 1)
// declare drawer Toggle
[Toggle] _Enable ("Enable ?", Float) = 0
}
SubShader
{
Pass
{
CGPROGRAM
…
// declare pragma
#pragma shader_feature _ENABLE_ON
…
float4 _Color;
…
half4 frag (v2f i) : SV_Target
{
half4 col = tex2D(_MainTex, i.uv);
// generate conditions
#if _ENABLE_ON
return col;
#else
return col * _Color;
#endif
}
ENDCG
}
}
}
在此示例中,我们声明了一个名为“_Enable”的 Toggle 类型属性。 然后我们将其添加到CGPROGRAM中找到的shader_feature中,但是与我们程序中的属性不同,Toggle被声明为“_ENABLE_ON”,这是为什么呢? 在shader_feature中添加的变体是“常量”,因此它们以大写字母书写,这意味着,例如,如果我们的属性被称为_Change,那么在着色器变体中它应该被添加为“_CHANGE”。 _ON 一词对应于 Toggle 的默认状态,因此,如果 _Enable 属性处于活动状态,我们将在片段着色器阶段返回默认纹理颜色,否则我们将 _Color 属性乘以自身。
值得一提的是,shader_feature 无法为一个应用程序编译多个变体,这意味着什么? Unity 不会包含我们在最终构建中未使用的变体,这意味着我们将无法在执行时从一种状态移动到另一种状态。 为此,我们必须使用具有变体着色器“multi_compile”的KeywordEnum绘制器。
3.0.9. | MPD KeywordEnum.
该绘制器在材质检查器中生成一个弹出式菜单。 与切换不同,此绘制器允许您为着色器配置最多九种不同的状态。 要执行它,我们必须在括号中添加单词“KeywordEnum”,然后列出我们要使用的状态集。
[KeywordEnum(StateOff, State01, etc...)]
_PropertyName ("Display name", Float) = 0
在前面的示例中,我们在括号中添加 KeywordEnum 绘制器,然后列出其状态,其中第一个对应于默认状态 (StateOff)。 我们继续进行属性声明、材质检查器中的显示名称、其 Float 数据类型,最后,我们使用其默认值进行初始化。
为了在我们的代码中声明这个绘制器,我们可以使用着色器变体shader_feature和multi_compile。 选择将取决于我们想要包含在最终版本中的变体数量。
我们已经知道,shader_feature 只会从材质检查器中导出选定的变体,而 multi_compile 则会导出着色器中找到的所有变体,无论它们是否被使用。 鉴于此功能,multi_compile 非常适合导出或编译将在执行时更改的多个状态(例如超级马里奥中的星星状态)。
为了理解它的实现,我们将执行以下操作:
Shader "InspectorPath/shaderName"
{
Properties
{
// declare drawer Toggle
[KeywordEnum(Off, Red, Blue)]
_Options ("Color Options", Float) = 0
}
SubShader
{
Pass
{
CGPROGRAM
…
// declare pragma and conditions
#pragma multi_compile _OPTIONS_OFF _OPTIONS_RED _OPTIONS_BLUE
…
half4 frag (v2f i) : SV_Target
{
half4 col = tex2D(_MainTex, i.uv);
// generate conditions
#if _OPTIONS_OFF
return col;
#elif _OPTIONS_RED
return col * float4(1, 0, 0, 1);
#elif _OPTIONS_BLUE
return col * float4(0, 0, 1, 1);
#endif
}
ENDCG
}
}
}
在此示例中,我们声明一个名为“_Options”的 KeywordEnum 类型属性,并为其配置三种状态(关闭、红色和蓝色)。 稍后我们将它们添加到 CGPROGRAM 中的 multi_compile 中并将它们声明为常量。
#pragma multi_compile _OPTIONS_OFF _OPTIONS_RED _OPTIONS_BLUE
最后,使用条件,我们为着色器定义与主纹理的颜色变化相对应的三种状态。
3.1.0. | MPD Enum.
该绘制器与 KeywordEnum 非常相似,不同之处在于它可以定义“值/id”作为参数,并将该属性传递给着色器中的命令,以从检查器动态更改其功能。
其语法如下:
[Enum(valor, id_00, valor, id_01, etc … )]
_PropertyName ("Display Name", Float) = 0
枚举不使用着色器变体,而是通过命令或函数声明。 为了理解它们的实现,我们将执行以下操作:
Shader "InspectorPath/shaderName"
{
Properties
{
// declare drawer
[Enum(Off, 0, Front, 1, Back, 2)]
_Face ("Face Culling", Float) = 0
}
SubShader
{
// we use the property as a command
Cull [_Face]
Pass { … }
}
}
如本示例所示,我们声明一个名为“_Face”的属性类型“Enum”,并将值作为参数传递:Off、0、Front、1、Back 和 2。然后我们将该属性添加到命令“Cull” 在SubShader中找到; 这样我们就可以从材质检查器中更改我们想要渲染的对象面。 在3.2.1节中我们将详细讨论Cull命令。
3.1.1. | MPD PowerSlider 和 IntRange.
这些绘制器在处理数值范围和精度时非常有用。 一方面,我们有 PowerSlider,它允许我们生成具有曲线控制的非线性滑块。
其语法如下:
[PowerSlider(3.0)] _PropertyName ("Display name", Range (0.01, 1)) = 0.08
另一方面,我们有 IntRange,正如其名称所示,它添加了整数值的数值范围。
其语法如下:
[IntRange] _PropertyName ("Display name", Range (0, 255)) = 100
请注意,如果我们想在着色器中使用这些属性,则必须以与常规属性相同的方式在 CGPROGRAM 中声明它们。 为了了解如何使用它,我们将执行以下操作:
Shader "InspectorPath/shaderName"
{
Properties
{
// declare drawer
[PowerSlider(3.0)]
_Brightness ("Brightness", Range (0.01, 1)) = 0.08
[IntRange]
_Samples ("Samples", Range (0, 255)) = 100
}
SubShader
{
Pass
{
CGPROGRAM
…
// 生成连接变量
float _Brightness;
int _Samples;
…
ENDCG
}
}
}
在上面的示例中,我们声明了一个名为 _Brightness 的 PowerSlider 和一个名为 _Samples 的 IntRange。 最后,使用相同的名称,我们在 CGPROGRAM 中生成连接变量。
3.1.2. | MPD Space 和 Header.
最后,这些绘制器对组织任务有很大帮助。
“Space”允许我们在一个属性和另一个属性之间添加空间。 如果我们希望我们的属性在材质检查器中单独显示,我们可以在它们之间添加Space。
其语法如下:
_PropertyName01 ("Display name", Float ) = 0
// we add the space
[Space(10)]
_PropertyName02 ("Display name", Float ) = 0
在本例中,我们在属性 _PropertyName01 和属性 _PropertyName02 之间添加十个空格。 同样,正如其名称所示,“Header”在 Unity Inspector 中添加一个标题。 这在我们的属性中生成类别时非常有用。
其语法如下:
// we add the header
[Header(Category name)]
_PropertyName01 ("Display name", Float ) = 0
_PropertyName02 ("Display name", Float ) = 0
在此示例中,我们在启动属性之前添加了一个小Header,该Header将在检查器中可见。 为了理解这两个属性,我们将执行以下操作:
Shader "InspectorPath/shaderName"
{
Properties
{
[Header(Specular properties)]
_Specularity (“Specularity”, Range (0.01, 1)) = 0.08
_Brightness (“Brightness”, Range (0.01, 1)) = 0.08
_SpecularColor (“Specular Color”, Color) = (1, 1, 1 , 1)
[Space(20)]
[Header(Texture properties)]
_MainTex (“Texture”, 2D) = “white” {}
}
SubShader { … }
}