Files
Vision/Assets/Shaders/Editor/UIMaskDrawers.cs
T
2026-10-10 20:12:37 +08:00

102 lines
3.7 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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)
{
// 下拉框的值本身就是要采样的通道号,无需同步到别的属性
}
}