在上一节中,我们添加了外轮廓线,但这个外轮廓线在所有使用该Shader的网格上是始终存在的。
如果我们想做一个开关,决定是否打开外轮廓线时,我们可以使用一个新的Uniform bool值,然后判断bool是否为true来开启外轮廓线。
但是这样会造成性能的浪费,因为就算我们没有开启这个功能,Shader还是会遍历每一个if条件。这与GPU的运行原理有关。
故我们使用Unity的多编译功能,将Shader多次编译成多个子Shader。
// 自定义关键字
[Toggle(_ENABLE_OUTLINE_ON)] _EnableOutline("Enable OutLine", Float) = 0.0
// 默认关键字(默认为 名称大写+_ON)
[Toggle] _EnableOutline("Enable OutLine", Float) = 0.0
// 默认关键字为(_ENABLEOUTLINE_ON)
1.
half _EnableInline;
2.
#ifdef UNITY_DOTS_INSTANCING_ENABLED
UNITY_DOTS_INSTANCING_START(MaterialPropertyMetadata)
...
UNITY_DOTS_INSTANCED_PROP(float , _EnableInline)
UNITY_DOTS_INSTANCING_END(MaterialPropertyMetadata)
3.
#define _EnableInline UNITY_ACCESS_DOTS_INSTANCED_PROP_FROM_MACRO(float , Metadata__EnableInline)
//pass中定义
#progma shader_feature _ENABLE_OUTLINE_ON//自定义关键字
#progma shader_feature _ENABLEOUTLINE_ON//默认关键字
#if defined(_ENABLE_OUTLINE_ON)
#else
#endif
public static class Styles
{
public static readonly GUIContent InlineEnable = new GUIContent("开启内勾边",
"");
}
public struct LitProperties
{
public MaterialProperty InlineEnabled;
public LitProperties(MaterialProperty[] properties)
{
InlineEnabled = BaseShaderGUI.FindProperty("_EnableInline", properties, false);
}
}
///
/// 当滚轮滑动材质Inspector面板时,该函数调用4+次
/// 当修改参数或点击按钮时,该函数也会调用约8-12次
/// 因此可将该函数看作多次遍历的函数
///
public static void DoDetailArea(LitProperties properties, MaterialEditor materialEditor)
{
materialEditor.ColorProperty(properties.OutLineColor, Styles.OutLineColorContent.text);
materialEditor.FloatProperty(properties.OutLineSize, Styles.OutLineSizeContent.text);
// 显示按钮,设置GUI按钮的值,返回开关选中的状态
bool inlineEnabled = EditorGUILayout.Toggle(Styles.InlineEnable, properties.InlineEnabled.floatValue > 0.5f);
// 根据按钮的选中状态修改Shader值
properties.InlineEnabled.floatValue = inlineEnabled ? 1f : 0f;
// BeginDisabledGroup参数填True,则为禁用Begin至End直接的功能。在untiy面板上置灰。
EditorGUI.BeginDisabledGroup(!inlineEnabled);
{
materialEditor.FloatProperty(properties.InlineSize, Styles.InlineSizeContent.text);
materialEditor.FloatProperty(properties.Inlineluminance, Styles.InlineluminanceContent.text);
materialEditor.FloatProperty(properties.HightLightTransition, Styles.HightLightTransitionContent.text);
}
EditorGUI.EndDisabledGroup();
}
此时,便可以通过按钮设置properties.InlineEnabled.floatValue的值了。
根据Shader中变量值"_EnableInline",设置宏"_ENABLE_INLINE_ON"的值
public static void SetMaterialKeywords(Material material)
{
if (material.HasProperty("_EnableInline"))
{
bool isSnowEnabled = material.GetFloat("_EnableInline") > 0.5f;
CoreUtils.SetKeyword(material, "_ENABLE_INLINE_ON", isSnowEnabled);
}
}
当用户使用这个ShaderGUI将材质加载到内存中或者改变Inspector中的值时,编辑器调用下面这个方法。我们在这个方法中调用SetMaterialKeywords函数
public override void ValidateMaterial(Material material)
{
CP_DragonOutLineGUI.SetMaterialKeywords(material);
}
该方法可用于设置材质中的各个宏定义。