using UnityEditor; using UnityEngine; // UIMask 材质面板的"下拉框 -> 隐藏属性"绘制器基类。 // ShaderLab 的 Blend / Cull 只接受数字属性,没法用枚举直接切换, // 所以由绘制器把下拉框的选项写进隐藏属性。 // 每次绘制面板都会同步一次,所以从其它 shader(例如 URP/Lit 也有同名的 // _SrcBlend / _DstBlend / _Cull)切过来的材质会被自动纠正。 // 注意:attribute 的名字必须是子类的简单类名,Unity 按类名查找绘制器。 public abstract class UIMaskEnumDrawer : MaterialPropertyDrawer { protected abstract string[] Options { get; } // 把下拉框当前选项同步到材质上的隐藏属性 protected abstract void Apply(MaterialEditor editor, int index); public override void OnGUI(Rect position, MaterialProperty prop, string label, MaterialEditor editor) { EditorGUI.BeginChangeCheck(); int index = Mathf.Clamp(Mathf.RoundToInt(prop.floatValue), 0, Options.Length - 1); index = EditorGUI.Popup(position, label, index, Options); if (EditorGUI.EndChangeCheck()) { prop.floatValue = index; } Apply(editor, index); } public override float GetPropertyHeight(MaterialProperty prop, string label, MaterialEditor editor) { return EditorGUIUtility.singleLineHeight; } protected void SetValue(MaterialEditor editor, string propertyName, float value) { foreach (Object target in editor.targets) { var material = target as Material; if (material == null || !material.HasProperty(propertyName)) { continue; } if (!Mathf.Approximately(material.GetFloat(propertyName), value)) { material.SetFloat(propertyName, value); } } } } // 混合模式:加色 / 普通混合 // 数值对应 UnityEngine.Rendering.BlendMode:SrcAlpha=5, One=1, OneMinusSrcAlpha=10 public class UIMaskBlendMode : UIMaskEnumDrawer { private static readonly string[] Items = { "Additive", "AlphaBlend" }; protected override string[] Options => Items; protected override void Apply(MaterialEditor editor, int index) { SetValue(editor, "_SrcBlend", (float)UnityEngine.Rendering.BlendMode.SrcAlpha); SetValue(editor, "_DstBlend", index == 0 ? (float)UnityEngine.Rendering.BlendMode.One : (float)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha); } } // 渲染面:只渲染前面 / 只渲染后面 / 双面 // ShaderLab 的 Cull 取值:Off=0(双面)、Front=1(剔除正面,即只渲染后面)、Back=2(剔除背面,即只渲染前面) public class UIMaskRenderFace : UIMaskEnumDrawer { private const float CullOff = 0f; private const float CullFront = 1f; private const float CullBack = 2f; private static readonly string[] Items = { "前面", "背面", "双面" }; protected override string[] Options => Items; protected override void Apply(MaterialEditor editor, int index) { float cull = index == 0 ? CullBack : (index == 1 ? CullFront : CullOff); SetValue(editor, "_Cull", cull); } } // 贴图通道:R / G / B / A(值直接被 shader 采样时使用,不需要写隐藏属性) // 默认 A(index = 3) public class UIMaskChannel : UIMaskEnumDrawer { private static readonly string[] Items = { "R 通道", "G 通道", "B 通道", "A 通道" }; protected override string[] Options => Items; protected override void Apply(MaterialEditor editor, int index) { // 下拉框的值本身就是要采样的通道号,无需同步到别的属性 } }